[
  {
    "path": ".github/actions/setup-anchor/action.yml",
    "content": "name: \"Setup anchor-cli\"\ndescription: \"Setup anchor cli\"\nruns:\n  using: \"composite\"\n  steps:\n    - uses: taiki-e/cache-cargo-install-action@v2\n      with:\n        tool: avm\n        tag: v${{ env.ANCHOR_CLI_VERSION }}\n        git: https://github.com/coral-xyz/anchor\n    - run: avm install ${{ env.ANCHOR_CLI_VERSION }}\n      shell: bash\n"
  },
  {
    "path": ".github/actions/setup-dep/action.yml",
    "content": "name: \"Setup\"\ndescription: \"Setup program dependencies\"\nruns:\n  using: \"composite\"\n  steps:\n    - run: sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev\n      shell: bash\n"
  },
  {
    "path": ".github/actions/setup-solana/action.yml",
    "content": "name: \"Setup Solana\"\ndescription: \"Setup Solana\"\nruns:\n  using: \"composite\"\n  steps:\n    - uses: actions/cache@v4\n      name: Cache Solana Tool Suite\n      id: cache-solana\n      with:\n        path: |\n          ~/.cache/solana/\n          ~/.local/share/solana/\n        key: solana-${{ runner.os }}-v0000-${{ env.SOLANA_CLI_VERSION }}\n    - run: sh -c \"$(curl -sSfL https://release.anza.xyz/v${{ env.SOLANA_CLI_VERSION }}/install)\"\n      shell: bash\n    - run: echo \"$HOME/.local/share/solana/install/active_release/bin/\" >> $GITHUB_PATH\n      shell: bash\n    - run: solana-keygen new --no-bip39-passphrase\n      shell: bash\n    - run: solana config set --url localhost\n      shell: bash\n"
  },
  {
    "path": ".github/workflows/ci-pr-main-cli.yml",
    "content": "name: DLMM Cli\n\non:\n  pull_request:\n    branches:\n      - main\n\nenv:\n  SOLANA_CLI_VERSION: 2.1.0\n  NODE_VERSION: 20.11.0\n  ANCHOR_CLI_VERSION: 0.31.0\n\njobs:\n  cli_changed_files:\n    runs-on: ubuntu-latest\n    outputs:\n      cli: ${{steps.changed-files-specific.outputs.any_changed}}\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - name: Get specific changed files\n        id: changed-files-specific\n        uses: tj-actions/changed-files@v18.6\n        with:\n          files: |\n            cli\n\n  cli_build:\n    runs-on: ubuntu-latest\n    needs: cli_changed_files\n    if: needs.cli_changed_files.outputs.cli == 'true'\n    steps:\n      - uses: actions/checkout@v2\n      # Install rust + toolchain\n      - uses: actions-rs/toolchain@v1\n        with:\n          toolchain: 1.85.0\n          override: true\n          components: clippy\n      # Cache rust, cargo\n      - uses: Swatinem/rust-cache@v1\n      - run: cargo build -p cli\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/ci-pr-main-market-making.yml",
    "content": "name: DLMM Market Making Example\n\non:\n  pull_request:\n    branches:\n      - main\n\nenv:\n  SOLANA_CLI_VERSION: 2.1.0\n  NODE_VERSION: 20.11.0\n  ANCHOR_CLI_VERSION: 0.31.0\n\njobs:\n  market_making_changed_files:\n    runs-on: ubuntu-latest\n    outputs:\n      market_making: ${{steps.changed-files-specific.outputs.any_changed}}\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - name: Get specific changed files\n        id: changed-files-specific\n        uses: tj-actions/changed-files@v18.6\n        with:\n          files: |\n            market_making\n\n  market_making_build:\n    runs-on: ubuntu-latest\n    needs: market_making_changed_files\n    if: needs.market_making_changed_files.outputs.market_making == 'true'\n    steps:\n      - uses: actions/checkout@v2\n      # Install rust + toolchain\n      - uses: actions-rs/toolchain@v1\n        with:\n          toolchain: 1.85.0\n          override: true\n          components: clippy\n      # Cache rust, cargo\n      - uses: Swatinem/rust-cache@v1\n      - run: cargo build -p market_making\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/ci-pr-main-program.yml",
    "content": "name: DLMM Commons\n\non:\n  pull_request:\n    branches:\n      - main\n\njobs:\n  common_changed_files:\n    runs-on: ubuntu-latest\n    outputs:\n      program: ${{steps.changed-files-specific.outputs.any_changed}}\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - name: Get specific changed files\n        id: changed-files-specific\n        uses: tj-actions/changed-files@v18.6\n        with:\n          files: |\n            commons\n            artifacts\n\n  common_test:\n    runs-on: ubuntu-latest\n    needs: common_changed_files\n    if: needs.common_changed_files.outputs.program == 'true'\n    steps:\n      - uses: actions/checkout@v2\n      # Install rust + toolchain\n      - uses: actions-rs/toolchain@v1\n        with:\n          toolchain: 1.85.0\n          override: true\n          components: clippy\n      # Cache rust, cargo\n      - uses: Swatinem/rust-cache@v1\n      - run: cargo t -p commons --test '*'\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/ci-pr-main-sdk.yml",
    "content": "name: DLMM SDK\n\non:\n  pull_request:\n    branches:\n      - main\n\nenv:\n  SOLANA_CLI_VERSION: 2.1.0\n  NODE_VERSION: 20.11.0\n  ANCHOR_CLI_VERSION: 0.31.0\n\njobs:\n  sdk_changed_files:\n    runs-on: ubuntu-latest\n    outputs:\n      sdk: ${{steps.changed-files-specific.outputs.any_changed}}\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - name: Get specific changed files\n        id: changed-files-specific\n        uses: tj-actions/changed-files@v18.6\n        with:\n          files: |\n            ts-client\n            artifacts\n\n  sdk_test:\n    runs-on: ubuntu-latest\n    needs: sdk_changed_files\n    if: needs.sdk_changed_files.outputs.sdk == 'true'\n    env:\n      RPC: ${{ secrets.RPC }}\n    steps:\n      - uses: actions/checkout@v2\n      - uses: ./.github/actions/setup-solana\n      - uses: ./.github/actions/setup-dep\n      - uses: ./.github/actions/setup-anchor\n      # Install rust + toolchain\n      - uses: actions-rs/toolchain@v1\n        with:\n          toolchain: stable\n          components: clippy\n      - uses: pnpm/action-setup@v4\n        with:\n          version: 10\n      # Cache node_modules\n      - uses: actions/cache@v4\n        id: cache-node-modules\n        with:\n          path: ./ts-client/node_modules\n          key: ${{ runner.os }}-${{ hashFiles('./pnpm-lock.yaml') }}\n      - run: anchor localnet -- --features localnet & sleep 2\n        shell: bash\n      - run: cd ts-client && pnpm install && pnpm run test\n        shell: bash\n"
  },
  {
    "path": ".gitignore",
    "content": "\n.anchor\n.DS_Store\n**/*.rs.bk\nnode_modules\ntest-ledger\n.yarn\nyarn.lock\n.yarnrc.yml\n\ntarget/*\n!target/types\n!target/idl\n!target/debug/cli\ndeployment\n\nts-client/dist\nts-client/.env\nts-client/scripts\n\n.pnpm-debug.log\n"
  },
  {
    "path": ".prettierignore",
    "content": "\n.anchor\n.DS_Store\ntarget\nnode_modules\ndist\nbuild\ntest-ledger\n"
  },
  {
    "path": "Anchor.toml",
    "content": "[features]\nseeds = false\nskip-lint = false\n\n[registry]\nurl = \"https://api.apr.dev\"\n\n[provider]\ncluster = \"Localnet\"\nwallet = \"keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\"\n\n[[test.genesis]]\naddress = \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\"\nprogram = \"./artifacts/token_2022.so\"\n\n[[test.genesis]]\naddress = \"LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ\"\nprogram = \"./artifacts/lb_clmm.so\"\n\n[[test.genesis]]\naddress = \"abcSyangMHdGzUGKhBhKoQzSFdJKUdkPGf5cbXVHpEw\"\nprogram = \"./artifacts/transfer_hook_counter.so\"\n\n[scripts]\ntest = \"yarn run ts-mocha --sort --type-check --bail -p ./tsconfig.json -t 1000000 tests/*.ts\"\n\n[toolchain]\nsolana_version = \"2.1.0\"\nanchor_version = \"0.31.0\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n### Added\n\n### Changed\n\n### Deprecated\n\n### Removed\n\n### Fixed\n\n### Security\n\n## @meteora-ag/dlmm [1.9.7] - [PR #286](https://github.com/MeteoraAg/dlmm-sdk/pull/286)\n\n### Fixed\n\n- Allow `dlmm.simulateRebalancePosition` on single bin\n\n## @meteora-ag/dlmm [1.9.6] - [PR #285](https://github.com/MeteoraAg/dlmm-sdk/pull/285)\n\n### Fixed\n\n- isSwapDisabled for missing pair types (`CustomizablePermissionless`)\n- Add missing `PairType`: `CustomizablePermissionless` `PermissionlessV2`\n\n## @meteora-ag/dlmm [1.9.5] - [PR #282](https://github.com/MeteoraAg/dlmm-sdk/pull/282)\n\n### Added\n\n- Added `getOracle` function to fetch oracle account for TWAP.\n- Added `increaseOracleLength` function to increase oracle length.\n\n## @meteora-ag/dlmm [1.9.4] - [PR #272](https://github.com/MeteoraAg/dlmm-sdk/pull/272)\n\n### Fixed\n\n- Fixed `removeLiquidity` with `shouldClaimAndClose` failing to close position when bins have unclaimed fees but no remaining liquidity.\n\n## @meteora-ag/dlmm [1.9.3] - [PR #262](https://github.com/MeteoraAg/dlmm-sdk/pull/262)\n\n### Added\n\n- Added `chunkedGetMultipleAccountsInfo` helper function to fetch program accounts in chunks, improving reliability for large account queries.\n\n## @meteora-ag/dlmm [1.9.2] - [PR #265](https://github.com/MeteoraAg/dlmm-sdk/pull/265)\n\n### Fixed\n\n- Fixed `createCustomizablePermissionlessLbPair` and `createCustomizablePermissionlessLbPair2` to include pre instructions for creating user token accounts.\n\n## @meteora-ag/dlmm [1.9.1] - [PR #263](https://github.com/MeteoraAg/dlmm-sdk/pull/263)\n\n### Added\n\n- Added `functionType` parameter to `createCustomizablePermissionlessLbPair` and `createCustomizablePermissionlessLbPair2`. No breaking change to the interface.\n\n### Changed\n\n- Changed `admin` to `signer` in `setActivationPoint`, `setPairStatusPermissionless` and `setPairStatus`.\n- Changed `rewardPerTokenStored` to `functionBytes`\n- Added `rent` account to `createEmptyPosition`, `initializePositionAndAddLiquidityByStrategy`, `initializePositionAndAddLiquidityByWeight` and `createInitAndExtendPositionIx`\n\n### Removed\n\n- Removed `amountXIn` and `amountYIn` from bin state\n\n## @meteora-ag/dlmm [1.9.0] - [PR #260](https://github.com/MeteoraAg/dlmm-sdk/pull/260)\n\n### Added\n\n- Added `binDeltaToMinMaxBinId` helper function. To have a canonical conversion from binDelta to minBinId and maxBinId\n\n### Fixed\n\n- Fixed `simulateRebalancePosition` to account for when the activeBinArray has not been initialized.\n\n## @meteora-ag/dlmm [1.8.0] - [PR #231](https://github.com/MeteoraAg/dlmm-sdk/pull/231)\n\n### Added\n\n- Added `initializeMultiplePositionAndAddLiquidityByStrategy2` function. It should improve transaction landing by allowing parallel execution of returned transaction's instructions. However, the drawback is the function will only expand position up to 525 bins, and chunk the remaining bins into another position with 525 bins again, and so on. This is due to transaction size limitation.\n\n## @meteora-ag/dlmm [1.7.6] - PR 250\n\n### Fixed\n\n- Fixed modern esm and old commonjs import compatibility\n\n## cli [0.5.2] - PR #251\n\n### Fixed\n\n- Fixed `fetch_quote_required_accounts` zero copy account deserialization\n\n## commons [0.3.2] - PR 249\n\n### Fixed\n\n- Fix rust quote infinite loop\n\n## @meteora-ag/dlmm [1.7.5] - PR 244\n\n### Fixed\n\n- Fixed wrapping more SOL than required during add liquidity\n\n## @meteora-ag/dlmm [1.7.4] - PR 235\n\n### Added\n\n- Added exports for `accountFilters`\n\n## @meteora-ag/dlmm [1.7.3] - PR 240\n\n### Fixed\n\n- Fixed `getPairPubkeyIfExists` return same pair pubkey for different baseFeeFactor\n\n## @meteora-ag/dlmm [1.7.2] - PR #239\n\n### Fixed\n\n- Reduced pending fee / reward value computed due to ghost bin\n\n## @meteora-ag/dlmm [1.7.1] - PR #237\n\n### Fixed\n\n- Inconsistent bid ask liquidity shape\n\n## @meteora-ag/dlmm [1.7.0] - PR #233\n\n### Changed\n\n- update `removeLiquidity` to have a new `skipUnwrapSOL` boolean flag that indicates whether to skip unwrapping SOL. Enable this when using zap-sdk to ensure accuracy in SOL zap out amount when SOL is the in token\n\n## @meteora-ag/dlmm [1.6.0] - PR #229\n\n### Changed\n\n- update `initializeMultiplePositionAndAddLiquidityByStrategy` to include `initializeAtaIxs` so that create ATA instructions don't need to be include in every rebalance transactions\n\n## @meteora-ag/dlmm [1.6.0] - PR #196\n\n### Changed\n\n- Update anchor to `0.31.0`\n- Decreased `MAX_CLAIM_ALL_ALLOWED` from `3` to `2`. This decreased the chunked claim instruction from 3 to 2 per transaction.\n\n### Added\n\n- Added `getPositionRentExemption` function. It return minimum balance required to pay for a position account for rent exemption.\n- Added `getPositionExpandRentExemption` function. It return minimum balance required to pay for a position account expansion for rent exemption.\n- Added `quoteExtendPosition` function. It return minimum balance required to pay for rent exemption for the given position expansion and bin array accounts to cover the expanded position range.\n- Added `decreasePositionLength` function. It return transaction to shrink an expanded position. The rent is not returned upon decrement, but returned when the position is closed.\n- Added `increasePositionLength` function. It return transaction to expand a position up to maximum 1400 bins.\n- Added `simulateRebalancePosition` function. It return a locally simulated rebalanced position, and required parameters for on chain rebalancing.\n- Added `createExtendedEmptyPosition` function. It return transaction to create an empty position with maximum 1400 bins.\n- Added `simulateRebalancePositionWithStrategy` function. It return a locally simulated rebalanced position with current price rebalanced to the center of the position.\n- Added `rebalancePosition` function. It return instructions to rebalance a position.\n- Added `initializeMultiplePositionAndAddLiquidityByStrategy` function. It allow user to initialize multiple extendable positions that cover wide bin range without chainsaw issue.\n- Added `addLiquidityByStrategyChunkable` function. It allow user to add liquidity to single extendable positions that cover wide bin range without chainsaw issue.\n\n### Changed\n\n- `removeLiquidity` function. It will chunk the bin range into multiple remove liquidity transactions if it exceed max size. The return type changed from `Promise<Transaction>` to `Promise<Transaction[]>`.\n- `claimLMReward` function. It will chunk the bin range into multiple claim reward transactions if it exceed max size. The return type changed from `Promise<Transaction>` to `Promise<Transaction[]>`.\n- `claimSwapFee` function. It will chunk the bin range into multiple claim swap fee transactions if it exceed max size. The return type changed from `Promise<Transaction>` to `Promise<Transaction[]>`.\n- `quoteCreatePosition` function. It return cost for position creation cost, realloc position cost and initialize bitmap extension.\n\n## cli [0.5.1] - PR #196\n\n- Added `sync_price` command.\n\n## dlmm_interface [Removed]\n\n- Removed since anchor now support generation of program CPI types using `declare_program!`.\n- For integrators using lower version of anchor, you may use [anchor_gen](https://github.com/saber-hq/anchor-gen) to generate program CPI types.\n- For rust client, you may import the types generated using `declare_program!` from `commons`.\n\n## @meteora-ag/dlmm [1.5.5] - PR #227\n\n### Fix\n\n- fix export helpers function for position\n\n## @meteora-ag/dlmm [1.5.4] - PR #220\n\n### Fixed\n\n- fix `swapQuote` price impact should be absolute\n\n## cli [0.5.1] - PR #215\n\n### Fixed\n\n- Fix swap bin array account ordering and account fetching\n\n## common [0.3.1] - PR #215\n\n### Fixed\n\n- Fix swap quote\n\n## @meteora-ag/dlmm [1.5.3] - PR #211\n\n### Fixed\n\n- fix `getBinsBetweenLowerAndUpperBound` when bin Array not found\n\n## @meteora-ag/dlmm [1.5.2] - PR #209\n\n### Fixed\n\n- `seedLiquiditySingle` used wrong token program for token2022\n\n## @meteora-ag/dlmm [1.5.1] - PR #205\n\n### Fixed\n\n- `seedLiquidity` find optimal decompress multiplier\n- Minor bug fix\n\n## @meteora-ag/dlmm [1.5.0] - PR #201\n\n### Changed\n\n- `seedLiquidity` now return `costBreakdown` field for account rental in `SeedLiquidityResponse`.\n- `seedLiquiditySingleBin` now return `SeedLiquiditySingleBinResponse` instead of `TransactionInstruction[]`. `SeedLiquiditySingleBinResponse` has `costBreakdown` field for account rental.\n\n### Fixed\n\n- Fixed `POSITION_FEE` and `BIN_ARRAY_FEE` account rental cost constant.\n\n## @meteora-ag/dlmm [1.4.11] - PR #195\n\n### Fixed\n\n- Fixed all claim method not working if position no liquidity\n\n## @meteora-ag/dlmm [1.4.10] - PR #194\n\n### Fixed\n\n- Fixed `createClaimBuildMethod` return undefined;\n\n## @meteora-ag/dlmm [1.4.9] - PR #193\n\n### Fixed\n\n- Fixed readme `Remove Liquidity` section\n\n## @meteora-ag/dlmm [1.4.8] - PR #192\n\n### Fixed\n\n- Fixed `getPositionsByUserAndLbPair` assertion\n\n## @meteora-ag/dlmm [1.4.7] - PR #191\n\n### Fixed\n\n- Fixed `seedLiquiditySingleBin` create token account for position owner token proof.\n- FIxed `syncWithMarketPrice` not initializing bitmap extensions if needed\n\n## @meteora-ag/dlmm [1.4.6] - PR #190\n\n### Fixed\n\n- Fixed `seedLiquiditySingleBin` function\n\n## @meteora-ag/dlmm [1.4.5] - PR #162\n\n### Changed\n\n- `calculateFeeInfo` added new optional `baseFeePowerFactor` parameter\n\n#### Breaking\n\n- `getPairPubkeyIfExists` added new `baseFeePowerFactor` parameter\n- `getAllPresetParameters` now return `presetParameter` and `presetParameter2` accounts instead of only `presetParameter`\n- `removeLiquidity`, `binIds` parameter has been replaced by `fromBinId` and `toBinId` which represent the bin range to be removed\n\n- `toAmountsBothSideByStrategy`, `fromWeightDistributionToAmount`, `toAmountBothSide` added `mintX`, `mintY` and `clock` parameters\n- `toAmountAskSide` added `mintX` and `clock` parameters\n- `toAmountBidSide` added `mintX` and `clock` parameters\n\n- Rename `LBCLMM_PROGRAM_IDS` to `DLMM_PROGRAM_IDS`\n- `computeBaseFactorFromFeeBps` return `baseFactor` + `baseFeePowerFactor` instead of only `baseFactor`\n\n### Added\n\n- `createCustomizablePermissionlessLbPair2`, similar as `createCustomizablePermissionlessLbPair` but support token 2022.\n- `createLbPair2`, similar as `createLbPair` but support token 2022. It require `PresetParameter2` account instead of `PresetParameter` which allow pool to have higher base fee.\n- `closePositionIfEmpty`. Will close the position only if it's empty, else do nothing.\n\n- `derivePresetParameterWithIndex`. Used to derive `PresetParameter2` account for `createLbPair2`\n- `deriveLbPairWithPresetParamWithIndexKey`. Used to derive `LbPair` account for `createLbPair2` using `PresetParameter2` account\n- `deriveTokenBadge`. Used to derive `TokenBadge` account for whitelisted token2022 mint.\n\n- `getTokenProgramId` to return token X and token Y program id for the pair\n\n- `getBinArrayIndexesCoverage` to return bin array indexes required for the given bin range\n- `getBinArrayKeysCoverage` to return bin array addresses required for the given bin range\n- `getBinArrayAccountMetasCoverage` to return bin array account metas required for the given bin range\n\n- `getExtraAccountMetasForTransferHook` to return extra account metas required for transfer hook\n- `calculateTransferFeeIncludedAmount` to calculate transfer fee included amount for token2022\n- `calculateTransferFeeExcludedAmount` to calculate transfer fee excluded amount for token2022\n\n### Deprecated\n\n- `initializePositionAndAddLiquidityByWeight`. Use `initializePositionAndAddLiquidityByStrategy` instead which support both token and token 2022 program.\n- `addLiquidityByWeight`. Use `addLiquidityByStrategy` instead which support both token and token2022.\n\n### Removed\n\n- `getWithdrawSingleSideAmount`. Unused.\n- `createPermissionLbPair`. Admin-only function.\n- `findSwappableMinMaxBinId`. Unused anymore.\n\n## cli [0.5.0]\n\n### Changed\n\n- File structure refactoring\n- Switched all the existing functions to support token 2022\n\n### Changed\n\n- `seed_liquidity` doesn't require file snapshot to support resume anymore\n\n### Removed\n\n- `seed_liquidity` and `seed_liquidity_single_bin`. Please use `seed_liquidity_by_operator` and `seed_liquidity_single_bin_by_operator`\n\n### Added\n\n- Admin function `initialize_token_badge` to initialize token badge for token 2022\n\n## lb_clmm [0.7.0]\n\n- DEPRECATED. Use `dlmm_interface` for types and `commons` for related account functions.\n\n## dlmm_interface [0.9.0]\n\n- Program interface generated using `solores`\n\n## commons [0.3.0]\n\n- Added token 2022 supportive functions.\n- Added position account supportive functions.\n\n## @meteora-ag/dlmm [1.4.2] - PR #183\n\n### Added\n\n- Add `getCustomizablePermissionlessLbPairIfExists` function to fetch existing customizable permissionless LB pair\n\n### Changed\n\n- remove CU estimation for `seedLiquidity`\n\n### Fixed\n\n- Fix incorrect enable/disable mapping in `setPairStatusPermissionless`\n\n## @meteora-ag/dlmm [1.4.1] - PR #182\n\n### Changed\n\n- Update readme to include `claimFee`\n\n## @meteora-ag/dlmm [1.4.0] - PR #181\n\n### Changed\n\n- Revamp StrategyType, now only have `StrategyType.Spot`, `StrategyType.BidAsk` & `StrategyType.Curve`\n\n## @meteora-ag/dlmm [1.3.16] - PR #179\n\n### Changed\n\n- Add `feeOwner`, `operator`, `lockReleasePoint`, `shouldSeedPositionOwner`, `txPayer` parameters for `seedLiquidity` function\n\n## @meteora-ag/dlmm [1.3.16] - PR #179\n\n### Changed\n\n- Add `feeOwner`, `operator`, `lockReleasePoint`, `shouldSeedPositionOwner`, `txPayer` parameters for `seedLiquidity` function\n\n## @meteora-ag/dlmm [1.3.15] - PR #173\n\n### Added\n\n- Add param `enablePoolOnOffControl` to `createCustomizablePermissionlessLbPair` function.\n- Add `setPairStatusPermissionless` function. This require pool field `creator_pool_on_off_control` to be true and pair type is `CustomizablePermissionless`. Pool creator can enable/disable the pair anytime before the pool is opened / activated. Once the pool activation time is passed, the pool creator can only enable the pair. Useful for token launches which do not have fixed activation time.\n\n## cli [0.4.2] - PR #173\n\n- Add param `creator_pool_on_off_control` to `InitializeCustomizablePermissionlessLbPair` function.\n- Add `set_pair_status_permissionless` function.\n\n## @meteora-ag/dlmm [1.3.14] - PR #167\n\n### Added\n\n- Add param `maxExtraBinArrays` to `swapQuote` and `swapQuoteExactOut` functions.\n\n## @meteora-ag/dlmm [1.3.13] - PR #166\n\n### Added\n\n- Add `ts-client` function `getLbPairLockInfo`.\n\n## @meteora-ag/dlmm [1.3.12] - PR #161\n\n### Added\n\n- Remove `@solana-developers/helpers` dependency.\n\n## cli [0.4.1] - PR #160\n\n### Added\n\n- Add admin commmand `set_pair_status`.\n\n### Removed\n\n- Removed admin command `toggle_pair_status`.\n\n## @meteora-ag/dlmm [1.3.11] - PR #160\n\n### Added\n\n- Add admin function `setPairStatus`.\n\n## @meteora-ag/dlmm [1.3.10] - PR #159\n\n### Changed\n\n- Bump DLMM IDL to 0.8.5.\n- Update `lb_clmm.so` artifact.\n- Update function `createCustomizablePermissionlessLbPair` to use account `userTokenY`.\n\n### Removed\n\n- Removed account `rent` in function `createCustomizablePermissionlessLbPair`.\n\n## @meteora-ag/dlmm [1.3.9] - PR #145\n\n### Fixed\n\n- Remove Strategy `SpotOneSide`, `CurveOneSide` & `BidAskOneSide`\n\n## @meteora-ag/dlmm [1.3.8] - PR #144\n\n### Fixed\n\n- Fix `getOrCreateATAInstruction` to use `createAssociatedTokenAccountIdempotentInstruction`\n\n## @meteora-ag/dlmm [1.3.7] - PR #143\n\n### Fixed\n\n- Fix `swapQuote` end price\n\n## @meteora-ag/dlmm [1.3.6] - PR #116\n\n### Changed\n\n- Refactored; remove `position(V1)` interaction from SDK\n- Throw error in `removeLiquidity` function if position doesn't have any liquidity\n\n### Fixed\n\n- Removed unused rpc call in `swap`\n\n### Added\n\n- Function `getPosition` to retrieve a single position data\n\n## @meteora-ag/dlmm [1.3.5] - PR #136\n\n### Fixed\n\n- Fixed the `getBins` method to handle the corner case when no bin arrays created for the requested bin ids.\n\n## @meteora-ag/dlmm [1.3.4] - PR #127\n\n### Changed\n\n- Use estimated compute unit instead of 1.4m compute unit for instructions.\n\n## @meteora-ag/dlmm [1.3.3] - PR #133\n\n### Changed\n\n- Update parameters for `ts-client` function `seedLiquiditySingleBin`\n\n## @meteora-ag/dlmm [1.3.2] - PR #134\n\n### Changed\n\n- Close wrap SOL ATA when SOL is swap in direction.\n\n## lb_clmm [0.8.2] - PR #115\n\n### Added\n\n- Add a new endpoint `initialize_customizable_permissionless_lb_pair`, that allows pool creator to be able to create pool with input `active_id`, `bin_step`, `base_factor`, `activation_point` and `alpha-vault`\n\n### Changed\n\n- Add a new PairType `CustomizablePermissionless`, that is set by using the new endpoint above.\n\n- Remove `whitelisted_wallet` and `lock_duration` in pool state.\n\n- Remove `subjected_to_bootstrap_liquidity_locking` in position state.\n\n- With PairType as `Permission` and `CustomizablePermissionless`, `token_y_mint` is always quote token (SOL/USDC). Users are able to deposit both quote token and base token before `activation_slot`, but those pools doesn't allow user to deposit quote token in active_bin before `activation_slot`. After `activation_slot`, that are free for everyone.\n\n- `PairType::Permission` allows user to withdraw base token before `activation_slot`, but `PairType::CustomizablePermissionless` doesn't allow user to withdraw base token before `activation_slot`\n\n- Refactoring on file structures\n\n### Removed\n\n- Remove endpoint `set_lock_release_point`\n- Remove endpoint `update_whitelisted_address`\n\n### Breaking Changes\n\n- Endpoint `initialize_position_by_operator` requires a new field `lock_release_point`, to allow position liquidity locking for compatibility with old launch mechanism in permissioned lb pair\n\n## @meteora-ag/dlmm [1.3.0] - PR #115\n\n### Added\n\n- Add `createCustomizablePermissionlessLbPair` to allow user to create launch pool with more flexible configuration.\n\n### Removed\n\n- Remove `updateWhitelistedWallet`\n\n### Breaking Changes\n\n- `createPermissionLbPair` removed `lockDuration`\n- `initializePositionByOperator` added `lockReleasePoint`\n- `seedLiquidity` removed `operator` and `feeOwner`\n\n## cli [0.4.0] - PR #115\n\n### Added\n\n- Add `initialize_customizable_permission_lb_pair`\n\n### Removed\n\n- Remove `update_whitelisted_wallet`\n\n## @meteora-ag/dlmm [1.2.4] - PR #119\n\n### Fixed\n\n- Refactor `getBins` to work with any bin ranges\n\n## @meteora-ag/dlmm [1.2.3] - PR #112\n\n### Fixed\n\n- Fixed `addLiquidityByStrategy` incorrect array bin indices calculation\n\n## @meteora-ag/dlmm [1.2.2] - PR #110\n\n### Fixed\n\n- Fixed `quoteCreatePosition` incorrect result if bin range too short\n\n## @meteora-ag/dlmm [1.2.0] - PR #109\n\n### Removed\n\n- Removed `removeLiquiditySingleSide`\n\n## @meteora-ag/dlmm [1.1.6] - PR #108\n\n### Added\n\n- new method `createEmptyPosition` allows to create an empty position with the corresponding bin arrays.\n\n## @meteora-ag/dlmm [1.1.5] - PR #107\n\n### Fixed\n\n- fix `getPairPubkeyIfExists` return type\n\n## @meteora-ag/dlmm [1.1.4] - PR #107\n\n### Fixed\n\n- `removeLiquiditySingleSide`. Add in unwrap sol in post instructions\n\n## @meteora-ag/dlmm [1.1.2] - PR #104\n\n### Fixed\n\n- `isSwapDisabled` checked against wrong field\n\n## @meteora-ag/dlmm [1.1.1] - PR #103\n\n### Removed\n\n- Removed `swapInitiator` parameter from `swapQuoteExactOut` and `swapQuote`.\n\n### Added\n\n- `isSwapDisabled` to check whether the pool allow swap\n\n## @meteora-ag/dlmm [1.1.0] - PR #101\n\n### Changed\n\n- `swapQuoteExactOut` and `swapQuote` require an additional `swapInitiator` parameter. `swapInitiator` is the address of the user who will initiate the swap transaction.\n\n## lb_clmm [0.8.0] - PR #96\n\n### Added\n\n- Pool supports 2 modes now defined by `activation_type`. If `activation_type == 0`, activation is calculated based on slot. If `activation_type == 1`, activation is calculated based on timestamp.\n\n### Changed\n\n- Pool state added a new field `activation_type`\n- Rename `pool.activation_slot` to `pool.activation_point`\n- Rename `pool.pre_activation_slot_duration` to `pool.pre_activation_duration`\n- Rename `pool.lock_duration_in_slot` to `pool.lock_duration`\n- Rename `position.lock_release_slot` to `position.lock_release_point`\n\n### Breaking Changes\n\n- The activation condition for all endpoints will by validated by slot or timestamp based on `activation_type` in pool state\n- All program endpoints to modify permissioned pool will migrate parameters with post_fix `_slot` to `_point`\n- Rename endpoint `set_activation_slot` to `set_activation_point`\n- Rename endpoint `set_pre_activation_slot_duration` to `set_pre_activation_duration`\n- Rename endpoint `set_lock_release_slot` to `set_lock_release_point`\n- Endpoint `initialize_permission_lb_pair` requires a new field `activation_type` in input parameters\n\n### Removed\n\n- `update_fee_owner` endpoint is removed\n\n## common [0.3.0] - PR #96\n\n### Changed\n\n- `quote_exact_out` and `quote_exact_in` throw error when pool is disabled, or not activated for swap yet.\n\n### Breaking Changes\n\n- `quote_exact_out` and `quote_exact_in` require a new field `current_slot` in input parameters\n\n## cli [0.3.0] - PR #96\n\n### Removed\n\n- `update_fee_owner` command is removed\n\n### Breaking Changes\n\n- Rename command `set_activation_slot` to `set_activation_point`\n- Rename command `set_pre_activation_slot_duration` to `set_pre_activation_duration`\n- Command `initialize_permission_lb_pair` require new `activation_type` parameter\n\n## @meteora-ag/dlmm [1.0.55] - PR #96\n\n### Changed\n\n- `swapQuoteExactOut` and `swapQuote` throw error when pool is disabled, or not activated for swap yet.\n\n### Breaking Changes\n\n- Renamed `setActivationSlot` to `setActivationPoint`\n- `createPermissionLbPair` require new `ActivationType` parameter\n\n## @mercurial-finance/dynamic-amm-sdk [1.0.54] - PR #99\n\n### Fixed\n\n- `getAmountOutWithdrawSingleSide`. Ensured the correct withdrawal amount is returned\n\n## @meteora-ag/dlmm [1.0.53] - PR #98\n\n### Added\n\n- `removeLiquiditySingleSide`. Withdraw only 1 token in the pair for the position\n- `getWithdrawSingleSideAmount`. Calculates the total single-sided withdrawable amount\n\n## @meteora-ag/dlmm [1.0.52] - PR #90\n\n### Added\n\n- extra field (`endPrice`) in swapQuote\n\n## @meteora-ag/dlmm [1.0.51] - PR #94\n\n### Added\n\n- `getBinArraysRequiredByPositionRange`. Retrieves the bin arrays required to initialize multiple positions in continuous range.\n- `initializeBinArrays`. Initializes bin arrays for the given bin array indexes if it wasn't initialized.\n\n## @meteora-ag/dlmm [1.0.50] - PR #91\n\n### Changed\n\n- Support partial fill in `swapQuote` function\n\n## @meteora-ag/dlmm [1.0.49] - PR #88\n\n### Improvement\n\n- Improve the `claimAllRewards` method with a more distinct filtering for claiming non empty swap fees and lm rewards per each kind.\n- Filter positions with non zero LM rewards in the `claimAllLMRewards` method.\n- Filter positions with non zero swap fees in the `claimAllSwapFee` method.\n\n## @meteora-ag/dlmm [1.0.48] - PR #87\n\n### Improvement\n\n- Exclude positions without any fees and/or rewards from reward claims in the `claimAllRewards` method.\n\n## @meteora-ag/dlmm [1.0.46] - PR #84\n\n### Added\n\n- `swapQuoteExactOut` for swap quote of program endpoint `swap_exact_out`.\n- `swapExactOut` to create transaction to swap using program endpoint `swap_exact_out`.\n- `swapWithPriceImpact` to create transaction to swap using program endpoint `swap_with_price_impact`.\n\n### Breaking\n\n- Renamed `swapQuoteAtBin` function to `swapExactInQuoteAtBin`\n\n## lb_clmm [0.7.0] - PR #84\n\n### Added\n\n- Program endpoint `swap_exact_out`. It will consume the in amount until the exact out amount reached.\n- Program endpoint `swap_with_price_impact`. Similar to minimum amount out (slippage), but in price impact form.\n\n## common [0.1.1] - PR #84\n\n### Added\n\n- `quote_exact_out` for swap quote of program endpoint `swap_exact_out`.\n\n### Breaking\n\n- Renamed return type of `swap_exact_in` function, `SwapQuote` to `SwapExactInQuote`\n\n## @meteora-ag/dlmm [1.0.45] - PR #76\n\n### Improvement\n\n- improve `getAllLbPairPositionsByUser` on some promise to run in parallel\n\n## @meteora-ag/dlmm [1.0.45] - PR #76\n\n### Fixed\n\n- fix `addLiquidityByStrategy` not working when active bin is not within the liquidity\n\n## commons [0.1.0] - PR #80\n\n### Added\n\n- Swap exact in quote\n\n## @meteora-ag/dlmm [1.0.44] - PR #81\n\n### Added\n\n- `getEmissionRate` should not return ended reward, which can be read from `rewardDurationEnd`\n\n## @meteora-ag/dlmm [1.0.43] - PR #76\n\n### Changed\n\n- update static function to support param program id\n\n## lb_clmm [0.6.1] - PR #79\n\n### Added\n\n- Staging program id\n\n## @meteora-ag/dlmm [1.0.42] - PR #78\n\n### Fixed\n\n- `swapQuote` not working on pool with bitmap extension when in token is tokenX\n\n## @meteora-ag/dlmm [1.0.41] - PR #77\n\n### Fixed\n\n- `swapQuote` not working on pool with bitmap extension\n\n## @meteora-ag/dlmm [1.0.40] - PR #74\n\n### Added\n\n- `getMaxPriceInBinArrays` to get the max price of a bin that has liquidity\n\n## lb_clmm [0.6.0] - PR #75\n\n### Added\n\n- Introduces `pre_activation_swap_address` and pre_activation_slot_duration\n  `pre_activation_slot_duration` fields.\n\n### Removed\n\n- `swap_cap_amount` and `swap_cap_deactivate_slot` fields.\n\n### Breaking\n\n- Reduced whitelisted_wallet from the size of 2 to 1. This break the `update_whitelisted_wallet` endpoint.\n\n## @meteora-ag/dlmm [1.0.38] - PR #71\n\n### Added\n\n- `getTokensMintFromPoolAddress` helper function to get tokenX mint & tokenY mint from lb pair address\n\n## @meteora-ag/dlmm [1.0.37] - PR #68\n\n### Added\n\n- `initializePositionByOperator` function allow operator to initialize positio for other user\n\n### Fixed\n\n- `withdrawLiquidity` error when close position due to rent receiver must be position owner\n\n## @meteora-ag/dlmm [1.0.36] - PR #68\n\n### Added\n\n- `getPairPubkeyIfExists` function to get the public key of existing pool address, if the pool doesn't exists return null\n\n## @meteora-ag/dlmm [1.0.35] - PR #59\n\n### Added\n\n- Support liquidity seeding for launch pool (permission pair) based on https://ilm.jup.ag/\n\n### Fixed\n\n- `findSwappableMinMaxBinId` returned invalid min/max bin id under some edge case\n- `derivePosition` using invalid seed\n\n## lb_clmm [0.5.2] - PR #59\n\n### Added\n\n- Add deposit single sided with exact amount endpoint\n\n## lb_clmm [0.5.1] - PR #49\n\n### Features\n\n- Support creation of permissionless pair with same binstep but a different fee tier.\n\n### Deprecated\n\n- `derive_lb_pair_pda` no longer in use. Use `derive_lb_pair_pda2` for new pair PDA.\n- `derive_preset_parameter_pda` no longer in use. Use `derive_preset_parameter_pda2` for new pair PDA.\n\n### Breaking\n\n- Initialization of `LbPair` PDA require `base_factor` as the fourth seed now. This break `InitializeLbPair` account context.\n- Initialization of `PresetParameter` PDA require `base_factor` as the third seed now. This break `InitializePresetParameter` account context.\n\n## @meteora-ag/dlmm [1.0.34] - PR #49\n\n### Features\n\n- Support creation of permissionless pair with same binstep, different fee tier.\n\n### Deprecated\n\n- `deriveLbPair` no longer in use. Use `deriveLbPair2` for new pair PDA.\n- `derivePresetParameter` no longer in use. Use `derivePresetParameter2` for new preset parameter PDA.\n\n## @mercurial-finance/dynamic-amm-sdk [1.0.33] - PR #67\n\n### Fixed\n\n- Fix position liquidity withdraw to position owner, instead of customized fee owner\n\n## @mercurial-finance/dynamic-amm-sdk [1.0.32] - PR #58\n\n### Added\n\n- A new function to sync outdated pool to nearest market price bin\n\n## @mercurial-finance/dlmm-sdk [1.0.30] - PR #65\n\n- Fix create permission lb pair browser compatibility\n\n## @mercurial-finance/dlmm-sdk [1.0.29] - PR #59\n\n## Fixed\n\n- Fix position quotation calculation for bin array creation.\n\n## @mercurial-finance/dlmm-sdk [1.0.27] - PR #57\n\n### Fixed\n\n- Fix position quotation calculation for position count.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\"cli\", \"commons\", \"market_making\"]\nresolver = \"2\"\n\n[workspace.dependencies]\nanchor-lang = \"0.31.0\"\nanchor-spl = \"0.31.0\"\nanchor-client = \"0.31.0\"\n\nsolana-sdk = \"2.1.0\"\nspl-associated-token-account = \"6.0.0\"\nsolana-transaction-status = \"2.1.0\"\nsolana-account-decoder = \"2.1.0\"\nspl-memo = \"6.0.0\"\nspl-transfer-hook-interface = \"0.9.0\"\n\nserde_json = \"1.0.140\"\nserde = \"1.0.219\"\nbincode = \"1.3.3\"\nbs58 = \"0.5.0\"\nbytemuck = \"1.13.1\"\n\nclap = \"4.3.3\"\nshellexpand = \"3.1.0\"\n\nenv_logger = \"0.9.0\"\nlog = \"0.4.17\"\n\nrust_decimal = \"1.31.0\"\nruint = \"1.3.0\"\nnum-integer = \"0.1.45\"\nnum-traits = \"0.2.16\"\n\nhyper = \"0.14.17\"\nrouterify = \"3\"\n\ntokio = \"^1.0\"\nfutures-util = \"0.3.0\"\nasync-trait = \"0.1.0\"\n\nanyhow = \"1.0.71\"\n\nrand = \"0.8.5\"\n\nchrono = \"0.4.31\"\n\nureq = \"2.0.0\"\n\nitertools = \"0.10.0\"\n\ncommons = { path = \"./commons\" }\n\n[profile.release]\noverflow-checks = true\nlto = \"fat\"\ncodegen-units = 1\n\n[profile.release.build-override]\nopt-level = 3\nincremental = false\ncodegen-units = 1\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:20\nRUN mkdir dlmm-server\nWORKDIR /dlmm-server\nCOPY package*.json ./\nRUN npm install\nCOPY . .\nRUN npm run build\nEXPOSE 3000\nCMD [\"npm\", \"start-server\"]\n"
  },
  {
    "path": "README.md",
    "content": "# LB CLMM SDK\n\n#### Quote Testing\n\n```\ncargo t -p commons --test '*'\n```\n\n#### SDK Testing\n\n```\n1. cd ts-client\n2. anchor localnet -- --features localnet\n3. pnpm run test\n```\n"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/6ipV2Sn7GCVgKG3Doqz1MpM33hranTMqxDmShj8Ro8cx.json",
    "content": "{\"account\":{\"data\":[\"XI5c3AWURrUCAAAAAAAAAAEAAAAAAAAA1IU0HY1iX4PqLSKapSAZ9V7oYfw81zuci7LhJHF22IQAAAAAAAAAAAAAAAAAAAAABY/C0QoScyYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAypo7AAAAAAAAAAAAAAAAcbAKlRVzviYBAAAAAAAAAAAqM56yJiR7qRugRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7FJFY2znCScBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8xoZLRRvVScBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJm1w5BEKoScBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8F5fGq47CcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4fSn6SJ6OCgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2p6yIUBPhCgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmKWG8c30CgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6UCVz7wzHCkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVfA2NyZDaCkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdCtJTQhmtCkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4wbgDWicACoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWERWdkrmTCoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANaZNhbRDmSoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATEOvOqu05SoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqtqrlzM5MisBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbie8nlLRfisBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxzShUw19yysBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABrJku2g8GCwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArUZZ3GkPZSwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv+YavhX2sSwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+yaPaXHw/iwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ5Hl6IH+Sy0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFvmXR0wgmS0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAINBqktVV5i0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1Hpt1yKfMy4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMqX6JTn8gC4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiZe4jh1tzi4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZouZI9XxGy8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiQDc92SKaS8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8RELINI2ty8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADsv+sSH3BDABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7XzcxFjLUjABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkxMXcXyzoDABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGtv0JGv7jABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApqb0/Z2/PDEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+4IEFqbjijEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJK9LNq8b2TEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuiDGfb5nJzIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Wm/DNnHdTIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuA/TBAQ8xDIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWd/siETEEjMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA80RJvZ9gYTMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcKF1xxoRsDMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1aBQzrrV/jMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnJAK+oSuTTQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIrYldH6bnDQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqV2Z6yc6zQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfZYkABSyOjUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkb6pa7rbiTUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ6TT2KQZ2TUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARnjDd9hrKDYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA02rueVrSdzYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQeEjBNxzYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATXpwdF7cFjcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyQlZ1up/ZjcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkugbto3tjcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM41kdTIEBjgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+CcaJPjkVTgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAptiLtTDapTgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBfbZeHj9TgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA422Acg8CRjkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWdJLGsA0ljkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASvxknfh75jkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFL5LPb7XNjoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu1zYPBZIhzoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGOg74AXN1zoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFJMAbZJmKDsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgwKKsEUeTsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"base64\"],\"executable\":false,\"lamports\":71437440,\"owner\":\"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\"rentEpoch\":18446744073709551615,\"space\":10136},\"pubkey\":\"6ipV2Sn7GCVgKG3Doqz1MpM33hranTMqxDmShj8Ro8cx\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/ERuqwiEFbQwNM8NhUMxUsvgGWbQpEyjbzhQLbBftCMPd.json",
    "content": "{\"account\":{\"data\":[\"XI5c3AWURrUAAAAAAAAAAAEAAAAAAAAA1IU0HY1iX4PqLSKapSAZ9V7oYfw81zuci7LhJHF22IQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAypo7AAAAAAAAAAAAAAAA76fGSzeJQQABAAAAAAAAAACWSNv/////PwyqOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzQUujzUjgwABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoRO5Ff/NxAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD0UELJiJBgEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX8/FHwVWSAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoPHNP0ozigEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4TwH3GshzAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbdx2RW4gDgIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMN48zlUwUAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXuUySZRkgIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj1/Ui+WC1AIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI/RuapbFFgMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADKbyuz0ZWQMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8C8K2N99mwMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAruJ8F4Hz3QMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK+4u1CV6IAQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUKohadIRYwQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/d9zMou6pQQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhJijVR06AQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA48ZG2DI/KwUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0tCaciobbgUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMpj1vD8IsQUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYmQNGXcG9AUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQKW36dQVNwYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtzzpkl02egYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATMi2eRVovQYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzepUBAGrAAcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADJYYmiT/QwcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqlR3o4RkhwcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+5MHiiXbygcBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/e2AuAtjDggBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV3O8mjv8UQgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgvW0nbmmlQgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5FCHL4pi2QgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHrdyv7EvHQkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWfnYvTQOYQkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsdI+nBf+pAkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApTJMzV7/6AkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsIfMxA4SLQoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3wmv9ys2cQoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAUH3LprtQoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADiYM6b+y+QoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAt8Aalz8LPgsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoh+0Xz51ggsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAucx+vcDwxgsBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzNxGLMt9CwwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuDr+KGIcUAwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlfK8MYrMlAwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEX3BxUeO2QwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwwpxZZ9hHg0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo89XkpVGYw0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkU4pzy49qA0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA66TAn29F7Q0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPNYgiVxfMg4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/Rd1EfqKdw4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYx0RwEzIvA4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT2NxHVkXAg8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPnw7syN4Rw8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXlw+DLHqjA8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAraVytAVv0g8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/T6OCYFGBABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyokKBetXRABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq7xlEd1moxABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqv9hhXwy6RABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3XLmFfoPLxEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHw7sVVr/dBEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo6X2aEAuxEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOcE5NtUTARIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG9RPAvk4RxIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"base64\"],\"executable\":false,\"lamports\":71437440,\"owner\":\"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\"rentEpoch\":18446744073709551615,\"space\":10136},\"pubkey\":\"ERuqwiEFbQwNM8NhUMxUsvgGWbQpEyjbzhQLbBftCMPd\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB.json",
    "content": "{\"account\":{\"data\":[\"IQsxYrVlsQ0QJx4AWAKIE0CcAAAwVwUAalX//5aqAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/woAAwAAAAAKAAAAECcAANYjK1IINMala6PQnLIrNY+ueDyVA1jhf0pZXPi99RQJBpuIV/6rgYT7aH9jRhjANdrEOdwa6ztVmKDwAAAAAAFnFuSSu++GgmnDsghSLvWYwChGzA+Xtw+GiGhD24q7TDHD5EuDMLrU9QzNBex+RQhysQLe3Wwgk3qe6dYJTIy2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhzz3TkqQbRDAtSIURflxYm+t9S0J8HtJm6TM3mhnJwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJcmd/lEKbh/6BL/3yM1WQGzw0ub30RbKoBToEq06bMHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADXvvLVcHYs26rHu6FZqhyvtry55mtf8qnM+QE50MBOzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"base64\"],\"executable\":false,\"lamports\":7182720,\"owner\":\"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\"rentEpoch\":18446744073709551615,\"space\":904},\"pubkey\":\"FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/FQuMNJ6UcrkA3xMLsmmLL8sk47RkZYod57mX3a8w1brg.json",
    "content": "{\"account\":{\"data\":[\"AQAAANe+8tVwdizbqse7oVmqHK+2vLnma1/yqcz5ATnQwE7PABAvMmFGYwEJAQEAAADXvvLVcHYs26rHu6FZqhyvtry55mtf8qnM+QE50MBOzw==\",\"base64\"],\"executable\":false,\"lamports\":1461600,\"owner\":\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\",\"rentEpoch\":18446744073709551615,\"space\":82},\"pubkey\":\"FQuMNJ6UcrkA3xMLsmmLL8sk47RkZYod57mX3a8w1brg\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/FR8HAZwQkmbmJXSqSp4CM3424emaMmJf7vz3u3RrYgRL.json",
    "content": "{\"account\":{\"data\":[\"XI5c3AWURrX9/////////wEAAAAAAAAA1IU0HY1iX4PqLSKapSAZ9V7oYfw81zuci7LhJHF22IQAAAAAAAAAAAAAAAAAAAAAadPBMAkGiM8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzlD5V88mvc8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArZKESy9V8s8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtri6hiyRJ9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAehHXhcraXNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0lT5xQwyktAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYd4lxfaWx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE+hFAowJ/dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAucQn/c+JMtEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArhp/NsYXaNEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjR7lL3KzndEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8c3Ya9dc09EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATyq/bfkTCdIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA03PjudvYPtIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU2R31YGrdNIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGqTRu+LqtIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeQ2lCd64NIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhlpIRi52FtMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA67yV5QaATNMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkZvU+7SXgtMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaWOiEzy9uNMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARJmEuJ/w7tMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVBXpduMxJdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkT4m3AqBW9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0Z7dhnekdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0mMQ1RJJyNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9A/3h/rB/tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3kAqINRINdUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzKWOL6Pda9UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5OLySGuAotUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG80PADAx2dUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJKaI6fTvD9YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfFjrmr28RtYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdLOwqo2XfdYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWac8sGiAtNYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoIHeQ1J369YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALynR/k18ItcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoVo7e1+PWdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAteQvVIqwkNcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr+StJdLfx9cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3QKhjDod/9cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKK/hJsdoNtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq101k3vCbdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZcNOcVsqpdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9BLOYWqg3NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXzlBBqwkFNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+BokASS3S9kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPtDg9dVXg9kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4uLPiMUGu9kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAy4o4X/bD8tkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMOtQH2yPKtoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxU8+cCppYtoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GkV+jRRmtoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK47aZY9H0toAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIfGBXT1MCtsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV+Xvi0JfQtsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgxj5nKKAetsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHdFiPWGwstsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9CvjGoLu6tsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0lkh5Ag7I9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPd21SPmVW9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANsgq+Vb/k9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFPr7piV3zNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ12XBGn9BN0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8iVdxSSSPd0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsA6gnVw1dt0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7JelQhTnrt0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYkWmak+n590AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf9zNzBF2IN4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBCDwAAAAAAm6I7IV9TWd4AAAAAAAAAAAAAAAAAAAAAQEIPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"base64\"],\"executable\":false,\"lamports\":71437440,\"owner\":\"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\"rentEpoch\":18446744073709551615,\"space\":10136},\"pubkey\":\"FR8HAZwQkmbmJXSqSp4CM3424emaMmJf7vz3u3RrYgRL\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/Gai2jqUAaJv8S68ibe69beV5DkhdBxAc6zoV3YQpuSNX.json",
    "content": "{\"account\":{\"data\":[\"XI5c3AWURrX//////////wEAAAAAAAAA1IU0HY1iX4PqLSKapSAZ9V7oYfw81zuci7LhJHF22IQAAAAAAAAAAAAAAAAAAAAAmSfomal/s+4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj6Coi6b8O4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhrXQaFjGLe8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUMK7ioBa+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZhBsNKpLqO8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/85P9ql5e8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+u+Er8PI/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2+5MtFyJYPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZqY9KrcSnvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmHLye9Kr2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9LzUsbJUGfEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDtW1VsNV/EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczLx8NHVlPEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+bsoEBmu0vEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QeJPzWWEPIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzqGnjCqOTvIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJbQjBv2VjPIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApUymu7CtyvIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqDivUnVCPMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA706WHswMR/MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnaiJ8DtUhfMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuPCPR52rw/MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4qKHOPQSAvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARLda2USKQPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuf+QJMRf/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/F1h+OovfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEt7NxTlQ/PQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+kUhFpoHO/UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJSXkwjPefUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV0xlWommuPUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv0/MhyCO9/UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvyEcOtKFNvYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADC2ykKKNdfYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQj6q5WltPYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfb1tra/N8/YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvAqWt/QFM/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqwK7mhOcvcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYJ5ydRCnsfcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtGWEc+8P8fcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFIGDwqJMPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqMbOb2QScPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnXzEvgKsr/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl8veJelV7/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGe4l0BsQL/kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArkez6Z7abvkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06qxn3a1rvkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+J5dIKeg7vkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjaYFmzScLvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL4UKQCOobvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1IXfQHfErvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGsEK0DTx7voAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmmMlIWAuL/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV/TbaP17b/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPpvu3BDar/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGcxtJ5I8PsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJpeMJqvHMPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6tv8bDpXcfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0KOTwVD3sfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHV93X/Kn8vwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ8fjgiNpM/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlCYqaeg6dP0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6p2xUEUdtf0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALm33eD4Q9v0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1TmPItgTN/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT1YjjxYoeP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVwl1Af5Muf4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYtVcvZKC+v4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGMDKB9nIO/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA45nGJtUfff8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBCDwAAAAAAkEVwYYuHvv8AAAAAAAAAAAAAAAAAAAAAQEIPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"base64\"],\"executable\":false,\"lamports\":71437440,\"owner\":\"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\"rentEpoch\":18446744073709551615,\"space\":10136},\"pubkey\":\"Gai2jqUAaJv8S68ibe69beV5DkhdBxAc6zoV3YQpuSNX\"}"
  },
  {
    "path": "artifacts/FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB/So11111111111111111111111111111111111111112.json",
    "content": "{\"account\":{\"data\":[\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"base64\"],\"executable\":false,\"lamports\":1384775953167,\"owner\":\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\",\"rentEpoch\":18446744073709551615,\"space\":82},\"pubkey\":\"So11111111111111111111111111111111111111112\"}"
  },
  {
    "path": "cli/Cargo.toml",
    "content": "[package]\nname = \"cli\"\nversion = \"0.5.2\"\nedition = \"2021\"\ndescription = \"cli\"\nauthors = [\"tian <tian@racoons.dev>\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[features]\n\n[dependencies]\ncommons = { workspace = true }\nanchor-lang = { workspace = true }\nanchor-spl = { workspace = true }\nanchor-client = { workspace = true, features = [\"async\"] }\nclap = { workspace = true, features = [\"derive\"] }\nanyhow = { workspace = true }\nshellexpand = { workspace = true }\nrust_decimal = { workspace = true, features = [\"maths\"] }\nspl-associated-token-account = { workspace = true }\nrand = { workspace = true }\ntokio = { workspace = true, features = [\"full\", \"parking_lot\"] }\nbincode = { workspace = true }\nspl-memo = { workspace = true, features = [\"no-entrypoint\"] }\nspl-transfer-hook-interface = { workspace = true }\nsolana-account-decoder = { workspace = true }\nnum-integer = { workspace = true }\nbytemuck = { workspace = true }\nfutures-util = { workspace = true }\n\nbigdecimal = \"0.4.2\"\nserde = \"1.0.167\"\nserde_json = \"1.0.100\"\nserde_json_any_key = \"2.0.0\"\n"
  },
  {
    "path": "cli/README.md",
    "content": "# DLMM Cli\n\nCommand line utility for managing DLMM program.\n\n### Toolchain\n\n```\nchannel = 1.76.0\n```\n\nIf you're using M1 chip\n\n```\nchannel = 1.76.0\ntarget triple = x86_64-apple-darwin\n# Eg: 1.76.0-x86_64-apple-darwin\n```\n\n### Build\n\n```\ncargo build\n```\n\n### Run\n\ntarget/debug/cli --help\n"
  },
  {
    "path": "cli/src/args.rs",
    "content": "use crate::instructions::{set_pair_status_permissionless::SetPairStatusPermissionlessParams, *};\nuse anchor_client::Cluster;\nuse clap::*;\n\n#[derive(Parser, Debug)]\npub struct ConfigOverride {\n    /// Cluster override\n    ///\n    /// Values = mainnet, testnet, devnet, localnet.\n    /// Default: mainnet\n    #[clap(global = true, long = \"provider.cluster\", default_value_t = Cluster::Mainnet)]\n    pub cluster: Cluster,\n    /// Wallet override\n    ///\n    /// Example: /path/to/wallet/keypair.json\n    /// Default: ~/.config/solana/id.json\n    #[clap(\n        global = true,\n        long = \"provider.wallet\",\n        default_value_t = String::from(shellexpand::tilde(\"~/.config/solana/id.json\"))\n    )]\n    pub wallet: String,\n    /// Priority fee\n    #[clap(global = true, long = \"priority-fee\", default_value_t = 0)]\n    pub priority_fee: u64,\n}\n\npub fn parse_bin_liquidity_removal(src: &str) -> Result<(i32, f64), Error> {\n    let mut parsed_str: Vec<&str> = src.split(',').collect();\n\n    let bps_to_remove = parsed_str\n        .pop()\n        .and_then(|s| s.parse::<f64>().ok())\n        .ok_or_else(|| clap::error::Error::new(error::ErrorKind::InvalidValue))?;\n\n    let bin_id = parsed_str\n        .pop()\n        .and_then(|s| s.parse::<i32>().ok())\n        .ok_or_else(|| clap::error::Error::new(error::ErrorKind::InvalidValue))?;\n\n    Ok((bin_id, bps_to_remove))\n}\n\npub fn parse_bin_liquidity_distribution(src: &str) -> Result<(i32, f64, f64), Error> {\n    let mut parsed_str: Vec<&str> = src.split(',').collect();\n\n    let dist_y = parsed_str\n        .pop()\n        .and_then(|s| s.parse::<f64>().ok())\n        .ok_or_else(|| clap::error::Error::new(error::ErrorKind::InvalidValue))?;\n\n    let dist_x = parsed_str\n        .pop()\n        .and_then(|s| s.parse::<f64>().ok())\n        .ok_or_else(|| clap::error::Error::new(error::ErrorKind::InvalidValue))?;\n\n    let delta_id = parsed_str\n        .pop()\n        .and_then(|s| s.parse::<i32>().ok())\n        .ok_or_else(|| clap::error::Error::new(error::ErrorKind::InvalidValue))?;\n\n    Ok((delta_id, dist_x, dist_y))\n}\n\n#[derive(Debug, Clone, ValueEnum)]\npub enum SelectiveRounding {\n    Up,\n    Down,\n    None,\n}\n\n#[derive(Parser, Debug)]\npub enum DLMMCommand {\n    /// Create a new liquidity pair.\n    InitializePair2(InitLbPair2Params),\n    /// Create a new liquidity pair.\n    InitializePair(InitLbPairParams),\n    /// Initialize bin array for the given liquidity pair. Use InitializeBinArrayWithPriceRange or InitializeBinArrayWithBinRange for a more user friendly version.\n    InitializeBinArray(InitBinArrayParams),\n    /// Initialize bin array for the given liquidity pair based on price range. For example: Initialize bin arrays for BTC/USDC from 20000 -> 30000 price.\n    InitializeBinArrayWithPriceRange(InitBinArrayWithPriceRangeParams),\n    /// Initialize bin array for the given liquidity pair based on bin range. For example: Initialize bin arrays for BTC/USDC from bin 5660 -> 6600.\n    InitializeBinArrayWithBinRange(InitBinArrayWithBinRangeParams),\n    /// Initialize position for the given liquidity pair based on price range.\n    InitializePositionWithPriceRange(InitPositionWithPriceRangeParams),\n    /// Initialize position for the given liquidity pair based on bin range.\n    InitializePosition(InitPositionParams),\n    /// Deposit liquidity to the position of the given liquidity pair.\n    AddLiquidity(AddLiquidityParams),\n    /// Remove liquidity from the position of the given liquidity pair.\n    RemoveLiquidity(RemoveLiquidityParams),\n    /// Trade token X -> Y, or vice versa.\n    SwapExactIn(SwapExactInParams),\n    SwapExactOut(SwapExactOutParams),\n    SwapWithPriceImpact(SwapWithPriceImpactParams),\n    /// Show information of the given liquidity pair.\n    ShowPair(ShowPairParams),\n    /// Show information of the given position.\n    ShowPosition(ShowPositionParams),\n    ClaimReward(ClaimRewardParams),\n    UpdateRewardDuration(UpdateRewardDurationParams),\n    UpdateRewardFunder(UpdateRewardFunderParams),\n    /// Close liquidity position.\n    ClosePosition(ClosePositionParams),\n    /// Claim fee\n    ClaimFee(ClaimFeeParams),\n    /// Increase an oracle observation sample length\n    IncreaseOracleLength(IncreaseOracleLengthParams),\n    ShowPresetParameter(ShowPresetAccountParams),\n    ListAllBinStep,\n    InitializeCustomizablePermissionlessLbPair(InitCustomizablePermissionlessLbPairParam),\n    InitializeCustomizablePermissionlessLbPair2(InitCustomizablePermissionlessLbPair2Param),\n    /// Seed liquidity by operator\n    SeedLiquidityByOperator(SeedLiquidityByOperatorParameters),\n    SeedLiquiditySingleBinByOperator(SeedLiquiditySingleBinByOperatorParameters),\n    SetPairStatusPermissionless(SetPairStatusPermissionlessParams),\n    GetAllPositionsForAnOwner(GetAllPositionsParams),\n    SyncPrice(SyncPriceParams),\n    #[clap(flatten)]\n    Admin(AdminCommand),\n}\n\n#[derive(Parser, Debug)]\n#[clap(version, about, author)]\npub struct Cli {\n    #[clap(flatten)]\n    pub config_override: ConfigOverride,\n    #[clap(subcommand)]\n    pub command: DLMMCommand,\n}\n\n#[derive(Debug, Parser)]\npub enum AdminCommand {\n    /// Create a new permission liquidity pair. It allow liquidity fragmentation with exact bin step.\n    InitializePermissionPair(InitPermissionLbPairParameters),\n    SetPairStatus(SetPairStatusParams),\n    /// Remove liquidity by price range\n    RemoveLiquidityByPriceRange(RemoveLiquidityByPriceRangeParameters),\n    SetActivationPoint(SetActivationPointParam),\n    WithdrawProtocolFee(WithdrawProtocolFeeParams),\n    InitializeReward(InitializeRewardParams),\n    FundReward(FundRewardParams),\n    InitializePresetParameter(InitPresetParameters),\n    ClosePresetParameter(ClosePresetAccountParams),\n    SetPreActivationDuration(SetPreactivationDurationParam),\n    SetPreActivationSwapAddress(SetPreactivationSwapAddressParam),\n    InitializeTokenBadge(InitializeTokenBadgeParams),\n    CreateClaimProtocolFeeOperator(CreateClaimFeeOperatorParams),\n    CloseClaimProtocolFeeOperator(CloseClaimFeeOperatorParams),\n    UpdateBaseFee(UpdateBaseFeeParams),\n}\n"
  },
  {
    "path": "cli/src/instructions/add_liquidity.rs",
    "content": "use crate::*;\nuse commons::dlmm::accounts::{LbPair, PositionV2};\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct AddLiquidityParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Position for the deposit.\n    pub position: Pubkey,\n    /// Amount of token X to be deposited.\n    pub amount_x: u64,\n    /// Amount of token Y to be deposited.\n    pub amount_y: u64,\n    /// Liquidity distribution to the bins. \"<DELTA_ID,DIST_X,DIST_Y, DELTA_ID,DIST_X,DIST_Y, ...>\" where\n    /// DELTA_ID = Number of bins surrounding the active bin. This decide which bin the token is going to deposit to. For example: if the current active id is 5555, delta_ids is 1, the user will be depositing to bin 5554, 5555, and 5556.\n    /// DIST_X = Percentage of amount_x to be deposited to the bins. Must not > 1.0\n    /// DIST_Y = Percentage of amount_y to be deposited to the bins. Must not > 1.0\n    /// For example: --bin-liquidity-distribution \"-1,0.0,0.25 0,0.75,0.75 1,0.25,0.0\"\n    #[clap(long, value_parser = parse_bin_liquidity_distribution, value_delimiter = ' ', allow_hyphen_values = true)]\n    pub bin_liquidity_distribution: Vec<(i32, f64, f64)>,\n}\n\npub async fn execute_add_liquidity<C: Deref<Target = impl Signer> + Clone>(\n    params: AddLiquidityParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let AddLiquidityParams {\n        lb_pair,\n        position,\n        amount_x,\n        amount_y,\n        mut bin_liquidity_distribution,\n    } = params;\n\n    // Sort by bin id\n    bin_liquidity_distribution.sort_by(|a, b| a.0.cmp(&b.0));\n\n    let rpc_client = program.rpc();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let bin_liquidity_distribution = bin_liquidity_distribution\n        .into_iter()\n        .map(|(bin_id, dist_x, dist_y)| BinLiquidityDistribution {\n            bin_id,\n            distribution_x: (dist_x * BASIS_POINT_MAX as f64) as u16,\n            distribution_y: (dist_y * BASIS_POINT_MAX as f64) as u16,\n        })\n        .collect::<Vec<_>>();\n\n    let position_state: PositionV2 = rpc_client\n        .get_account_and_deserialize(&position, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let min_bin_id = bin_liquidity_distribution\n        .first()\n        .map(|bld| bld.bin_id)\n        .context(\"No bin liquidity distribution provided\")?;\n\n    let max_bin_id = bin_liquidity_distribution\n        .last()\n        .map(|bld| bld.bin_id)\n        .context(\"No bin liquidity distribution provided\")?;\n\n    let bin_arrays_account_meta =\n        position_state.get_bin_array_accounts_meta_coverage_by_chunk(min_bin_id, max_bin_id)?;\n\n    let user_token_x = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_x_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let user_token_y = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_y_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let bin_array_bitmap_extension = rpc_client\n        .get_account(&bin_array_bitmap_extension)\n        .await\n        .map(|_| bin_array_bitmap_extension)\n        .ok()\n        .or(Some(dlmm::ID));\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::AddLiquidity2 {\n        lb_pair,\n        bin_array_bitmap_extension,\n        position,\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        sender: program.payer(),\n        user_token_x,\n        user_token_y,\n        token_x_program,\n        token_y_program,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    };\n\n    remaining_accounts.extend(bin_arrays_account_meta);\n\n    let data = dlmm::client::args::AddLiquidity2 {\n        liquidity_parameter: LiquidityParameter {\n            amount_x,\n            amount_y,\n            bin_liquidity_dist: bin_liquidity_distribution,\n        },\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let add_liquidity_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(add_liquidity_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Add Liquidity. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/close_claim_protocol_fee_operator.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct CloseClaimFeeOperatorParams {\n    #[clap(long)]\n    pub operator: Pubkey,\n}\n\npub async fn execute_close_claim_protocol_fee_operator<C: Deref<Target = impl Signer> + Clone>(\n    params: CloseClaimFeeOperatorParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let CloseClaimFeeOperatorParams { operator } = params;\n\n    let (claim_fee_operator, _bump) = derive_claim_protocol_fee_operator_pda(operator);\n\n    let accounts = dlmm::client::accounts::CloseClaimProtocolFeeOperator {\n        claim_fee_operator,\n        admin: program.payer(),\n        rent_receiver: program.payer(),\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::CloseClaimProtocolFeeOperator {}.data();\n\n    let instruction = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Close claim protocol fee operator. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/close_preset_parameter.rs",
    "content": "use crate::*;\nuse anchor_lang::Discriminator;\n\n#[derive(Debug, Parser)]\npub struct ClosePresetAccountParams {\n    /// Preset parameter pubkey. Get from ListAllBinStep\n    pub preset_parameter: Pubkey,\n}\n\npub async fn execute_close_preset_parameter<C: Deref<Target = impl Signer> + Clone>(\n    params: ClosePresetAccountParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let ClosePresetAccountParams { preset_parameter } = params;\n\n    let rpc_client = program.rpc();\n    let preset_parameter_account = rpc_client.get_account(&preset_parameter).await?;\n\n    let disc = &preset_parameter_account.data[..8];\n\n    let instruction = if disc == dlmm::accounts::PresetParameter::DISCRIMINATOR {\n        let accounts = dlmm::client::accounts::ClosePresetParameter {\n            admin: program.payer(),\n            rent_receiver: program.payer(),\n            preset_parameter,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::ClosePresetParameter {}.data();\n\n        Instruction {\n            program_id: dlmm::ID,\n            accounts,\n            data,\n        }\n    } else if disc == dlmm::accounts::PresetParameter2::DISCRIMINATOR {\n        let accounts = dlmm::client::accounts::ClosePresetParameter2 {\n            admin: program.payer(),\n            rent_receiver: program.payer(),\n            preset_parameter,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::ClosePresetParameter2 {}.data();\n\n        Instruction {\n            program_id: dlmm::ID,\n            accounts,\n            data,\n        }\n    } else {\n        bail!(\"Not a valid preset parameter account\");\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\n        \"Close preset parameter {}. Signature: {signature:#?}\",\n        preset_parameter\n    );\n\n    signature?;\n\n    Ok(preset_parameter)\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/create_claim_protocol_fee_operator.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct CreateClaimFeeOperatorParams {\n    #[clap(long)]\n    pub operator: Pubkey,\n}\n\npub async fn execute_create_claim_protocol_fee_operator<C: Deref<Target = impl Signer> + Clone>(\n    params: CreateClaimFeeOperatorParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let CreateClaimFeeOperatorParams { operator } = params;\n\n    let (claim_fee_operator, _bump) = derive_claim_protocol_fee_operator_pda(operator);\n\n    let accounts = dlmm::client::accounts::CreateClaimProtocolFeeOperator {\n        claim_fee_operator,\n        operator,\n        admin: program.payer(),\n        system_program: anchor_lang::system_program::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::CreateClaimProtocolFeeOperator {}.data();\n\n    let instruction = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Create claim protocol fee operator. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/initialize_permission_lb_pair.rs",
    "content": "use std::sync::Arc;\n\nuse crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\nuse commons::dlmm::types::{InitPermissionPairIx, Rounding};\n\n#[derive(Debug, Parser)]\npub struct InitPermissionLbPairParameters {\n    /// Bin step of the liquidity pair. It decide the bps when between bins.\n    pub bin_step: u16,\n    /// Token X mint of the liquidity pair. Eg: BTC. This should be the base token.\n    pub token_mint_x: Pubkey,\n    /// Token Y mint of the liquidity pair. Eg: USDC. This should be the quote token.\n    pub token_mint_y: Pubkey,\n    /// The initial price of the liquidity pair. Eg: 24123.12312412 USDC per 1 BTC.\n    pub initial_price: f64,\n    /// Base keypair path\n    pub base_keypair_path: String,\n    /// Base fee bps\n    pub base_fee_bps: u16,\n    /// Activation type\n    pub activation_type: u8,\n}\n\npub async fn execute_initialize_permission_lb_pair<C: Deref<Target = impl Signer> + Clone>(\n    params: InitPermissionLbPairParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitPermissionLbPairParameters {\n        bin_step,\n        token_mint_x,\n        token_mint_y,\n        initial_price,\n        base_keypair_path,\n        base_fee_bps,\n        activation_type,\n    } = params;\n\n    let base_keypair =\n        Arc::new(read_keypair_file(base_keypair_path).expect(\"base keypair file not found\"));\n\n    let rpc_client = program.rpc();\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[token_mint_x, token_mint_y])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport = price_per_token_to_per_lamport(\n        initial_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let computed_active_id = get_id_from_price(bin_step, &price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    let (lb_pair, _bump) =\n        derive_permission_lb_pair_pda(base_keypair.pubkey(), token_mint_x, token_mint_y, bin_step);\n\n    if program.rpc().get_account_data(&lb_pair).await.is_ok() {\n        return Ok(lb_pair);\n    }\n\n    let (reserve_x, _bump) = derive_reserve_pda(token_mint_x, lb_pair);\n    let (reserve_y, _bump) = derive_reserve_pda(token_mint_y, lb_pair);\n    let (oracle, _bump) = derive_oracle_pda(lb_pair);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let (token_badge_x, _bump) = derive_token_badge_pda(token_mint_x);\n    let (token_badge_y, _bump) = derive_token_badge_pda(token_mint_y);\n\n    let accounts = rpc_client\n        .get_multiple_accounts(&[token_badge_x, token_badge_y])\n        .await?;\n\n    let token_badge_x = accounts[0]\n        .as_ref()\n        .map(|_| token_badge_x)\n        .or(Some(dlmm::ID));\n\n    let token_badge_y = accounts[1]\n        .as_ref()\n        .map(|_| token_badge_y)\n        .or(Some(dlmm::ID));\n\n    let accounts = dlmm::client::accounts::InitializePermissionLbPair {\n        lb_pair,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        token_mint_x,\n        token_mint_y,\n        token_badge_x,\n        token_badge_y,\n        token_program_x: token_mint_base_account.owner,\n        token_program_y: token_mint_quote_account.owner,\n        oracle,\n        admin: program.payer(),\n        rent: solana_sdk::sysvar::rent::ID,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n        base: base_keypair.pubkey(),\n    }\n    .to_account_metas(None);\n\n    let (base_factor, base_fee_power_factor) =\n        compute_base_factor_from_fee_bps(bin_step, base_fee_bps)?;\n\n    let data = dlmm::client::args::InitializePermissionLbPair {\n        ix_data: InitPermissionPairIx {\n            active_id: computed_active_id,\n            bin_step,\n            base_factor,\n            activation_type,\n            base_fee_power_factor,\n            protocol_share: ILM_PROTOCOL_SHARE,\n        },\n    }\n    .data();\n\n    let init_pair_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_pair_ix)\n        .signer(base_keypair)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize Permission LB pair {lb_pair}. Signature: {signature:#?}\");\n\n    signature?;\n\n    println!(\"{lb_pair}\");\n\n    Ok(lb_pair)\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/initialize_preset_parameter.rs",
    "content": "use anchor_lang::Discriminator;\nuse commons::dlmm::{accounts::PresetParameter2, types::InitPresetParameters2Ix};\nuse solana_client::{\n    rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},\n    rpc_filter::{Memcmp, RpcFilterType},\n};\n\nuse crate::*;\n\n#[derive(Debug, Parser)]\npub struct InitPresetParameters {\n    /// Bin step. Represent the price increment / decrement.\n    pub bin_step: u16,\n    /// Used for base fee calculation. base_fee_rate = base_factor * bin_step\n    pub base_factor: u16,\n    /// Filter period determine high frequency trading time window.\n    pub filter_period: u16,\n    /// Decay period determine when the volatile fee start decay / decrease.\n    pub decay_period: u16,\n    /// Reduction factor controls the volatile fee rate decrement rate.\n    pub reduction_factor: u16,\n    /// Used to scale the variable fee component depending on the dynamic of the market\n    pub variable_fee_control: u32,\n    /// Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\n    pub max_volatility_accumulator: u32,\n    /// Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\n    pub protocol_share: u16,\n    /// Base fee power factor  \n    pub base_fee_power_factor: u8,\n}\n\npub async fn execute_initialize_preset_parameter<C: Deref<Target = impl Signer> + Clone>(\n    params: InitPresetParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitPresetParameters {\n        base_factor,\n        bin_step,\n        decay_period,\n        filter_period,\n        max_volatility_accumulator,\n        protocol_share,\n        reduction_factor,\n        variable_fee_control,\n        base_fee_power_factor,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let preset_parameter_v2_count = rpc_client\n        .get_program_accounts_with_config(\n            &dlmm::ID,\n            RpcProgramAccountsConfig {\n                filters: Some(vec![RpcFilterType::Memcmp(Memcmp::new_base58_encoded(\n                    0,\n                    &PresetParameter2::DISCRIMINATOR,\n                ))]),\n                account_config: RpcAccountInfoConfig {\n                    encoding: Some(UiAccountEncoding::Base64),\n                    data_slice: Some(UiDataSliceConfig {\n                        offset: 0,\n                        length: 0,\n                    }),\n                    ..Default::default()\n                },\n                ..Default::default()\n            },\n        )\n        .await?\n        .len();\n\n    let index = preset_parameter_v2_count as u16;\n\n    let (preset_parameter, _bump) =\n        derive_preset_parameter_pda_v2(preset_parameter_v2_count as u16);\n\n    let accounts = dlmm::client::accounts::InitializePresetParameter2 {\n        preset_parameter,\n        admin: program.payer(),\n        system_program: solana_sdk::system_program::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializePresetParameter2 {\n        ix: InitPresetParameters2Ix {\n            index,\n            bin_step,\n            base_factor,\n            filter_period,\n            decay_period,\n            reduction_factor,\n            variable_fee_control,\n            max_volatility_accumulator,\n            protocol_share,\n            base_fee_power_factor,\n        },\n    }\n    .data();\n\n    let init_preset_param_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_preset_param_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\n        \"Initialize preset parameter {}. Signature: {signature:#?}\",\n        preset_parameter\n    );\n\n    signature?;\n\n    Ok(preset_parameter)\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/initialize_reward.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct InitializeRewardParams {\n    pub lb_pair: Pubkey,\n    pub reward_mint: Pubkey,\n    pub reward_index: u64,\n    pub reward_duration: u64,\n    pub funder: Pubkey,\n}\n\npub async fn execute_initialize_reward<C: Deref<Target = impl Signer> + Clone>(\n    params: InitializeRewardParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let InitializeRewardParams {\n        lb_pair,\n        reward_mint,\n        reward_index,\n        reward_duration,\n        funder,\n    } = params;\n\n    let (reward_vault, _bump) = derive_reward_vault_pda(lb_pair, reward_index);\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let rpc_client = program.rpc();\n    let reward_mint_account = rpc_client.get_account(&reward_mint).await?;\n\n    let (token_badge, _bump) = derive_token_badge_pda(reward_mint);\n    let token_badge = rpc_client\n        .get_account(&token_badge)\n        .await\n        .ok()\n        .map(|_| token_badge)\n        .or(Some(dlmm::ID));\n\n    let accounts = dlmm::client::accounts::InitializeReward {\n        lb_pair,\n        reward_vault,\n        reward_mint,\n        admin: program.payer(),\n        token_program: reward_mint_account.owner,\n        token_badge,\n        rent: solana_sdk::sysvar::rent::ID,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeReward {\n        reward_index,\n        reward_duration,\n        funder,\n    }\n    .data();\n\n    let instruction = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize reward. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/initialize_token_badge.rs",
    "content": "use crate::*;\nuse solana_sdk::system_program;\n\n#[derive(Debug, Parser)]\npub struct InitializeTokenBadgeParams {\n    /// Token mint address\n    pub mint: Pubkey,\n}\n\npub async fn execute_initialize_token_badge<C: Deref<Target = impl Signer> + Clone>(\n    params: InitializeTokenBadgeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let InitializeTokenBadgeParams { mint } = params;\n\n    let (token_badge, _bump) = derive_token_badge_pda(mint);\n\n    let accounts = dlmm::client::accounts::InitializeTokenBadge {\n        admin: program.payer(),\n        token_mint: mint,\n        system_program: system_program::ID,\n        token_badge,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeTokenBadge {}.data();\n\n    let instruction = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize token badge {}. Signature: {signature:#?}\", mint);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/mod.rs",
    "content": "pub mod close_preset_parameter;\npub use close_preset_parameter::*;\n\npub mod initialize_permission_lb_pair;\npub use initialize_permission_lb_pair::*;\n\npub mod initialize_preset_parameter;\npub use initialize_preset_parameter::*;\n\npub mod initialize_reward;\npub use initialize_reward::*;\n\npub mod set_activation_point;\npub use set_activation_point::*;\n\npub mod set_pre_activation_duration;\npub use set_pre_activation_duration::*;\n\npub mod set_pre_activation_swap_address;\npub use set_pre_activation_swap_address::*;\n\npub mod toggle_pair_status;\npub use toggle_pair_status::*;\n\npub mod update_reward_duration;\npub use update_reward_duration::*;\n\npub mod update_reward_funder;\npub use update_reward_funder::*;\n\npub mod withdraw_protocol_fee;\npub use withdraw_protocol_fee::*;\n\npub mod initialize_token_badge;\npub use initialize_token_badge::*;\n\npub mod create_claim_protocol_fee_operator;\npub use create_claim_protocol_fee_operator::*;\n\npub mod close_claim_protocol_fee_operator;\npub use close_claim_protocol_fee_operator::*;\n\npub mod update_base_fee;\npub use update_base_fee::*;\n"
  },
  {
    "path": "cli/src/instructions/admin/set_activation_point.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct SetActivationPointParam {\n    /// Address of the pair\n    pub lb_pair: Pubkey,\n    /// Activation point\n    pub activation_point: u64,\n}\n\npub async fn execute_set_activation_point<C: Deref<Target = impl Signer> + Clone>(\n    params: SetActivationPointParam,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetActivationPointParam {\n        lb_pair,\n        activation_point,\n    } = params;\n\n    let accounts = dlmm::client::accounts::SetActivationPoint {\n        admin: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::SetActivationPoint { activation_point }.data();\n\n    let set_activation_point_ix = Instruction {\n        accounts,\n        data,\n        program_id: dlmm::ID,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(set_activation_point_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Set activation point. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/set_pre_activation_duration.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct SetPreactivationDurationParam {\n    pub lb_pair: Pubkey,\n    pub pre_activation_duration: u16,\n}\n\npub async fn execute_set_pre_activation_duration<C: Deref<Target = impl Signer> + Clone>(\n    params: SetPreactivationDurationParam,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetPreactivationDurationParam {\n        lb_pair,\n        pre_activation_duration,\n    } = params;\n\n    let accounts = dlmm::client::accounts::SetPreActivationDuration {\n        creator: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::SetPreActivationDuration {\n        pre_activation_duration: pre_activation_duration as u64,\n    }\n    .data();\n\n    let set_pre_activation_slot_duration_ix = Instruction {\n        accounts,\n        data,\n        program_id: dlmm::ID,\n    };\n\n    let request_builder = program.request();\n\n    let signature = request_builder\n        .instruction(set_pre_activation_slot_duration_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Set pre activation duration. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/set_pre_activation_swap_address.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct SetPreactivationSwapAddressParam {\n    pub lb_pair: Pubkey,\n    pub pre_activation_swap_address: Pubkey,\n}\n\npub async fn execute_set_pre_activation_swap_address<C: Deref<Target = impl Signer> + Clone>(\n    params: SetPreactivationSwapAddressParam,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetPreactivationSwapAddressParam {\n        lb_pair,\n        pre_activation_swap_address,\n    } = params;\n\n    let accounts = dlmm::client::accounts::SetPreActivationSwapAddress {\n        creator: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::SetPreActivationSwapAddress {\n        pre_activation_swap_address,\n    }\n    .data();\n\n    let set_pre_activation_swap_address_ix = Instruction {\n        accounts,\n        data,\n        program_id: dlmm::ID,\n    };\n\n    let request_builder = program.request();\n\n    let signature = request_builder\n        .instruction(set_pre_activation_swap_address_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\n        \"Set pre activation swap address. Signature: {:#?}\",\n        signature\n    );\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/toggle_pair_status.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct SetPairStatusParams {\n    /// Address of the pair\n    pub lb_pair: Pubkey,\n    /// Pair status. 0 is enabled, 1 is disabled\n    pub pair_status: u8,\n}\n\npub async fn execute_set_pair_status<C: Deref<Target = impl Signer> + Clone>(\n    params: SetPairStatusParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetPairStatusParams {\n        lb_pair,\n        pair_status,\n    } = params;\n\n    let accounts = dlmm::client::accounts::SetPairStatus {\n        admin: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::SetPairStatus {\n        status: pair_status,\n    }\n    .data();\n\n    let instruction = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(instruction)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Set pair status. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/update_base_fee.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct UpdateBaseFeeParams {\n    pub lb_pair: Pubkey,\n    pub base_fee_bps: u16,\n}\n\npub async fn execute_update_base_fee<C: Deref<Target = impl Signer> + Clone>(\n    params: UpdateBaseFeeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let UpdateBaseFeeParams {\n        lb_pair,\n        base_fee_bps,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let pair_account = rpc_client.get_account(&lb_pair).await?;\n\n    let lb_pair_state = LbPair::try_deserialize(&mut pair_account.data.as_ref())?;\n\n    let (base_factor, base_fee_power_factor) =\n        compute_base_factor_from_fee_bps(lb_pair_state.bin_step, base_fee_bps)?;\n\n    let ix_data = dlmm::client::args::UpdateBaseFeeParameters {\n        fee_parameter: BaseFeeParameter {\n            protocol_share: lb_pair_state.parameters.protocol_share,\n            base_factor,\n            base_fee_power_factor,\n        },\n    }\n    .data();\n\n    let event_authority = derive_event_authority_pda().0;\n\n    let accounts = dlmm::client::accounts::UpdateBaseFeeParameters {\n        lb_pair,\n        admin: program.payer(),\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let ix = Instruction {\n        program_id: program.id(),\n        data: ix_data,\n        accounts: accounts.to_vec(),\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Update base fee. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/update_reward_duration.rs",
    "content": "use crate::*;\nuse commons::dlmm::accounts::{BinArray, LbPair};\n\n#[derive(Debug, Parser)]\npub struct UpdateRewardDurationParams {\n    pub lb_pair: Pubkey,\n    pub reward_index: u64,\n    pub reward_duration: u64,\n}\n\npub async fn execute_update_reward_duration<C: Deref<Target = impl Signer> + Clone>(\n    params: UpdateRewardDurationParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let UpdateRewardDurationParams {\n        lb_pair,\n        reward_index,\n        reward_duration,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let active_bin_array_idx = BinArray::bin_id_to_bin_array_index(lb_pair_state.active_id)?;\n    let (bin_array, _bump) = derive_bin_array_pda(lb_pair, active_bin_array_idx as i64);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::UpdateRewardDuration {\n        lb_pair,\n        admin: program.payer(),\n        bin_array,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::UpdateRewardDuration {\n        reward_index,\n        new_duration: reward_duration,\n    }\n    .data();\n\n    let ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Fund reward. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/update_reward_funder.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct UpdateRewardFunderParams {\n    pub lb_pair: Pubkey,\n    pub reward_index: u64,\n    pub funder: Pubkey,\n}\n\npub async fn execute_update_reward_funder<C: Deref<Target = impl Signer> + Clone>(\n    params: UpdateRewardFunderParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let UpdateRewardFunderParams {\n        lb_pair,\n        reward_index,\n        funder,\n    } = params;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::UpdateRewardFunder {\n        lb_pair,\n        admin: program.payer(),\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::UpdateRewardFunder {\n        reward_index,\n        new_funder: funder,\n    }\n    .data();\n\n    let ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Fund reward. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/admin/withdraw_protocol_fee.rs",
    "content": "use anchor_spl::associated_token::get_associated_token_address_with_program_id;\nuse commons::dlmm::accounts::LbPair;\n\nuse crate::*;\n#[derive(Debug, Parser)]\npub struct WithdrawProtocolFeeParams {\n    pub lb_pair: Pubkey,\n}\n\npub async fn execute_withdraw_protocol_fee<C: Deref<Target = impl Signer> + Clone>(\n    params: WithdrawProtocolFeeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let WithdrawProtocolFeeParams { lb_pair } = params;\n\n    let rpc_client = program.rpc();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let receiver_token_x = get_associated_token_address_with_program_id(\n        &program.payer(),\n        &lb_pair_state.token_x_mint,\n        &token_x_program,\n    );\n\n    let receiver_token_y = get_associated_token_address_with_program_id(\n        &program.payer(),\n        &lb_pair_state.token_y_mint,\n        &token_y_program,\n    );\n\n    let (claim_fee_operator, _) = derive_claim_protocol_fee_operator_pda(program.payer());\n\n    let main_accounts = dlmm::client::accounts::WithdrawProtocolFee {\n        lb_pair,\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        token_x_program,\n        token_y_program,\n        receiver_token_x,\n        receiver_token_y,\n        claim_fee_operator,\n        operator: program.payer(),\n        memo_program: spl_memo::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    };\n\n    let data = dlmm::client::args::WithdrawProtocolFee {\n        max_amount_x: u64::MAX,\n        max_amount_y: u64::MAX,\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let withdraw_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(200_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(withdraw_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"WithdrawProtocolFee. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/claim_fee.rs",
    "content": "use crate::*;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct ClaimFeeParams {\n    /// Position address\n    pub position: Pubkey,\n}\n\npub async fn execute_claim_fee<C: Deref<Target = impl Signer> + Clone>(\n    params: ClaimFeeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let ClaimFeeParams { position } = params;\n\n    let rpc_client = program.rpc();\n    let position_state: PositionV2 = rpc_client\n        .get_account_and_deserialize(&position, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&position_state.lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let (user_token_x, user_token_y) = if position_state.fee_owner.eq(&Pubkey::default()) {\n        let user_token_x = get_or_create_ata(\n            program,\n            transaction_config,\n            lb_pair_state.token_x_mint,\n            program.payer(),\n            compute_unit_price.clone(),\n        )\n        .await?;\n\n        let user_token_y = get_or_create_ata(\n            program,\n            transaction_config,\n            lb_pair_state.token_y_mint,\n            program.payer(),\n            compute_unit_price.clone(),\n        )\n        .await?;\n\n        (user_token_x, user_token_y)\n    } else {\n        let user_token_x = get_or_create_ata(\n            program,\n            transaction_config,\n            lb_pair_state.token_x_mint,\n            position_state.fee_owner,\n            compute_unit_price.clone(),\n        )\n        .await?;\n\n        let user_token_y = get_or_create_ata(\n            program,\n            transaction_config,\n            lb_pair_state.token_y_mint,\n            position_state.fee_owner,\n            compute_unit_price.clone(),\n        )\n        .await?;\n\n        (user_token_x, user_token_y)\n    };\n\n    let [token_program_x, token_program_y] = lb_pair_state.get_token_programs()?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::ClaimFee2 {\n        lb_pair: position_state.lb_pair,\n        sender: program.payer(),\n        position,\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_program_x,\n        token_program_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        user_token_x,\n        user_token_y,\n        event_authority,\n        program: dlmm::ID,\n        memo_program: spl_memo::id(),\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut token_2022_remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        token_2022_remaining_accounts.extend(transfer_hook_remaining_accounts);\n    };\n\n    for (min_bin_id, max_bin_id) in\n        position_bin_range_chunks(position_state.lower_bin_id, position_state.upper_bin_id)\n    {\n        let data = dlmm::client::args::ClaimFee2 {\n            min_bin_id,\n            max_bin_id,\n            remaining_accounts_info: remaining_accounts_info.clone(),\n        }\n        .data();\n\n        let bin_arrays_account_meta =\n            position_state.get_bin_array_accounts_meta_coverage_by_chunk(min_bin_id, max_bin_id)?;\n\n        let accounts = [\n            main_accounts.to_vec(),\n            token_2022_remaining_accounts.clone(),\n            bin_arrays_account_meta,\n        ]\n        .concat();\n\n        let claim_fee_ix = Instruction {\n            program_id: dlmm::ID,\n            accounts,\n            data,\n        };\n\n        let mut request_builder = program.request();\n\n        if let Some(compute_unit_price_ix) = compute_unit_price.clone() {\n            request_builder = request_builder.instruction(compute_unit_price_ix);\n        }\n\n        let signature = request_builder\n            .instruction(claim_fee_ix)\n            .send_with_spinner_and_config(transaction_config)\n            .await;\n\n        println!(\"Claim fee. Signature: {:#?}\", signature);\n\n        signature?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/claim_reward.rs",
    "content": "use crate::*;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct ClaimRewardParams {\n    pub lb_pair: Pubkey,\n    pub reward_index: u64,\n    pub position: Pubkey,\n}\n\npub async fn execute_claim_reward<C: Deref<Target = impl Signer> + Clone>(\n    params: ClaimRewardParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let ClaimRewardParams {\n        lb_pair,\n        reward_index,\n        position,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let (reward_vault, _bump) = derive_reward_vault_pda(lb_pair, reward_index);\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let position_state: PositionV2 = rpc_client\n        .get_account_and_deserialize(&position, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let reward_info = lb_pair_state.reward_infos[reward_index as usize];\n    let reward_mint = reward_info.mint;\n\n    let reward_mint_program = rpc_client.get_account(&reward_mint).await?.owner;\n\n    let user_token_account = get_or_create_ata(\n        program,\n        transaction_config,\n        reward_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::ClaimReward2 {\n        lb_pair,\n        reward_vault,\n        reward_mint,\n        memo_program: spl_memo::ID,\n        token_program: reward_mint_program,\n        position,\n        user_token_account,\n        sender: program.payer(),\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut token_2022_remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Reward(reward_index as usize),\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        token_2022_remaining_accounts.extend(transfer_hook_remaining_accounts);\n    };\n\n    for (min_bin_id, max_bin_id) in\n        position_bin_range_chunks(position_state.lower_bin_id, position_state.upper_bin_id)\n    {\n        let data = dlmm::client::args::ClaimReward2 {\n            reward_index,\n            min_bin_id,\n            max_bin_id,\n            remaining_accounts_info: remaining_accounts_info.clone(),\n        }\n        .data();\n\n        let bin_arrays_account_meta =\n            position_state.get_bin_array_accounts_meta_coverage_by_chunk(min_bin_id, max_bin_id)?;\n\n        let accounts = [\n            main_accounts.to_vec(),\n            token_2022_remaining_accounts.clone(),\n            bin_arrays_account_meta,\n        ]\n        .concat();\n\n        let claim_reward_ix = Instruction {\n            program_id: dlmm::ID,\n            accounts,\n            data,\n        };\n\n        let request_builder = program.request();\n        let signature = request_builder\n            .instruction(claim_reward_ix)\n            .send_with_spinner_and_config(transaction_config)\n            .await;\n\n        println!(\"Claim reward. Signature: {:#?}\", signature);\n\n        signature?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/close_position.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct ClosePositionParams {\n    pub position: Pubkey,\n}\n\npub async fn execute_close_position<C: Deref<Target = impl Signer> + Clone>(\n    params: ClosePositionParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let ClosePositionParams { position } = params;\n\n    let rpc_client = program.rpc();\n    let position_state: PositionV2 = rpc_client\n        .get_account_and_deserialize(&position, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let bin_arrays_account_meta = position_state.get_bin_array_accounts_meta_coverage()?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::ClosePosition2 {\n        sender: position_state.owner,\n        rent_receiver: position_state.owner,\n        position,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::ClosePosition2 {}.data();\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let accounts = [main_accounts.to_vec(), bin_arrays_account_meta].concat();\n\n    let close_position_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(close_position_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Close position. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/fund_reward.rs",
    "content": "use crate::*;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct FundRewardParams {\n    pub lb_pair: Pubkey,\n    pub reward_index: u64,\n    pub funding_amount: u64,\n}\n\npub async fn execute_fund_reward<C: Deref<Target = impl Signer> + Clone>(\n    params: FundRewardParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let FundRewardParams {\n        lb_pair,\n        reward_index,\n        funding_amount,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let (reward_vault, _bump) = derive_reward_vault_pda(lb_pair, reward_index);\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let reward_info = lb_pair_state.reward_infos[reward_index as usize];\n    let reward_mint = reward_info.mint;\n\n    let reward_mint_program = rpc_client.get_account(&reward_mint).await?.owner;\n\n    let funder_token_account = get_or_create_ata(\n        program,\n        transaction_config,\n        reward_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let active_bin_array_idx = BinArray::bin_id_to_bin_array_index(lb_pair_state.active_id)?;\n    let (bin_array, _bump) = derive_bin_array_pda(lb_pair, active_bin_array_idx as i64);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let reward_transfer_hook_accounts =\n        get_extra_account_metas_for_transfer_hook(reward_mint, program.rpc()).await?;\n\n    let remaining_accounts_info = RemainingAccountsInfo {\n        slices: vec![RemainingAccountsSlice {\n            accounts_type: AccountsType::TransferHookReward,\n            length: reward_transfer_hook_accounts.len() as u8,\n        }],\n    };\n\n    let main_accounts = dlmm::client::accounts::FundReward {\n        lb_pair,\n        reward_vault,\n        reward_mint,\n        funder: program.payer(),\n        funder_token_account,\n        bin_array,\n        token_program: reward_mint_program,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::FundReward {\n        reward_index,\n        amount: funding_amount,\n        carry_forward: true,\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), reward_transfer_hook_accounts].concat();\n\n    let fund_reward_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(fund_reward_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Fund reward. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/get_all_positions.rs",
    "content": "use crate::*;\nuse solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig};\n\n#[derive(Debug, Parser)]\npub struct GetAllPositionsParams {\n    /// Address of the pair\n    #[clap(long)]\n    lb_pair: Pubkey,\n    /// Owner of position\n    #[clap(long)]\n    owner: Pubkey,\n}\n\npub async fn execute_get_all_positions<C: Deref<Target = impl Signer> + Clone>(\n    program: &Program<C>,\n    params: GetAllPositionsParams,\n) -> Result<()> {\n    let GetAllPositionsParams { lb_pair, owner } = params;\n\n    let rpc_client = program.rpc();\n\n    let account_config = RpcAccountInfoConfig {\n        encoding: Some(UiAccountEncoding::Base64),\n        ..Default::default()\n    };\n    let config = RpcProgramAccountsConfig {\n        filters: Some(position_filter_by_wallet_and_pair(owner, lb_pair)),\n        account_config,\n        ..Default::default()\n    };\n\n    let accounts = rpc_client\n        .get_program_accounts_with_config(&dlmm::ID, config)\n        .await?;\n\n    for (position_key, position_raw_account) in accounts {\n        let position_state: PositionV2 =\n            bytemuck::pod_read_unaligned(&position_raw_account.data[8..]);\n        println!(\n            \"Position {} fee owner {}\",\n            position_key, position_state.fee_owner\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/ilm/mod.rs",
    "content": "pub mod remove_liquidity_by_price_range;\npub use remove_liquidity_by_price_range::*;\n\npub mod seed_liquidity_from_operator;\npub use seed_liquidity_from_operator::*;\n\npub mod seed_liquidity_single_bin_by_operator;\npub use seed_liquidity_single_bin_by_operator::*;\n"
  },
  {
    "path": "cli/src/instructions/ilm/remove_liquidity_by_price_range.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct RemoveLiquidityByPriceRangeParameters {\n    /// Address of the pair\n    pub lb_pair: Pubkey,\n    // base position path\n    pub base_position_key: Pubkey,\n    /// min price\n    pub min_price: f64,\n    /// max price\n    pub max_price: f64,\n}\n\npub async fn execute_remove_liquidity_by_price_range<C: Deref<Target = impl Signer> + Clone>(\n    params: RemoveLiquidityByPriceRangeParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let RemoveLiquidityByPriceRangeParameters {\n        lb_pair,\n        base_position_key,\n        min_price,\n        max_price,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let bin_step = lb_pair_state.bin_step;\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[lb_pair_state.token_x_mint, lb_pair_state.token_y_mint])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let min_price_per_lamport = price_per_token_to_per_lamport(\n        min_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let min_active_id = get_id_from_price(bin_step, &min_price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    let max_price_per_lamport = price_per_token_to_per_lamport(\n        max_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let max_active_id = get_id_from_price(bin_step, &max_price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    assert!(min_active_id < max_active_id);\n\n    let user_token_x = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_x_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let user_token_y = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_y_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n    let bin_array_bitmap_extension = rpc_client\n        .get_account(&bin_array_bitmap_extension)\n        .await\n        .map(|_| bin_array_bitmap_extension)\n        .ok()\n        .or(Some(dlmm::ID));\n\n    let width = DEFAULT_BIN_PER_POSITION as i32;\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut transfer_hook_remaining_accounts = vec![];\n\n    if let Some((slices, remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        transfer_hook_remaining_accounts.extend(remaining_accounts);\n    };\n\n    for i in min_active_id..=max_active_id {\n        let (position, _bump) = derive_position_pda(lb_pair, base_position_key, i, width);\n\n        let position_account = rpc_client.get_account(&position).await;\n        if let std::result::Result::Ok(account) = position_account {\n            let position_state: PositionV2 = bytemuck::pod_read_unaligned(&account.data[8..]);\n\n            let bin_arrays_account_meta = position_state.get_bin_array_accounts_meta_coverage()?;\n\n            let remaining_accounts = [\n                transfer_hook_remaining_accounts.clone(),\n                bin_arrays_account_meta,\n            ]\n            .concat();\n\n            let mut instructions =\n                vec![ComputeBudgetInstruction::set_compute_unit_limit(1_400_000)];\n\n            let main_accounts = dlmm::client::accounts::RemoveLiquidityByRange2 {\n                position,\n                lb_pair,\n                bin_array_bitmap_extension,\n                user_token_x,\n                user_token_y,\n                reserve_x: lb_pair_state.reserve_x,\n                reserve_y: lb_pair_state.reserve_y,\n                token_x_mint: lb_pair_state.token_x_mint,\n                token_y_mint: lb_pair_state.token_y_mint,\n                sender: program.payer(),\n                token_x_program,\n                token_y_program,\n                memo_program: spl_memo::ID,\n                event_authority,\n                program: dlmm::ID,\n            }\n            .to_account_metas(None);\n\n            let data = dlmm::client::args::RemoveLiquidityByRange2 {\n                from_bin_id: position_state.lower_bin_id,\n                to_bin_id: position_state.upper_bin_id,\n                bps_to_remove: BASIS_POINT_MAX as u16,\n                remaining_accounts_info: remaining_accounts_info.clone(),\n            }\n            .data();\n\n            let accounts = [main_accounts.to_vec(), remaining_accounts.clone()].concat();\n\n            let withdraw_all_ix = Instruction {\n                program_id: dlmm::ID,\n                accounts,\n                data,\n            };\n\n            instructions.push(withdraw_all_ix);\n\n            let main_accounts = dlmm::client::accounts::ClaimFee2 {\n                lb_pair,\n                position,\n                sender: program.payer(),\n                reserve_x: lb_pair_state.reserve_x,\n                reserve_y: lb_pair_state.reserve_y,\n                token_x_mint: lb_pair_state.token_x_mint,\n                token_y_mint: lb_pair_state.token_y_mint,\n                token_program_x: token_x_program,\n                token_program_y: token_y_program,\n                memo_program: spl_memo::ID,\n                event_authority,\n                program: dlmm::ID,\n                user_token_x,\n                user_token_y,\n            }\n            .to_account_metas(None);\n\n            let data = dlmm::client::args::ClaimFee2 {\n                min_bin_id: position_state.lower_bin_id,\n                max_bin_id: position_state.upper_bin_id,\n                remaining_accounts_info: remaining_accounts_info.clone(),\n            }\n            .data();\n\n            let accounts = [main_accounts.to_vec(), remaining_accounts.clone()].concat();\n\n            let claim_fee_ix = Instruction {\n                program_id: dlmm::ID,\n                accounts,\n                data,\n            };\n\n            instructions.push(claim_fee_ix);\n\n            let accounts = dlmm::client::accounts::ClosePosition2 {\n                position,\n                sender: program.payer(),\n                rent_receiver: program.payer(),\n                event_authority,\n                program: dlmm::ID,\n            }\n            .to_account_metas(None);\n\n            let data = dlmm::client::args::ClosePosition2 {}.data();\n\n            let close_position_ix = Instruction {\n                program_id: dlmm::ID,\n                accounts,\n                data,\n            };\n\n            instructions.push(close_position_ix);\n\n            println!(\n                \"Close position {}. Min bin id {}, Max bin id {}\",\n                position, position_state.lower_bin_id, position_state.upper_bin_id\n            );\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/ilm/seed_liquidity_from_operator.rs",
    "content": "use std::{collections::HashMap, ops::Index, u64};\n\nuse crate::*;\nuse anchor_lang::{prelude::Clock, AccountDeserialize};\nuse anchor_spl::{\n    associated_token::get_associated_token_address_with_program_id,\n    token_interface::{spl_token_2022::instruction::transfer_checked, Mint, TokenAccount},\n};\n\nuse futures_util::future::try_join_all;\nuse spl_associated_token_account::instruction::create_associated_token_account_idempotent;\n\npub fn to_wei_amount(amount: u64, decimal: u8) -> Result<u64> {\n    let wei_amount = amount\n        .checked_mul(10u64.pow(decimal.into()))\n        .context(\"to_wei_amount overflow\")?;\n\n    Ok(wei_amount)\n}\n\npub fn convert_min_max_ui_price_to_min_max_bin_id(\n    bin_step: u16,\n    min_price: f64,\n    max_price: f64,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n) -> Result<(i32, i32)> {\n    let min_price_per_lamport =\n        price_per_token_to_per_lamport(min_price, base_token_decimal, quote_token_decimal)\n            .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let min_active_id = get_id_from_price(bin_step, &min_price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    let max_price_per_lamport =\n        price_per_token_to_per_lamport(max_price, base_token_decimal, quote_token_decimal)\n            .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let max_active_id = get_id_from_price(bin_step, &max_price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    Ok((min_active_id, max_active_id))\n}\n\nfn get_base(bin_step: u16) -> f64 {\n    1.0 + bin_step as f64 / 10_000.0\n}\n\npub fn get_ui_price_from_id(\n    bin_step: u16,\n    bin_id: i32,\n    base_token_decimal: i32,\n    quote_token_decimal: i32,\n) -> f64 {\n    let base = get_base(bin_step);\n    base.powi(bin_id) * 10.0f64.powi(base_token_decimal - quote_token_decimal)\n}\n\npub fn get_number_of_position_required_to_cover_range(\n    min_bin_id: i32,\n    max_bin_id: i32,\n) -> Result<i32> {\n    let bin_delta = max_bin_id\n        .checked_sub(min_bin_id)\n        .context(\"bin_delta overflow\")?;\n    let mut position_required = bin_delta\n        .checked_div(DEFAULT_BIN_PER_POSITION as i32)\n        .context(\"position_required overflow\")?;\n    let rem = bin_delta % DEFAULT_BIN_PER_POSITION as i32;\n\n    if rem > 0 {\n        position_required += 1;\n    }\n\n    Ok(position_required)\n}\n\nstruct CompressionResult {\n    compressed_bin_amount: HashMap<i32, u32>,\n    compression_loss: u64,\n}\n\nfn compress_bin_amount(\n    bins_amount: HashMap<i32, u64>,\n    multiplier: u64,\n) -> Result<CompressionResult> {\n    let mut compressed_bin_amount = HashMap::new();\n\n    let mut compression_loss = 0u64;\n\n    for (bin_id, amount) in bins_amount.into_iter() {\n        let compressed_amount: u32 = amount\n            .checked_div(multiplier)\n            .context(\"overflow\")?\n            .try_into()\n            .context(\"compressed fail\")?;\n        compressed_bin_amount.insert(bin_id, compressed_amount);\n\n        let loss = amount\n            .checked_sub(\n                u64::from(compressed_amount)\n                    .checked_mul(multiplier)\n                    .context(\"overflow\")?,\n            )\n            .context(\"overflow\")?;\n\n        compression_loss = compression_loss.checked_add(loss).context(\"overflow\")?;\n    }\n\n    Ok(CompressionResult {\n        compressed_bin_amount,\n        compression_loss,\n    })\n}\n\n#[derive(Debug, Parser, Clone)]\npub struct SeedLiquidityByOperatorParameters {\n    /// Address of the pair\n    #[clap(long)]\n    pub lb_pair: Pubkey,\n    /// Base position path\n    #[clap(long)]\n    pub base_position_path: String,\n    /// Amount of x\n    #[clap(long)]\n    pub amount: u64,\n    /// Min price\n    #[clap(long)]\n    pub min_price: f64,\n    /// Max price\n    #[clap(long)]\n    pub max_price: f64,\n    /// Base pubkey\n    #[clap(long)]\n    pub base_pubkey: Pubkey,\n    /// Curvature\n    #[clap(long)]\n    pub curvature: f64,\n    /// position owner\n    #[clap(long)]\n    pub position_owner: Pubkey,\n    /// fee owner\n    #[clap(long)]\n    pub fee_owner: Pubkey,\n    /// lock release point\n    #[clap(long)]\n    pub lock_release_point: u64,\n    /// Max retries\n    #[clap(long)]\n    pub max_retries: u16,\n}\n\npub async fn execute_seed_liquidity_by_operator<C: Deref<Target = impl Signer> + Clone>(\n    params: SeedLiquidityByOperatorParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let SeedLiquidityByOperatorParameters {\n        lb_pair,\n        base_position_path,\n        amount,\n        min_price,\n        max_price,\n        base_pubkey,\n        curvature,\n        position_owner,\n        fee_owner,\n        lock_release_point,\n        ..\n    } = params;\n\n    let position_base_kp = read_keypair_file(base_position_path.clone())\n        .expect(\"position base keypair file not found\");\n\n    assert!(\n        position_base_kp.pubkey() == base_pubkey,\n        \"base_pubkey mismatch\"\n    );\n\n    let rpc_client = program.rpc();\n\n    let k = 1.0 / curvature;\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let bin_step = lb_pair_state.bin_step;\n\n    let (mut bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[\n            lb_pair_state.token_x_mint,\n            lb_pair_state.token_y_mint,\n            solana_sdk::sysvar::clock::ID,\n            bitmap_extension,\n        ])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n    let clock_account = accounts[2].take().context(\"clock not found\")?;\n    let bitmap_extension_account = accounts[3].take();\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n    let clock = bincode::deserialize::<Clock>(&clock_account.data)?;\n\n    let fund_amount = to_wei_amount(amount, token_mint_base.decimals)?;\n\n    let (min_bin_id, max_bin_id) = convert_min_max_ui_price_to_min_max_bin_id(\n        bin_step,\n        min_price,\n        max_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )?;\n\n    let actual_min_price = get_ui_price_from_id(\n        bin_step,\n        min_bin_id,\n        token_mint_base.decimals.into(),\n        token_mint_quote.decimals.into(),\n    );\n    let actual_max_price = get_ui_price_from_id(\n        bin_step,\n        max_bin_id,\n        token_mint_base.decimals.into(),\n        token_mint_quote.decimals.into(),\n    );\n\n    let position_number = get_number_of_position_required_to_cover_range(min_bin_id, max_bin_id)?;\n\n    println!(\"Start seed. Min price: {} Max price: {} Actual min price: {} Actual max price: {} Min bin id: {} Max bin id: {} Position: {}\", min_price, max_price, actual_min_price, actual_max_price, min_bin_id, max_bin_id, position_number);\n\n    assert!(min_bin_id < max_bin_id, \"Invalid price range\");\n\n    let bins_amount = generate_amount_for_bins(\n        bin_step,\n        min_bin_id,\n        max_bin_id,\n        actual_min_price,\n        actual_max_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n        fund_amount,\n        k,\n    );\n\n    let bins_amount_map: HashMap<i32, u64> = bins_amount\n        .iter()\n        .map(|(bin_id, amount_x)| (*bin_id, *amount_x))\n        .collect();\n\n    let decompress_multiplier = 10u64.pow(token_mint_base.decimals.into());\n\n    let CompressionResult {\n        compressed_bin_amount,\n        compression_loss,\n    } = compress_bin_amount(bins_amount_map, decompress_multiplier)?;\n\n    let width = DEFAULT_BIN_PER_POSITION as i32;\n\n    let mut token_account_and_bitmap_ext_and_token_prove_setup_ixs = vec![];\n    let mut position_and_bin_array_setup_ixs = vec![];\n    let mut liquidity_setup_ixs = vec![];\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n    let seeder = program.payer();\n\n    let token_mint_base_owner = token_mint_base_account.owner;\n    let token_mint_quote_owner = token_mint_quote_account.owner;\n\n    let seeder_token_x = get_associated_token_address_with_program_id(\n        &seeder,\n        &lb_pair_state.token_x_mint,\n        &token_mint_base_owner,\n    );\n\n    let seeder_token_y = get_associated_token_address_with_program_id(\n        &seeder,\n        &lb_pair_state.token_y_mint,\n        &token_mint_quote_owner,\n    );\n\n    let owner_token_x = get_associated_token_address_with_program_id(\n        &position_owner,\n        &lb_pair_state.token_x_mint,\n        &token_mint_base_owner,\n    );\n\n    let transfer_hook_x_account =\n        get_extra_account_metas_for_transfer_hook(lb_pair_state.token_x_mint, program.rpc())\n            .await?;\n\n    let transfer_hook_y_account =\n        get_extra_account_metas_for_transfer_hook(lb_pair_state.token_y_mint, program.rpc())\n            .await?;\n\n    let accounts = rpc_client\n        .get_multiple_accounts(&[seeder_token_x, seeder_token_y, owner_token_x])\n        .await?;\n\n    let seeder_token_x_account = accounts.index(0);\n    if seeder_token_x_account.is_none() {\n        token_account_and_bitmap_ext_and_token_prove_setup_ixs.push(\n            create_associated_token_account_idempotent(\n                &seeder,\n                &seeder,\n                &lb_pair_state.token_x_mint,\n                &token_mint_base_owner,\n            ),\n        );\n    }\n\n    let seeder_token_y_account = accounts.index(1);\n    if seeder_token_y_account.is_none() {\n        token_account_and_bitmap_ext_and_token_prove_setup_ixs.push(\n            create_associated_token_account_idempotent(\n                &seeder,\n                &seeder,\n                &lb_pair_state.token_y_mint,\n                &token_mint_quote_owner,\n            ),\n        );\n    }\n\n    let owner_token_x_account = accounts.index(2);\n    let mut require_token_prove = false;\n\n    if owner_token_x_account.is_none() {\n        require_token_prove = true;\n    } else if let Some(account) = owner_token_x_account.to_owned() {\n        let owner_token_x_state = TokenAccount::try_deserialize(&mut account.data.as_slice())?;\n        require_token_prove = owner_token_x_state.amount == 0;\n    }\n\n    if require_token_prove {\n        token_account_and_bitmap_ext_and_token_prove_setup_ixs.push(\n            create_associated_token_account_idempotent(\n                &seeder,\n                &position_owner,\n                &lb_pair_state.token_x_mint,\n                &token_mint_base_owner,\n            ),\n        );\n\n        let prove_amount =\n            calculate_transfer_fee_included_amount(&token_mint_base_account, 1, clock.epoch)?\n                .amount;\n\n        let mut transfer_ix = transfer_checked(\n            &token_mint_base_owner,\n            &seeder_token_x,\n            &lb_pair_state.token_x_mint,\n            &owner_token_x,\n            &seeder,\n            &[],\n            prove_amount,\n            token_mint_base.decimals,\n        )?;\n\n        transfer_ix\n            .accounts\n            .extend_from_slice(&transfer_hook_x_account);\n\n        token_account_and_bitmap_ext_and_token_prove_setup_ixs.push(transfer_ix);\n    }\n\n    let (min_bitmap_id, max_bitmap_id) = LbPair::bitmap_range();\n    let lower_bin_array_index = BinArray::bin_id_to_bin_array_index(min_bin_id)?;\n    let upper_bin_array_index = BinArray::bin_id_to_bin_array_index(max_bin_id - 1)?;\n\n    let overflow_internal_bitmap_range =\n        upper_bin_array_index > max_bitmap_id || lower_bin_array_index < min_bitmap_id;\n\n    if overflow_internal_bitmap_range && bitmap_extension_account.is_none() {\n        let accounts = dlmm::client::accounts::InitializeBinArrayBitmapExtension {\n            lb_pair,\n            bin_array_bitmap_extension: bitmap_extension,\n            funder: seeder,\n            system_program: solana_sdk::system_program::ID,\n            rent: solana_sdk::sysvar::rent::ID,\n        }\n        .to_account_metas(None);\n\n        let ix_data = dlmm::client::args::InitializeBinArrayBitmapExtension {}.data();\n\n        let init_bitmap_ext_ix = Instruction {\n            program_id: dlmm::ID,\n            accounts,\n            data: ix_data,\n        };\n\n        token_account_and_bitmap_ext_and_token_prove_setup_ixs.push(init_bitmap_ext_ix);\n    } else {\n        bitmap_extension = dlmm::ID;\n    }\n\n    for i in 0..position_number {\n        let lower_bin_id = min_bin_id + (DEFAULT_BIN_PER_POSITION as i32 * i);\n        let upper_bin_id = lower_bin_id + DEFAULT_BIN_PER_POSITION as i32 - 1;\n        let upper_bin_id = std::cmp::min(upper_bin_id, max_bin_id - 1);\n\n        let mut instructions = vec![];\n\n        let (position, _bump) =\n            derive_position_pda(lb_pair, position_base_kp.pubkey(), lower_bin_id, width);\n\n        let bin_array_account_metas =\n            BinArray::get_bin_array_account_metas_coverage(lower_bin_id, upper_bin_id, lb_pair)?;\n\n        let bin_array_indexes =\n            BinArray::get_bin_array_indexes_coverage(lower_bin_id, upper_bin_id)?;\n\n        let keys: Vec<_> = [position]\n            .into_iter()\n            .chain(\n                bin_array_indexes\n                    .iter()\n                    .map(|&index| derive_bin_array_pda(lb_pair, index.into()).0),\n            )\n            .collect();\n\n        let accounts = rpc_client.get_multiple_accounts(&keys).await?;\n\n        let position_account = accounts.index(0).to_owned();\n        if position_account.is_none() {\n            let account = dlmm::client::accounts::InitializePositionByOperator {\n                position,\n                payer: seeder,\n                base: position_base_kp.pubkey(),\n                lb_pair,\n                owner: position_owner,\n                operator: seeder,\n                operator_token_x: seeder_token_x,\n                owner_token_x,\n                system_program: solana_sdk::system_program::ID,\n                event_authority,\n                program: dlmm::ID,\n            }\n            .to_account_metas(None);\n\n            let ix_data = dlmm::client::args::InitializePositionByOperator {\n                lower_bin_id,\n                width,\n                fee_owner,\n                lock_release_point,\n            }\n            .data();\n\n            let init_position_ix = Instruction {\n                program_id: dlmm::ID,\n                accounts: account.to_vec(),\n                data: ix_data,\n            };\n\n            instructions.push(init_position_ix);\n        }\n\n        let bin_array_account = &accounts[1..];\n\n        for (account, index) in bin_array_account.iter().zip(bin_array_indexes) {\n            if account.is_none() {\n                let bin_array = derive_bin_array_pda(lb_pair, index.into()).0;\n                let accounts = dlmm::client::accounts::InitializeBinArray {\n                    bin_array,\n                    lb_pair,\n                    funder: seeder,\n                    system_program: solana_sdk::system_program::ID,\n                }\n                .to_account_metas(None);\n\n                let ix_data = dlmm::client::args::InitializeBinArray {\n                    index: index.into(),\n                }\n                .data();\n\n                let init_bin_array_ix = Instruction {\n                    program_id: dlmm::ID,\n                    accounts,\n                    data: ix_data,\n                };\n\n                instructions.push(init_bin_array_ix);\n            }\n        }\n\n        if !instructions.is_empty() {\n            if let Some(cu_price_ix) = compute_unit_price.clone() {\n                instructions.push(cu_price_ix);\n            }\n\n            position_and_bin_array_setup_ixs.push(instructions.clone());\n        }\n\n        instructions.clear();\n\n        let position_deposited = position_account\n            .map(|account| {\n                let state: PositionV2 = bytemuck::pod_read_unaligned(&account.data[8..]);\n                state.liquidity_shares.iter().any(|share| *share > 0)\n            })\n            .unwrap_or(false);\n\n        if !position_deposited {\n            let mut bins = vec![];\n\n            for bin_id in lower_bin_id..=upper_bin_id {\n                bins.push(CompressedBinDepositAmount {\n                    bin_id,\n                    amount: *compressed_bin_amount\n                        .get(&bin_id)\n                        .context(\"Missing bin amount to deposit\")?,\n                });\n            }\n\n            let ix_data = dlmm::client::args::AddLiquidityOneSidePrecise2 {\n                liquidity_parameter: AddLiquiditySingleSidePreciseParameter2 {\n                    bins,\n                    decompress_multiplier,\n                    max_amount: u64::MAX,\n                },\n                remaining_accounts_info: RemainingAccountsInfo {\n                    slices: vec![RemainingAccountsSlice {\n                        accounts_type: AccountsType::TransferHookX,\n                        length: transfer_hook_x_account.len() as u8,\n                    }],\n                },\n            }\n            .data();\n\n            let accounts = dlmm::client::accounts::AddLiquidityOneSidePrecise2 {\n                position,\n                lb_pair,\n                bin_array_bitmap_extension: Some(bitmap_extension),\n                user_token: seeder_token_x,\n                reserve: lb_pair_state.reserve_x,\n                token_mint: lb_pair_state.token_x_mint,\n                sender: program.payer(),\n                token_program: token_mint_base_owner,\n                event_authority,\n                program: dlmm::ID,\n            }\n            .to_account_metas(None);\n\n            let mut accounts = accounts.to_vec();\n            accounts.extend_from_slice(&transfer_hook_x_account);\n            accounts.extend_from_slice(&bin_array_account_metas);\n\n            let add_liquidity_ix = Instruction {\n                program_id: dlmm::ID,\n                accounts,\n                data: ix_data,\n            };\n\n            if instructions.is_empty() {\n                if let Some(cu_price_ix) = compute_unit_price.clone() {\n                    instructions.push(cu_price_ix);\n                }\n                instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(800_000));\n            }\n\n            instructions.push(add_liquidity_ix);\n\n            // Last position\n            if i + 1 == position_number && compression_loss > 0 {\n                let loss_includes_transfer_fee = calculate_transfer_fee_included_amount(\n                    &token_mint_base_account,\n                    compression_loss,\n                    clock.epoch,\n                )?\n                .amount;\n\n                let bin_array_account_metas = BinArray::get_bin_array_account_metas_coverage(\n                    upper_bin_id,\n                    upper_bin_id,\n                    lb_pair,\n                )?;\n\n                let ix_data = dlmm::client::args::AddLiquidity2 {\n                    liquidity_parameter: LiquidityParameter {\n                        amount_x: loss_includes_transfer_fee,\n                        amount_y: 0,\n                        bin_liquidity_dist: vec![BinLiquidityDistribution {\n                            bin_id: upper_bin_id,\n                            distribution_x: BASIS_POINT_MAX as u16,\n                            distribution_y: BASIS_POINT_MAX as u16,\n                        }],\n                    },\n                    remaining_accounts_info: RemainingAccountsInfo {\n                        slices: vec![\n                            RemainingAccountsSlice {\n                                accounts_type: AccountsType::TransferHookX,\n                                length: transfer_hook_x_account.len() as u8,\n                            },\n                            RemainingAccountsSlice {\n                                accounts_type: AccountsType::TransferHookY,\n                                length: transfer_hook_y_account.len() as u8,\n                            },\n                        ],\n                    },\n                }\n                .data();\n\n                let accounts = dlmm::client::accounts::AddLiquidity2 {\n                    position,\n                    lb_pair,\n                    bin_array_bitmap_extension: Some(bitmap_extension),\n                    user_token_x: seeder_token_x,\n                    user_token_y: seeder_token_y,\n                    reserve_x: lb_pair_state.reserve_x,\n                    reserve_y: lb_pair_state.reserve_y,\n                    token_x_mint: lb_pair_state.token_x_mint,\n                    token_y_mint: lb_pair_state.token_y_mint,\n                    token_x_program: token_mint_base_owner,\n                    token_y_program: token_mint_quote_owner,\n                    sender: program.payer(),\n                    event_authority,\n                    program: dlmm::ID,\n                }\n                .to_account_metas(None);\n\n                let mut accounts = accounts.to_vec();\n                accounts.extend_from_slice(&transfer_hook_x_account);\n                accounts.extend_from_slice(&transfer_hook_y_account);\n                accounts.extend_from_slice(&bin_array_account_metas);\n\n                let add_liquidity_ix = Instruction {\n                    program_id: dlmm::ID,\n                    accounts,\n                    data: ix_data,\n                };\n\n                if instructions.is_empty() {\n                    if let Some(cu_price_ix) = compute_unit_price.clone() {\n                        instructions.push(cu_price_ix);\n                    }\n\n                    instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(800_000));\n                }\n\n                instructions.push(add_liquidity_ix);\n            }\n\n            if !instructions.is_empty() {\n                liquidity_setup_ixs.push(instructions);\n            }\n        }\n    }\n\n    println!(\"Init token account, bitmap extension and transfer token prove if necessary\");\n    if !token_account_and_bitmap_ext_and_token_prove_setup_ixs.is_empty() {\n        let mut builder = program.request();\n\n        for ix in token_account_and_bitmap_ext_and_token_prove_setup_ixs {\n            builder = builder.instruction(ix);\n        }\n\n        let signature = builder\n            .send_with_spinner_and_config(transaction_config)\n            .await;\n\n        println!(\"{:#?}\", signature);\n        signature?;\n    }\n    println!(\"Init token account, bitmap extension and transfer token prove if necessary - DONE\");\n\n    println!(\"Setup position and bin arrays if necessary\");\n    if !position_and_bin_array_setup_ixs.is_empty() {\n        let mut futures = vec![];\n\n        for ixs in position_and_bin_array_setup_ixs {\n            let mut builder = program.request();\n\n            for ix in ixs {\n                builder = builder.instruction(ix);\n            }\n\n            futures.push(builder.send_with_spinner_and_config(transaction_config));\n        }\n\n        let result = try_join_all(futures).await;\n        println!(\"{:#?}\", result);\n        result?;\n    }\n    println!(\"Setup position and bin arrays if necessary - DONE\");\n\n    println!(\"Seed liquidity\");\n    if !liquidity_setup_ixs.is_empty() {\n        let mut futures = vec![];\n        for ixs in liquidity_setup_ixs {\n            let mut builder = program.request();\n\n            for ix in ixs {\n                builder = builder.instruction(ix);\n            }\n\n            futures.push(builder.send_with_spinner_and_config(transaction_config));\n        }\n\n        let result = try_join_all(futures).await;\n        println!(\"{:#?}\", result);\n        result?;\n    }\n    println!(\"Seed liquidity - DONE\");\n\n    Ok(())\n}\n\nfn get_bin_deposit_amount(\n    amount: u64,\n    bin_step: u16,\n    bin_id: i32,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n    min_price: f64,\n    max_price: f64,\n    k: f64,\n) -> u64 {\n    let c1 = get_c(\n        amount,\n        bin_step,\n        bin_id + 1,\n        base_token_decimal,\n        quote_token_decimal,\n        min_price,\n        max_price,\n        k,\n    );\n\n    let c0 = get_c(\n        amount,\n        bin_step,\n        bin_id,\n        base_token_decimal,\n        quote_token_decimal,\n        min_price,\n        max_price,\n        k,\n    );\n\n    assert!(c1 > c0);\n\n    let amount_into_bin = c1 - c0;\n    amount_into_bin\n}\n\n// c(p) = 5 * 10^8 ((p - 0.1)/0.7) ^ 1.25, where P = ui price\n// c(p) = 5 * 10^8 ((p - min_price)/(max_price - min_price)) ^ 1.25\nfn get_c(\n    amount: u64,\n    bin_step: u16,\n    bin_id: i32,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n    min_price: f64,\n    max_price: f64,\n    k: f64,\n) -> u64 {\n    let price_per_lamport = (1.0 + bin_step as f64 / 10000.0).powi(bin_id);\n\n    let current_price =\n        price_per_lamport * 10.0f64.powi(base_token_decimal as i32 - quote_token_decimal as i32);\n\n    let price_range = max_price - min_price;\n    let current_price_delta_from_min = current_price - min_price;\n\n    let c = amount as f64 * ((current_price_delta_from_min / price_range).powf(k));\n    c as u64\n}\n\npub fn generate_amount_for_bins(\n    bin_step: u16,\n    min_bin_id: i32,\n    max_bin_id: i32,\n    min_price: f64,\n    max_price: f64,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n    amount: u64,\n    k: f64,\n) -> Vec<(i32, u64)> {\n    let mut total_amount = 0;\n    let mut bin_amounts = vec![];\n\n    // Last bin is purposely no included because for the last bin, c(last_bin +1) - c(last_bin) will > fund amount\n    for bin_id in min_bin_id..max_bin_id {\n        let bin_amount = get_bin_deposit_amount(\n            amount,\n            bin_step,\n            bin_id,\n            base_token_decimal,\n            quote_token_decimal,\n            min_price,\n            max_price,\n            k,\n        );\n\n        bin_amounts.push((bin_id, bin_amount));\n\n        total_amount += bin_amount;\n    }\n\n    assert_eq!(\n        total_amount, amount,\n        \"Amount distributed to bins not equals to funding amount\"\n    );\n\n    bin_amounts\n}\n"
  },
  {
    "path": "cli/src/instructions/ilm/seed_liquidity_single_bin_by_operator.rs",
    "content": "use std::sync::Arc;\n\nuse anchor_lang::{prelude::Clock, AccountDeserialize};\nuse anchor_spl::{\n    associated_token::get_associated_token_address_with_program_id,\n    token::spl_token::instruction::transfer_checked,\n    token_interface::{Mint, TokenAccount},\n};\nuse spl_associated_token_account::instruction::create_associated_token_account_idempotent;\n\nuse crate::*;\n\n#[derive(Debug, Parser)]\npub struct SeedLiquiditySingleBinByOperatorParameters {\n    /// Address of the pair\n    #[clap(long)]\n    pub lb_pair: Pubkey,\n    /// Base position path\n    #[clap(long)]\n    pub base_position_path: String,\n    /// Base position pubkey\n    #[clap(long)]\n    pub base_pubkey: Pubkey,\n    /// amount of x\n    #[clap(long)]\n    pub amount: u64,\n    /// price\n    #[clap(long)]\n    pub price: f64,\n    /// Position owner\n    #[clap(long)]\n    pub position_owner: Pubkey,\n    /// lock release point\n    #[clap(long)]\n    pub lock_release_point: u64,\n    /// fee owner\n    #[clap(long)]\n    pub fee_owner: Pubkey,\n    /// Selective rounding\n    #[clap(long)]\n    pub selective_rounding: SelectiveRounding,\n}\n\npub async fn execute_seed_liquidity_single_bin_by_operator<\n    C: Deref<Target = impl Signer> + Clone,\n>(\n    params: SeedLiquiditySingleBinByOperatorParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let SeedLiquiditySingleBinByOperatorParameters {\n        lb_pair,\n        base_position_path,\n        base_pubkey,\n        amount,\n        price,\n        position_owner,\n        lock_release_point,\n        fee_owner,\n        selective_rounding,\n    } = params;\n\n    let position_base_kp = Arc::new(\n        read_keypair_file(base_position_path).expect(\"position base keypair file not found\"),\n    );\n\n    assert_eq!(\n        position_base_kp.pubkey(),\n        base_pubkey,\n        \"Invalid position base key\"\n    );\n\n    let rpc_client = program.rpc();\n    let operator = program.payer();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let [token_x_owner, token_y_owner] = lb_pair_state.get_token_programs()?;\n\n    let bin_step = lb_pair_state.bin_step;\n\n    let operator_token_x = get_associated_token_address_with_program_id(\n        &operator,\n        &lb_pair_state.token_x_mint,\n        &token_x_owner,\n    );\n\n    let operator_token_y = get_associated_token_address_with_program_id(\n        &operator,\n        &lb_pair_state.token_y_mint,\n        &token_y_owner,\n    );\n\n    let owner_token_x = get_associated_token_address_with_program_id(\n        &position_owner,\n        &lb_pair_state.token_x_mint,\n        &token_x_owner,\n    );\n\n    let (mut bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[\n            lb_pair_state.token_x_mint,\n            lb_pair_state.token_y_mint,\n            owner_token_x,\n            bin_array_bitmap_extension,\n            solana_sdk::sysvar::clock::ID,\n        ])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n    let owner_token_x_account = accounts[2].take();\n    let bin_array_bitmap_extension_account = accounts[3].take();\n    let clock_account = accounts[4].take().context(\"clock not found\")?;\n\n    let clock = bincode::deserialize::<Clock>(&clock_account.data)?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let native_amount = to_wei_amount(amount, token_mint_base.decimals)?;\n    let native_amount = calculate_transfer_fee_included_amount(\n        &token_mint_base_account,\n        native_amount,\n        clock.epoch,\n    )?\n    .amount;\n\n    let price =\n        price_per_token_to_per_lamport(price, token_mint_base.decimals, token_mint_quote.decimals)\n            .context(\"price_per_token_per_lamport overflow\")?;\n\n    let bin_id = match selective_rounding {\n        SelectiveRounding::None => get_precise_id_from_price(bin_step, &price)\n            .context(\"fail to get exact bin id for the price\"),\n        SelectiveRounding::Down => get_id_from_price(bin_step, &price, Rounding::Down)\n            .context(\"get_id_from_price overflow\"),\n        SelectiveRounding::Up => {\n            get_id_from_price(bin_step, &price, Rounding::Up).context(\"get_id_from_price overflow\")\n        }\n    }?;\n\n    assert_eq!(\n        lb_pair_state.active_id, bin_id,\n        \"bin id doesn't match active bin id\"\n    );\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n    let (position, _bump) = derive_position_pda(lb_pair, base_pubkey, bin_id, 1);\n\n    let bin_array_accounts_meta =\n        BinArray::get_bin_array_account_metas_coverage(bin_id, bin_id, lb_pair)?;\n\n    let bin_array_index = BinArray::bin_id_to_bin_array_index(bin_id)?;\n\n    let mut instructions = vec![ComputeBudgetInstruction::set_compute_unit_limit(1_400_000)];\n\n    if let Some(priority_fee_ix) = compute_unit_price {\n        instructions.push(priority_fee_ix);\n    }\n\n    let (min_bitmap_id, max_bitmap_id) = LbPair::bitmap_range();\n    // We only deposit to lower bin array\n    let overflow_internal_bitmap_range =\n        bin_array_index > max_bitmap_id || bin_array_index < min_bitmap_id;\n\n    if overflow_internal_bitmap_range && bin_array_bitmap_extension_account.is_none() {\n        let accounts = dlmm::client::accounts::InitializeBinArrayBitmapExtension {\n            lb_pair,\n            bin_array_bitmap_extension,\n            funder: program.payer(),\n            system_program: solana_sdk::system_program::ID,\n            rent: solana_sdk::sysvar::rent::ID,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::InitializeBinArrayBitmapExtension {}.data();\n\n        let initialize_bitmap_extension_ix = Instruction {\n            accounts,\n            program_id: dlmm::ID,\n            data,\n        };\n\n        instructions.push(initialize_bitmap_extension_ix);\n    } else {\n        bin_array_bitmap_extension = dlmm::ID;\n    }\n\n    let account = dlmm::client::accounts::InitializeBinArray {\n        lb_pair,\n        bin_array: bin_array_accounts_meta[0].pubkey,\n        funder: program.payer(),\n        system_program: solana_sdk::system_program::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeBinArray {\n        index: bin_array_index.into(),\n    }\n    .data();\n\n    let initialize_bin_array_ix = Instruction {\n        accounts: account.to_vec(),\n        program_id: dlmm::ID,\n        data,\n    };\n\n    instructions.push(initialize_bin_array_ix);\n\n    let require_token_prove = if let Some(account) = owner_token_x_account {\n        let token_account = TokenAccount::try_deserialize(&mut account.data.as_ref())?;\n        token_account.amount == 0\n    } else {\n        true\n    };\n\n    if require_token_prove {\n        instructions.push(create_associated_token_account_idempotent(\n            &operator,\n            &position_owner,\n            &lb_pair_state.token_x_mint,\n            &token_x_owner,\n        ));\n\n        let prove_amount =\n            calculate_transfer_fee_included_amount(&token_mint_base_account, 1, clock.epoch)?\n                .amount;\n\n        instructions.push(transfer_checked(\n            &token_x_owner,\n            &operator_token_x,\n            &lb_pair_state.token_x_mint,\n            &owner_token_x,\n            &operator,\n            &[],\n            prove_amount,\n            token_mint_base.decimals,\n        )?);\n    }\n\n    let accounts = dlmm::client::accounts::InitializePositionByOperator {\n        lb_pair,\n        base: base_pubkey,\n        owner: position_owner,\n        operator: program.payer(),\n        payer: program.payer(),\n        position,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        operator_token_x,\n        owner_token_x,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializePositionByOperator {\n        lower_bin_id: bin_id,\n        width: 1,\n        fee_owner,\n        lock_release_point,\n    }\n    .data();\n\n    let initialize_position_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    instructions.push(initialize_position_ix);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slice, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slice;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    }\n\n    remaining_accounts.extend(bin_array_accounts_meta);\n\n    let main_accounts = dlmm::client::accounts::AddLiquidity2 {\n        position,\n        lb_pair,\n        bin_array_bitmap_extension: Some(bin_array_bitmap_extension),\n        user_token_x: operator_token_x,\n        user_token_y: operator_token_y,\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        sender: program.payer(),\n        token_x_program: token_mint_base_account.owner,\n        token_y_program: token_mint_quote_account.owner,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::AddLiquidity2 {\n        liquidity_parameter: LiquidityParameter {\n            amount_x: native_amount,\n            amount_y: 0,\n            bin_liquidity_dist: vec![BinLiquidityDistribution {\n                bin_id,\n                distribution_x: 10000,\n                distribution_y: 10000,\n            }],\n        },\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let deposit_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    instructions.push(deposit_ix);\n\n    let mut builder = program.request();\n    builder = builder.signer(position_base_kp);\n    builder = instructions\n        .into_iter()\n        .fold(builder, |builder, ix| builder.instruction(ix));\n\n    let signature = builder\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"{:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/increase_oracle_length.rs",
    "content": "use crate::*;\nuse anchor_client::solana_sdk;\n\n#[derive(Debug, Parser)]\npub struct IncreaseOracleLengthParams {\n    pub lb_pair: Pubkey,\n    pub length_to_add: u64,\n}\n\npub async fn execute_increase_oracle_length<C: Deref<Target = impl Signer> + Clone>(\n    params: IncreaseOracleLengthParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let IncreaseOracleLengthParams {\n        lb_pair,\n        length_to_add,\n    } = params;\n\n    let (oracle, _) = derive_oracle_pda(lb_pair);\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::IncreaseOracleLength {\n        funder: program.payer(),\n        oracle,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::IncreaseOracleLength { length_to_add }.data();\n\n    let increase_length_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(increase_length_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Increase oracle {oracle} length. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_bin_array.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct InitBinArrayParams {\n    /// Index of the bin array.\n    #[clap(long, allow_negative_numbers = true)]\n    pub bin_array_index: i64,\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n}\n\npub async fn execute_initialize_bin_array<C: Deref<Target = impl Signer> + Clone>(\n    params: InitBinArrayParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitBinArrayParams {\n        lb_pair,\n        bin_array_index,\n    } = params;\n\n    let (bin_array, _bump) = derive_bin_array_pda(lb_pair, bin_array_index);\n\n    let accounts = dlmm::client::accounts::InitializeBinArray {\n        bin_array,\n        funder: program.payer(),\n        lb_pair,\n        system_program: solana_sdk::system_program::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeBinArray {\n        index: bin_array_index,\n    }\n    .data();\n\n    let init_bin_array_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_bin_array_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize Bin Array {bin_array}. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(bin_array)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_bin_array_with_bin_range.rs",
    "content": "use crate::*;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct InitBinArrayWithBinRangeParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Lower bound of the bin range.\n    #[clap(long, allow_negative_numbers = true)]\n    pub lower_bin_id: i32,\n    /// Upper bound of the bin range.\n    #[clap(long, allow_negative_numbers = true)]\n    pub upper_bin_id: i32,\n}\n\npub async fn execute_initialize_bin_array_with_bin_range<C: Deref<Target = impl Signer> + Clone>(\n    params: InitBinArrayWithBinRangeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Vec<Pubkey>> {\n    let InitBinArrayWithBinRangeParams {\n        lb_pair,\n        lower_bin_id,\n        upper_bin_id,\n    } = params;\n\n    let mut bin_arrays_pubkey = vec![];\n\n    let lower_bin_array_idx = BinArray::bin_id_to_bin_array_index(lower_bin_id)?;\n    let upper_bin_array_idx = BinArray::bin_id_to_bin_array_index(upper_bin_id)?;\n\n    for idx in lower_bin_array_idx..=upper_bin_array_idx {\n        let params = InitBinArrayParams {\n            bin_array_index: idx.into(),\n            lb_pair,\n        };\n        let bin_array_pubkey =\n            execute_initialize_bin_array(params, program, transaction_config).await?;\n        bin_arrays_pubkey.push(bin_array_pubkey);\n    }\n\n    Ok(bin_arrays_pubkey)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_bin_array_with_price_range.rs",
    "content": "use crate::*;\nuse instructions::*;\nuse rust_decimal::Decimal;\n\n#[derive(Debug, Parser)]\npub struct InitBinArrayWithPriceRangeParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Lower bound of the price.\n    pub lower_price: f64,\n    /// Upper bound of the price.\n    pub upper_price: f64,\n}\n\npub async fn execute_initialize_bin_array_with_price_range<\n    C: Deref<Target = impl Signer> + Clone,\n>(\n    params: InitBinArrayWithPriceRangeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Vec<Pubkey>> {\n    let InitBinArrayWithPriceRangeParams {\n        lb_pair,\n        lower_price,\n        upper_price,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let lower_bin_id = get_id_from_price(\n        lb_pair_state.bin_step,\n        &Decimal::from_f64_retain(lower_price).context(\"lower price overflow\")?,\n        Rounding::Down,\n    )\n    .context(\"get_id_from_price overflow\")?;\n\n    let upper_bin_id = get_id_from_price(\n        lb_pair_state.bin_step,\n        &Decimal::from_f64_retain(upper_price).context(\"upper price overflow\")?,\n        Rounding::Up,\n    )\n    .context(\"get_id_from_price overflow\")?;\n\n    let params = InitBinArrayWithBinRangeParams {\n        lb_pair,\n        lower_bin_id,\n        upper_bin_id,\n    };\n\n    execute_initialize_bin_array_with_bin_range(params, program, transaction_config).await\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_customizable_permissionless_lb_pair.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct InitCustomizablePermissionlessLbPairParam {\n    /// Token X address\n    #[clap(long)]\n    pub token_mint_x: Pubkey,\n    /// Token Y address\n    #[clap(long)]\n    pub token_mint_y: Pubkey,\n    /// Bin step\n    #[clap(long)]\n    pub bin_step: u16,\n    /// Pool starting price\n    #[clap(long)]\n    pub initial_price: f64,\n    /// Base fee rate\n    #[clap(long)]\n    pub base_fee_bps: u16,\n    /// Pool activation (start trading) type. 0 = Slot based, 1 = Timestamp based\n    #[clap(long)]\n    pub activation_type: u8,\n    /// Indicate whether the launch pool have alpha vault\n    #[clap(long)]\n    pub has_alpha_vault: bool,\n    /// Initial price rounding\n    #[clap(long)]\n    pub selective_rounding: SelectiveRounding,\n    /// Indicate whether the launch pool creator can enable/disable pool\n    #[clap(long)]\n    pub creator_pool_on_off_control: bool,\n    /// Pool activation point. None = Now\n    #[clap(long)]\n    pub activation_point: Option<u64>,\n}\n\npub async fn execute_initialize_customizable_permissionless_lb_pair<\n    C: Deref<Target = impl Signer> + Clone,\n>(\n    params: InitCustomizablePermissionlessLbPairParam,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<Pubkey> {\n    let InitCustomizablePermissionlessLbPairParam {\n        bin_step,\n        token_mint_x,\n        token_mint_y,\n        initial_price,\n        base_fee_bps,\n        activation_type,\n        activation_point,\n        has_alpha_vault,\n        selective_rounding,\n        creator_pool_on_off_control,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[token_mint_x, token_mint_y])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport = price_per_token_to_per_lamport(\n        initial_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let computed_active_id = match selective_rounding {\n        SelectiveRounding::None => get_precise_id_from_price(bin_step, &price_per_lamport)\n            .context(\"fail to get exact bin id for the price\"),\n        SelectiveRounding::Down => get_id_from_price(bin_step, &price_per_lamport, Rounding::Down)\n            .context(\"get_id_from_price overflow\"),\n        SelectiveRounding::Up => get_id_from_price(bin_step, &price_per_lamport, Rounding::Up)\n            .context(\"get_id_from_price overflow\"),\n    }?;\n\n    let (lb_pair, _bump) = derive_customizable_permissionless_lb_pair(token_mint_x, token_mint_y);\n\n    if program.rpc().get_account_data(&lb_pair).await.is_ok() {\n        return Ok(lb_pair);\n    }\n\n    let (reserve_x, _bump) = derive_reserve_pda(token_mint_x, lb_pair);\n    let (reserve_y, _bump) = derive_reserve_pda(token_mint_y, lb_pair);\n    let (oracle, _bump) = derive_oracle_pda(lb_pair);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let user_token_x = get_or_create_ata(\n        program,\n        transaction_config,\n        token_mint_x,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let user_token_y = get_or_create_ata(\n        program,\n        transaction_config,\n        token_mint_y,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let accounts = dlmm::client::accounts::InitializeCustomizablePermissionlessLbPair {\n        lb_pair,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        token_mint_x,\n        token_mint_y,\n        oracle,\n        funder: program.payer(),\n        system_program: solana_sdk::system_program::ID,\n        token_program: token_mint_base_account.owner,\n        event_authority,\n        user_token_x,\n        user_token_y,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let (base_factor, base_fee_power_factor) =\n        compute_base_factor_from_fee_bps(bin_step, base_fee_bps)?;\n\n    assert!(base_fee_power_factor == 0);\n\n    let data = dlmm::client::args::InitializeCustomizablePermissionlessLbPair {\n        params: CustomizableParams {\n            active_id: computed_active_id,\n            bin_step,\n            base_factor,\n            activation_type,\n            activation_point,\n            has_alpha_vault,\n            base_fee_power_factor,\n            creator_pool_on_off_control,\n            padding: [0u8; 62],\n        },\n    }\n    .data();\n\n    let init_pair_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_pair_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize Customizable LB pair {lb_pair}. Signature: {signature:#?}\");\n\n    signature?;\n\n    println!(\"{lb_pair}\");\n\n    Ok(lb_pair)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_customizable_permissionless_lb_pair2.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct InitCustomizablePermissionlessLbPair2Param {\n    /// Token X address\n    #[clap(long)]\n    pub token_mint_x: Pubkey,\n    /// Token Y address\n    #[clap(long)]\n    pub token_mint_y: Pubkey,\n    /// Bin step\n    #[clap(long)]\n    pub bin_step: u16,\n    /// Pool starting price\n    #[clap(long)]\n    pub initial_price: f64,\n    /// Base fee rate\n    #[clap(long)]\n    pub base_fee_bps: u16,\n    /// Pool activation (start trading) type. 0 = Slot based, 1 = Timestamp based\n    #[clap(long)]\n    pub activation_type: u8,\n    /// Indicate whether the launch pool have alpha vault\n    #[clap(long)]\n    pub has_alpha_vault: bool,\n    /// Initial price rounding\n    #[clap(long)]\n    pub selective_rounding: SelectiveRounding,\n    /// Indicate whether the launch pool creator can enable/disable pool\n    #[clap(long)]\n    pub creator_pool_on_off_control: bool,\n    /// Pool activation point. None = Now\n    #[clap(long)]\n    pub activation_point: Option<u64>,\n}\n\npub async fn execute_initialize_customizable_permissionless_lb_pair2<\n    C: Deref<Target = impl Signer> + Clone,\n>(\n    params: InitCustomizablePermissionlessLbPair2Param,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<Pubkey> {\n    let InitCustomizablePermissionlessLbPair2Param {\n        bin_step,\n        token_mint_x,\n        token_mint_y,\n        initial_price,\n        base_fee_bps,\n        activation_type,\n        activation_point,\n        has_alpha_vault,\n        selective_rounding,\n        creator_pool_on_off_control,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[token_mint_x, token_mint_y])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport = price_per_token_to_per_lamport(\n        initial_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let computed_active_id = match selective_rounding {\n        SelectiveRounding::None => get_precise_id_from_price(bin_step, &price_per_lamport)\n            .context(\"fail to get exact bin id for the price\"),\n        SelectiveRounding::Down => get_id_from_price(bin_step, &price_per_lamport, Rounding::Down)\n            .context(\"get_id_from_price overflow\"),\n        SelectiveRounding::Up => get_id_from_price(bin_step, &price_per_lamport, Rounding::Up)\n            .context(\"get_id_from_price overflow\"),\n    }?;\n\n    let (lb_pair, _bump) = derive_customizable_permissionless_lb_pair(token_mint_x, token_mint_y);\n\n    if program.rpc().get_account_data(&lb_pair).await.is_ok() {\n        return Ok(lb_pair);\n    }\n\n    let (reserve_x, _bump) = derive_reserve_pda(token_mint_x, lb_pair);\n    let (reserve_y, _bump) = derive_reserve_pda(token_mint_y, lb_pair);\n    let (oracle, _bump) = derive_oracle_pda(lb_pair);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let user_token_x = get_or_create_ata(\n        program,\n        transaction_config,\n        token_mint_x,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let user_token_y = get_or_create_ata(\n        program,\n        transaction_config,\n        token_mint_y,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let token_badge_x = derive_token_badge_pda(token_mint_x).0;\n    let token_badge_y = derive_token_badge_pda(token_mint_y).0;\n\n    accounts = rpc_client\n        .get_multiple_accounts(&[token_badge_x, token_badge_y])\n        .await?;\n\n    let token_badge_x = accounts[0].take().map(|_| token_badge_x).or(Some(dlmm::ID));\n    let token_badge_y = accounts[1].take().map(|_| token_badge_y).or(Some(dlmm::ID));\n\n    let accounts = dlmm::client::accounts::InitializeCustomizablePermissionlessLbPair2 {\n        lb_pair,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        token_mint_x,\n        token_mint_y,\n        oracle,\n        funder: program.payer(),\n        system_program: solana_sdk::system_program::ID,\n        token_program_x: token_mint_base_account.owner,\n        token_program_y: token_mint_quote_account.owner,\n        token_badge_x,\n        token_badge_y,\n        event_authority,\n        user_token_x,\n        user_token_y,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let (base_factor, base_fee_power_factor) =\n        compute_base_factor_from_fee_bps(bin_step, base_fee_bps)?;\n\n    let data = dlmm::client::args::InitializeCustomizablePermissionlessLbPair2 {\n        params: CustomizableParams {\n            active_id: computed_active_id,\n            bin_step,\n            base_factor,\n            activation_type,\n            activation_point,\n            has_alpha_vault,\n            base_fee_power_factor,\n            creator_pool_on_off_control,\n            padding: [0u8; 62],\n        },\n    }\n    .data();\n\n    let init_pair_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_pair_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize Customizable LB pair {lb_pair}. Signature: {signature:#?}\");\n\n    signature?;\n\n    println!(\"{lb_pair}\");\n\n    Ok(lb_pair)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_lb_pair.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\n\n#[derive(Debug, Parser)]\npub struct InitLbPairParams {\n    /// Preset parameter pubkey. Get the pubkey from list_all_binstep command.\n    pub preset_parameter: Pubkey,\n    /// Token X mint of the liquidity pair. Eg: BTC. This should be the base token.\n    pub token_mint_x: Pubkey,\n    /// Token Y mint of the liquidity pair. Eg: USDC. This should be the quote token.\n    pub token_mint_y: Pubkey,\n    /// The initial price of the liquidity pair. Eg: 24123.12312412 USDC per 1 BTC.\n    pub initial_price: f64,\n}\n\npub async fn execute_initialize_lb_pair<C: Deref<Target = impl Signer> + Clone>(\n    params: InitLbPairParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitLbPairParams {\n        preset_parameter,\n        token_mint_x,\n        token_mint_y,\n        initial_price,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[token_mint_x, token_mint_y])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport = price_per_token_to_per_lamport(\n        initial_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let preset_parameter_state = rpc_client\n        .get_account_and_deserialize(&preset_parameter, |account| {\n            Ok(PresetParameter::try_deserialize(\n                &mut account.data.as_ref(),\n            )?)\n        })\n        .await?;\n\n    let bin_step = preset_parameter_state.bin_step;\n\n    let computed_active_id = get_id_from_price(bin_step, &price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    let (lb_pair, _bump) = derive_lb_pair_pda2(\n        token_mint_x,\n        token_mint_y,\n        preset_parameter_state.bin_step,\n        preset_parameter_state.base_factor,\n    );\n\n    if program.rpc().get_account_data(&lb_pair).await.is_ok() {\n        return Ok(lb_pair);\n    }\n\n    let (reserve_x, _bump) = derive_reserve_pda(token_mint_x, lb_pair);\n    let (reserve_y, _bump) = derive_reserve_pda(token_mint_y, lb_pair);\n    let (oracle, _bump) = derive_oracle_pda(lb_pair);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::InitializeLbPair {\n        lb_pair,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        token_mint_x,\n        token_mint_y,\n        oracle,\n        funder: program.payer(),\n        token_program: token_mint_base_account.owner,\n        preset_parameter,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n        rent: solana_sdk::sysvar::rent::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeLbPair {\n        active_id: computed_active_id,\n        bin_step,\n    }\n    .data();\n\n    let init_pair_ix = Instruction {\n        program_id: dlmm::ID,\n        data,\n        accounts,\n    };\n\n    let request_builder = program.request();\n\n    let signature = request_builder\n        .instruction(init_pair_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize LB pair {lb_pair}. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(lb_pair)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_lb_pair2.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\n\n#[derive(Debug, Parser)]\npub struct InitLbPair2Params {\n    /// Preset parameter pubkey. Get the pubkey from list_all_binstep command.\n    pub preset_parameter: Pubkey,\n    /// Token X mint of the liquidity pair. Eg: BTC. This should be the base token.\n    pub token_mint_x: Pubkey,\n    /// Token Y mint of the liquidity pair. Eg: USDC. This should be the quote token.\n    pub token_mint_y: Pubkey,\n    /// The initial price of the liquidity pair. Eg: 24123.12312412 USDC per 1 BTC.\n    pub initial_price: f64,\n}\n\npub async fn execute_initialize_lb_pair2<C: Deref<Target = impl Signer> + Clone>(\n    params: InitLbPair2Params,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitLbPair2Params {\n        preset_parameter,\n        token_mint_x,\n        token_mint_y,\n        initial_price,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[token_mint_x, token_mint_y])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport = price_per_token_to_per_lamport(\n        initial_price,\n        token_mint_base.decimals,\n        token_mint_quote.decimals,\n    )\n    .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let preset_parameter_state: PresetParameter2 = rpc_client\n        .get_account_and_deserialize(&preset_parameter, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let bin_step = preset_parameter_state.bin_step;\n\n    let computed_active_id = get_id_from_price(bin_step, &price_per_lamport, Rounding::Up)\n        .context(\"get_id_from_price overflow\")?;\n\n    let (lb_pair, _bump) =\n        derive_lb_pair_with_preset_parameter_key(preset_parameter, token_mint_x, token_mint_y);\n\n    if program.rpc().get_account_data(&lb_pair).await.is_ok() {\n        return Ok(lb_pair);\n    }\n\n    let (reserve_x, _bump) = derive_reserve_pda(token_mint_x, lb_pair);\n    let (reserve_y, _bump) = derive_reserve_pda(token_mint_y, lb_pair);\n    let (oracle, _bump) = derive_oracle_pda(lb_pair);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n    let (token_badge_x, _bump) = derive_token_badge_pda(token_mint_x);\n    let (token_badge_y, _bump) = derive_token_badge_pda(token_mint_y);\n\n    let accounts = rpc_client\n        .get_multiple_accounts(&[token_badge_x, token_badge_y])\n        .await?;\n\n    let token_badge_x = accounts[0]\n        .as_ref()\n        .map(|_| token_badge_x)\n        .or(Some(dlmm::ID));\n\n    let token_badge_y = accounts[1]\n        .as_ref()\n        .map(|_| token_badge_y)\n        .or(Some(dlmm::ID));\n\n    let accounts = dlmm::client::accounts::InitializeLbPair2 {\n        lb_pair,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        token_mint_x,\n        token_mint_y,\n        oracle,\n        funder: program.payer(),\n        token_badge_x,\n        token_badge_y,\n        token_program_x: token_mint_base_account.owner,\n        token_program_y: token_mint_quote_account.owner,\n        preset_parameter,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializeLbPair2 {\n        params: InitializeLbPair2Params {\n            active_id: computed_active_id,\n            padding: [0u8; 96],\n        },\n    }\n    .data();\n\n    let init_pair_ix = Instruction {\n        program_id: dlmm::ID,\n        data,\n        accounts,\n    };\n\n    let request_builder = program.request();\n\n    let signature = request_builder\n        .instruction(init_pair_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Initialize LB pair2 {lb_pair}. Signature: {signature:#?}\");\n\n    signature?;\n\n    Ok(lb_pair)\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_position.rs",
    "content": "use std::sync::Arc;\n\nuse crate::*;\n\n#[derive(Debug, Parser)]\npub struct InitPositionParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Lower bound of the bin range.\n    #[clap(long, allow_negative_numbers = true)]\n    pub lower_bin_id: i32,\n    /// Width of the position. Start with 1 until 70.\n    pub width: i32,\n}\n\npub async fn execute_initialize_position<C: Deref<Target = impl Signer> + Clone>(\n    params: InitPositionParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitPositionParams {\n        lb_pair,\n        lower_bin_id,\n        width,\n    } = params;\n\n    let position_keypair = Arc::new(Keypair::new());\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::InitializePosition {\n        lb_pair,\n        payer: program.payer(),\n        position: position_keypair.pubkey(),\n        owner: program.payer(),\n        rent: solana_sdk::sysvar::rent::ID,\n        system_program: solana_sdk::system_program::ID,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let data = dlmm::client::args::InitializePosition {\n        lower_bin_id,\n        width,\n    }\n    .data();\n\n    let init_position_ix = Instruction {\n        program_id: dlmm::ID,\n        data,\n        accounts,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(init_position_ix)\n        .signer(position_keypair.clone())\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\n        \"Initialize position {}. Signature: {signature:#?}\",\n        position_keypair.pubkey()\n    );\n\n    signature?;\n\n    Ok(position_keypair.pubkey())\n}\n"
  },
  {
    "path": "cli/src/instructions/initialize_position_with_price_range.rs",
    "content": "use crate::*;\nuse instructions::*;\nuse rust_decimal::Decimal;\n\n#[derive(Debug, Parser)]\npub struct InitPositionWithPriceRangeParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Lower bound of the price.\n    pub lower_price: f64,\n    /// Width of the position. Start with 1 until 70.\n    pub width: i32,\n}\n\npub async fn execute_initialize_position_with_price_range<\n    C: Deref<Target = impl Signer> + Clone,\n>(\n    params: InitPositionWithPriceRangeParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<Pubkey> {\n    let InitPositionWithPriceRangeParams {\n        lb_pair,\n        lower_price,\n        width,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let lower_bin_id = get_id_from_price(\n        lb_pair_state.bin_step,\n        &Decimal::from_f64_retain(lower_price).context(\"lower price overflow\")?,\n        Rounding::Down,\n    )\n    .context(\"get_id_from_price overflow\")?;\n\n    let params = InitPositionParams {\n        lb_pair,\n        lower_bin_id,\n        width,\n    };\n\n    execute_initialize_position(params, program, transaction_config).await\n}\n"
  },
  {
    "path": "cli/src/instructions/list_all_binstep.rs",
    "content": "use anchor_lang::Discriminator;\nuse solana_client::{\n    rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},\n    rpc_filter::{Memcmp, RpcFilterType},\n};\n\nuse crate::*;\n\npub async fn execute_list_all_bin_step<C: Deref<Target = impl Signer> + Clone>(\n    program: &Program<C>,\n) -> Result<()> {\n    let rpc_client = program.rpc();\n\n    let account_config = RpcAccountInfoConfig {\n        encoding: Some(UiAccountEncoding::Base64),\n        data_slice: Some(UiDataSliceConfig {\n            offset: 0,\n            length: 0,\n        }),\n        ..Default::default()\n    };\n\n    let preset_parameter_keys = rpc_client\n        .get_program_accounts_with_config(\n            &dlmm::ID,\n            RpcProgramAccountsConfig {\n                filters: Some(vec![RpcFilterType::Memcmp(Memcmp::new_base58_encoded(\n                    0,\n                    &PresetParameter::DISCRIMINATOR,\n                ))]),\n                account_config: account_config.clone(),\n                ..Default::default()\n            },\n        )\n        .await?\n        .into_iter()\n        .map(|(key, _)| key)\n        .collect::<Vec<_>>();\n\n    let preset_parameter_v2_keys = rpc_client\n        .get_program_accounts_with_config(\n            &dlmm::ID,\n            RpcProgramAccountsConfig {\n                filters: Some(vec![RpcFilterType::Memcmp(Memcmp::new_base58_encoded(\n                    0,\n                    &PresetParameter2::DISCRIMINATOR,\n                ))]),\n                account_config,\n                ..Default::default()\n            },\n        )\n        .await?\n        .into_iter()\n        .map(|(key, _)| key)\n        .collect::<Vec<_>>();\n\n    let all_versioned_keys = [preset_parameter_keys, preset_parameter_v2_keys].concat();\n\n    for keys in all_versioned_keys.chunks(100) {\n        let accounts = rpc_client.get_multiple_accounts(keys).await?;\n        for (key, account) in keys.iter().zip(accounts) {\n            if let Some(account) = account {\n                let mut disc = [0u8; 8];\n                disc.copy_from_slice(&account.data[..8]);\n\n                let (bin_step, base_factor, base_fee_power_factor) = if disc\n                    == PresetParameter::DISCRIMINATOR\n                {\n                    let state = PresetParameter::try_deserialize(&mut account.data.as_ref())?;\n                    (state.bin_step, state.base_factor, 0)\n                } else if disc == PresetParameter2::DISCRIMINATOR {\n                    let state: PresetParameter2 = bytemuck::pod_read_unaligned(&account.data[8..]);\n                    (\n                        state.bin_step,\n                        state.base_factor,\n                        state.base_fee_power_factor,\n                    )\n                } else {\n                    continue;\n                };\n\n                let base_fee = (u128::from(bin_step)\n                    * u128::from(base_factor).pow(base_fee_power_factor.into())\n                    * 1000) as f64\n                    / FEE_PRECISION as f64;\n\n                println!(\n                    \"Preset Pubkey: {}. Bin step {}. Base fee: {}%\",\n                    key, bin_step, base_fee\n                );\n            }\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/mod.rs",
    "content": "pub mod add_liquidity;\npub use add_liquidity::*;\n\npub mod claim_fee;\npub use claim_fee::*;\n\npub mod claim_reward;\npub use claim_reward::*;\n\npub mod close_position;\npub use close_position::*;\n\npub mod fund_reward;\npub use fund_reward::*;\n\npub mod get_all_positions;\npub use get_all_positions::*;\n\npub mod increase_oracle_length;\npub use increase_oracle_length::*;\n\npub mod initialize_bin_array;\npub use initialize_bin_array::*;\n\npub mod initialize_bin_array_with_bin_range;\npub use initialize_bin_array_with_bin_range::*;\n\npub mod initialize_bin_array_with_price_range;\npub use initialize_bin_array_with_price_range::*;\n\npub mod initialize_customizable_permissionless_lb_pair2;\npub use initialize_customizable_permissionless_lb_pair2::*;\n\npub mod initialize_lb_pair2;\npub use initialize_lb_pair2::*;\n\npub mod initialize_position;\npub use initialize_position::*;\n\npub mod initialize_position_with_price_range;\npub use initialize_position_with_price_range::*;\n\npub mod list_all_binstep;\npub use list_all_binstep::*;\n\npub mod remove_liquidity;\npub use remove_liquidity::*;\n\npub mod show_pair;\npub use show_pair::*;\n\npub mod swap_exact_in;\npub use swap_exact_in::*;\n\npub mod swap_exact_out;\npub use swap_exact_out::*;\n\npub mod swap_with_price_impact;\npub use swap_with_price_impact::*;\n\nmod utils;\npub use utils::*;\n\npub mod show_position;\npub use show_position::*;\n\npub mod show_preset_parameters;\npub use show_preset_parameters::*;\n\npub mod set_pair_status_permissionless;\n\npub mod admin;\npub use admin::*;\n\npub mod ilm;\npub use ilm::*;\n\npub mod initialize_customizable_permissionless_lb_pair;\npub use initialize_customizable_permissionless_lb_pair::*;\n\npub mod initialize_lb_pair;\npub use initialize_lb_pair::*;\n\npub mod sync_price;\npub use sync_price::*;\n"
  },
  {
    "path": "cli/src/instructions/remove_liquidity.rs",
    "content": "use crate::*;\nuse instructions::*;\n\n#[derive(Debug, Parser)]\npub struct RemoveLiquidityParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Bin liquidity information to be remove. \"<BIN_ID,BPS_TO_REMOVE, BIN_ID,BPS_TO_REMOVE, ...>\" where\n    /// BIN_ID = bin id to withdraw\n    /// BPS_TO_REMOVE = Percentage of position owned share to be removed. Maximum is 1.0f, which equivalent to 100%.\n    #[clap(long, value_parser = parse_bin_liquidity_removal, value_delimiter = ' ', allow_hyphen_values = true)]\n    pub bin_liquidity_removal: Vec<(i32, f64)>,\n    /// Position to be withdraw.\n    pub position: Pubkey,\n}\n\npub async fn execute_remove_liquidity<C: Deref<Target = impl Signer> + Clone>(\n    params: RemoveLiquidityParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let RemoveLiquidityParams {\n        lb_pair,\n        position,\n        mut bin_liquidity_removal,\n    } = params;\n\n    bin_liquidity_removal.sort_by(|a, b| a.0.cmp(&b.0));\n\n    let rpc_client = program.rpc();\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[lb_pair, position])\n        .await?;\n\n    let lb_pair_account = accounts[0].take().context(\"lb_pair not found\")?;\n    let position_account = accounts[1].take().context(\"position not found\")?;\n\n    let lb_pair_state: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n    let position_state: PositionV2 = bytemuck::pod_read_unaligned(&position_account.data[8..]);\n\n    let min_bin_id = bin_liquidity_removal\n        .first()\n        .map(|(bin_id, _)| *bin_id)\n        .context(\"bin_liquidity_removal is empty\")?;\n\n    let max_bin_id = bin_liquidity_removal\n        .last()\n        .map(|(bin_id, _)| *bin_id)\n        .context(\"bin_liquidity_removal is empty\")?;\n\n    let bin_arrays_account_meta =\n        position_state.get_bin_array_accounts_meta_coverage_by_chunk(min_bin_id, max_bin_id)?;\n\n    let user_token_x = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_x_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let user_token_y = get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_y_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n    let bin_array_bitmap_extension = rpc_client\n        .get_account(&bin_array_bitmap_extension)\n        .await\n        .map(|_| bin_array_bitmap_extension)\n        .ok()\n        .or(Some(dlmm::ID));\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    };\n\n    remaining_accounts.extend(bin_arrays_account_meta);\n\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let main_accounts = dlmm::client::accounts::RemoveLiquidity2 {\n        position,\n        lb_pair,\n        bin_array_bitmap_extension,\n        user_token_x,\n        user_token_y,\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_x_program,\n        token_y_mint: lb_pair_state.token_y_mint,\n        token_y_program,\n        sender: program.payer(),\n        memo_program: spl_memo::ID,\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let bin_liquidity_removal = bin_liquidity_removal\n        .into_iter()\n        .map(|(bin_id, bps)| BinLiquidityReduction {\n            bin_id,\n            bps_to_remove: (bps * BASIS_POINT_MAX as f64) as u16,\n        })\n        .collect::<Vec<BinLiquidityReduction>>();\n\n    let data = dlmm::client::args::RemoveLiquidity2 {\n        bin_liquidity_removal,\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let remove_liquidity_ix = Instruction {\n        program_id: dlmm::ID,\n        data,\n        accounts,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(remove_liquidity_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Remove Liquidity. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/set_pair_status.rs",
    "content": "use std::ops::Deref;\n\nuse anchor_client::solana_client::rpc_config::RpcSendTransactionConfig;\nuse anchor_client::{solana_sdk::pubkey::Pubkey, solana_sdk::signer::Signer, Program};\n\nuse anchor_lang::solana_program::instruction::Instruction;\nuse anchor_lang::{InstructionData, ToAccountMetas};\nuse anyhow::*;\n\n#[derive(Debug)]\npub struct SetPairStatusParam {\n    pub lb_pair: Pubkey,\n    pub pair_status: u8,\n}\n\npub async fn set_pair_status<C: Deref<Target = impl Signer> + Clone>(\n    params: SetPairStatusParam,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetPairStatusParam {\n        lb_pair,\n        pair_status,\n    } = params;\n\n    let accounts = lb_clmm::accounts::SetPairStatus {\n        admin: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let ix_data = lb_clmm::instruction::SetPairStatus {\n        status: pair_status,\n    }\n    .data();\n\n    let set_pair_status_ix = Instruction {\n        accounts,\n        data: ix_data,\n        program_id: lb_clmm::ID,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(set_pair_status_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Set pair status successfully. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/set_pair_status_permissionless.rs",
    "content": "use crate::*;\n\n#[derive(Debug, Parser)]\npub struct SetPairStatusPermissionlessParams {\n    #[clap(long)]\n    pub lb_pair: Pubkey,\n    #[clap(long)]\n    pub enable: bool,\n}\n\npub async fn execute_set_pair_status_permissionless<C: Deref<Target = impl Signer> + Clone>(\n    params: SetPairStatusPermissionlessParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SetPairStatusPermissionlessParams { lb_pair, enable } = params;\n\n    let accounts = dlmm::client::accounts::SetPairStatusPermissionless {\n        creator: program.payer(),\n        lb_pair,\n    }\n    .to_account_metas(None);\n\n    let status = if enable { 1 } else { 0 };\n\n    let data = dlmm::client::args::SetPairStatusPermissionless { status }.data();\n\n    let set_pair_status_permissionless_ix = Instruction {\n        accounts,\n        data,\n        program_id: dlmm::ID,\n    };\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(set_pair_status_permissionless_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\n        \"Set pair status permissionless. Signature: {:#?}\",\n        signature\n    );\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/show_pair.rs",
    "content": "use crate::*;\nuse anchor_lang::AccountDeserialize;\nuse anchor_spl::token_interface::Mint;\nuse rust_decimal::prelude::*;\nuse rust_decimal::Decimal;\nuse solana_client::{\n    rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},\n    rpc_filter::{Memcmp, RpcFilterType},\n};\n\nfn fee_rate_to_fee_pct(fee_rate: u128) -> Option<Decimal> {\n    let fee_rate = Decimal::from_u128(fee_rate)?.checked_div(Decimal::from(FEE_PRECISION))?;\n    fee_rate.checked_mul(Decimal::ONE_HUNDRED)\n}\n\n#[derive(Debug, Parser)]\npub struct ShowPairParams {\n    pub lb_pair: Pubkey,\n}\n\npub async fn execute_show_pair<C: Deref<Target = impl Signer> + Clone>(\n    params: ShowPairParams,\n    program: &Program<C>,\n) -> Result<()> {\n    let ShowPairParams { lb_pair } = params;\n    let rpc_client = program.rpc();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let lb_pair_filter = RpcFilterType::Memcmp(Memcmp::new_base58_encoded(16, &lb_pair.to_bytes()));\n    let account_config = RpcAccountInfoConfig {\n        encoding: Some(UiAccountEncoding::Base64),\n        ..Default::default()\n    };\n    let config = RpcProgramAccountsConfig {\n        filters: Some(vec![lb_pair_filter]),\n        account_config,\n        ..Default::default()\n    };\n\n    let mut bin_arrays: Vec<(Pubkey, BinArray)> = rpc_client\n        .get_program_accounts_with_config(&dlmm::ID, config)\n        .await?\n        .into_iter()\n        .filter_map(|(key, account)| {\n            let bin_array = bytemuck::pod_read_unaligned(&account.data[8..]);\n            Some((key, bin_array))\n        })\n        .collect();\n\n    bin_arrays.sort_by(|a, b| a.1.index.cmp(&b.1.index));\n\n    println!(\"{:#?}\", lb_pair_state);\n\n    for (_, bin_array) in bin_arrays {\n        let (mut lower_bin_id, _) =\n            BinArray::get_bin_array_lower_upper_bin_id(bin_array.index as i32)?;\n        for bin in bin_array.bins.iter() {\n            let total_amount = bin.amount_x + bin.amount_y;\n            if total_amount > 0 {\n                println!(\n                    \"Bin: {}, X: {}, Y: {}\",\n                    lower_bin_id, bin.amount_x, bin.amount_y\n                );\n            }\n            lower_bin_id += 1;\n        }\n    }\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[lb_pair_state.token_x_mint, lb_pair_state.token_y_mint])\n        .await?;\n\n    let token_x_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_y_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n\n    let x_mint = Mint::try_deserialize(&mut token_x_account.data.as_ref())?;\n    let y_mint = Mint::try_deserialize(&mut token_y_account.data.as_ref())?;\n\n    let q64x64_price = get_price_from_id(lb_pair_state.active_id, lb_pair_state.bin_step)?;\n    let decimal_price_per_lamport =\n        q64x64_price_to_decimal(q64x64_price).context(\"q64x64 price to decimal overflow\")?;\n\n    let token_price = price_per_lamport_to_price_per_token(\n        decimal_price_per_lamport\n            .to_f64()\n            .context(\"Decimal conversion to f64 fail\")?,\n        x_mint.decimals,\n        y_mint.decimals,\n    )\n    .context(\"price_per_lamport_to_price_per_token overflow\")?;\n\n    let base_fee_rate = fee_rate_to_fee_pct(lb_pair_state.get_total_fee()?)\n        .context(\"get_total_fee convert to percentage overflow\")?;\n    let variable_fee_rate = fee_rate_to_fee_pct(lb_pair_state.get_variable_fee()?)\n        .context(\"get_total_fee convert to percentage overflow\")?;\n    let current_fee_rate = fee_rate_to_fee_pct(lb_pair_state.get_total_fee()?)\n        .context(\"get_total_fee convert to percentage overflow\")?;\n\n    println!(\"Current price {}\", token_price);\n    println!(\"Base fee rate {}%\", base_fee_rate);\n    println!(\"Volatile fee rate {}%\", variable_fee_rate);\n    println!(\"Current fee rate {}%\", current_fee_rate);\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/show_position.rs",
    "content": "use anchor_lang::Discriminator;\n\nuse crate::*;\n\n#[derive(Debug, Parser)]\npub struct ShowPositionParams {\n    pub position: Pubkey,\n}\n\npub async fn execute_show_position<C: Deref<Target = impl Signer> + Clone>(\n    params: ShowPositionParams,\n    program: &Program<C>,\n) -> Result<()> {\n    let ShowPositionParams { position } = params;\n\n    let rpc_client = program.rpc();\n    let position_account = rpc_client.get_account(&position).await?;\n\n    let mut disc = [0u8; 8];\n    disc.copy_from_slice(&position_account.data[..8]);\n\n    if disc == Position::DISCRIMINATOR {\n        let position_state: Position = bytemuck::pod_read_unaligned(&position_account.data[8..]);\n        println!(\"{:#?}\", position_state);\n    } else if disc == PositionV2::DISCRIMINATOR {\n        let position_state: PositionV2 = bytemuck::pod_read_unaligned(&position_account.data[8..]);\n        println!(\"{:#?}\", position_state);\n    } else {\n        bail!(\"Not a valid position account\");\n    };\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/show_preset_parameters.rs",
    "content": "use anchor_lang::Discriminator;\n\nuse crate::*;\n\n#[derive(Debug, Parser)]\npub struct ShowPresetAccountParams {\n    pub preset_parameter: Pubkey,\n}\n\npub async fn execute_show_preset_parameters<C: Deref<Target = impl Signer> + Clone>(\n    params: ShowPresetAccountParams,\n    program: &Program<C>,\n) -> Result<()> {\n    let ShowPresetAccountParams { preset_parameter } = params;\n\n    let rpc_client = program.rpc();\n    let account = rpc_client.get_account(&preset_parameter).await?;\n\n    let mut disc = [0u8; 8];\n    disc.copy_from_slice(&account.data[..8]);\n\n    if disc == PresetParameter::DISCRIMINATOR {\n        let preset_param_state = PresetParameter::try_deserialize(&mut account.data.as_ref())?;\n        println!(\"{:#?}\", preset_param_state);\n    } else if disc == PresetParameter2::DISCRIMINATOR {\n        let preset_param_state: PresetParameter2 = bytemuck::pod_read_unaligned(&account.data[8..]);\n        println!(\"{:#?}\", preset_param_state);\n    } else {\n        bail!(\"Not a valid preset parameter account\");\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/simulate_swap_demand.rs",
    "content": "use crate::instructions::utils::get_or_create_ata;\nuse crate::swap;\nuse crate::SwapExactInParameters;\nuse anchor_client::solana_client::rpc_config::RpcSendTransactionConfig;\nuse anchor_client::solana_sdk::instruction::Instruction;\nuse anchor_client::{solana_sdk::pubkey::Pubkey, solana_sdk::signer::Signer, Program};\nuse anchor_spl::token::Mint;\nuse anyhow::*;\nuse lb_clmm::state::lb_pair::LbPair;\nuse rand::Rng;\nuse std::ops::Deref;\nuse std::result::Result::Ok;\n#[derive(Debug)]\npub struct SimulateSwapDemandParameters {\n    pub lb_pair: Pubkey,\n    pub x_amount: f64, // ex: 10 jup\n    pub y_amount: f64, // ex: 1k jup\n    pub side_ratio: u64,\n}\n\npub async fn simulate_swap_demand<C: Deref<Target = impl Signer> + Clone>(\n    params: SimulateSwapDemandParameters,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let SimulateSwapDemandParameters {\n        lb_pair,\n        x_amount,\n        y_amount,\n        side_ratio,\n    } = params;\n\n    let lb_pair_state: LbPair = program.account(lb_pair).await?;\n    let token_mint_base: Mint = program.account(lb_pair_state.token_x_mint).await?;\n    let token_mint_quote: Mint = program.account(lb_pair_state.token_y_mint).await?;\n\n    get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_x_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n    get_or_create_ata(\n        program,\n        transaction_config,\n        lb_pair_state.token_y_mint,\n        program.payer(),\n        compute_unit_price.clone(),\n    )\n    .await?;\n\n    // random amount\n    let mut rng = rand::thread_rng();\n    loop {\n        let side = rng.gen_range(0..side_ratio);\n        if side == 0 {\n            // sell side\n            println!(\"try to sell {x_amount} jup\");\n            let amount_x = x_amount * (10u64.pow(token_mint_base.decimals as u32) as f64);\n            let params = SwapExactInParameters {\n                amount_in: amount_x.round() as u64,\n                lb_pair,\n                swap_for_y: true,\n            };\n            match swap(params, program, transaction_config).await {\n                Ok(_) => {}\n                Err(err) => {\n                    println!(\"{err}\");\n                }\n            }\n        } else {\n            // buy side\n            println!(\"try to buy with {y_amount} usd\");\n            let amount_y = y_amount * (10u64.pow(token_mint_quote.decimals as u32) as f64);\n\n            let params = SwapExactInParameters {\n                amount_in: amount_y.round() as u64,\n                lb_pair,\n                swap_for_y: false,\n            };\n            match swap(params, program, transaction_config).await {\n                Ok(_) => {}\n                Err(err) => {\n                    println!(\"{err}\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "cli/src/instructions/swap_exact_in.rs",
    "content": "use crate::*;\nuse anchor_spl::associated_token::get_associated_token_address_with_program_id;\n\n#[derive(Debug, Parser)]\npub struct SwapExactInParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Amount of token to be sell.\n    pub amount_in: u64,\n    /// Buy direction. true = buy token Y, false = buy token X.\n    #[clap(long)]\n    pub swap_for_y: bool,\n}\n\npub async fn execute_swap<C: Deref<Target = impl Signer> + Clone>(\n    params: SwapExactInParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SwapExactInParams {\n        amount_in,\n        lb_pair,\n        swap_for_y,\n    } = params;\n\n    let rpc_client = program.rpc();\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let (user_token_in, user_token_out) = if swap_for_y {\n        (\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_x_mint,\n                &token_x_program,\n            ),\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_y_mint,\n                &token_y_program,\n            ),\n        )\n    } else {\n        (\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_y_mint,\n                &token_y_program,\n            ),\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_x_mint,\n                &token_x_program,\n            ),\n        )\n    };\n\n    let (bitmap_extension_key, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let bitmap_extension = rpc_client\n        .get_account_and_deserialize(&bitmap_extension_key, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await\n        .ok();\n\n    let bin_arrays_for_swap = get_bin_array_pubkeys_for_swap(\n        lb_pair,\n        &lb_pair_state,\n        bitmap_extension.as_ref(),\n        swap_for_y,\n        3,\n    )?;\n\n    let SwapQuoteAccounts {\n        lb_pair_state,\n        clock,\n        mint_x_account,\n        mint_y_account,\n        bin_arrays,\n        bin_array_keys,\n    } = fetch_quote_required_accounts(&rpc_client, lb_pair, &lb_pair_state, bin_arrays_for_swap)\n        .await?;\n\n    let quote = quote_exact_in(\n        lb_pair,\n        &lb_pair_state,\n        amount_in,\n        swap_for_y,\n        bin_arrays,\n        bitmap_extension.as_ref(),\n        &clock,\n        &mint_x_account,\n        &mint_y_account,\n    )?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::Swap2 {\n        lb_pair,\n        bin_array_bitmap_extension: bitmap_extension\n            .map(|_| bitmap_extension_key)\n            .or(Some(dlmm::ID)),\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        token_x_program,\n        token_y_program,\n        user: program.payer(),\n        user_token_in,\n        user_token_out,\n        oracle: lb_pair_state.oracle,\n        host_fee_in: Some(dlmm::ID),\n        event_authority,\n        program: dlmm::ID,\n        memo_program: spl_memo::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    }\n\n    remaining_accounts.extend(\n        bin_array_keys\n            .into_iter()\n            .map(|key| AccountMeta::new(key, false)),\n    );\n\n    // 100 bps slippage\n    let min_amount_out = quote.amount_out * 9900 / BASIS_POINT_MAX as u64;\n\n    let data = dlmm::client::args::Swap2 {\n        amount_in,\n        min_amount_out,\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let swap_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(swap_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Swap. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/swap_exact_out.rs",
    "content": "use crate::*;\nuse anchor_spl::associated_token::get_associated_token_address;\n\n#[derive(Debug, Parser)]\npub struct SwapExactOutParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Amount of token to be buy.\n    pub amount_out: u64,\n    /// Buy direction. true = buy token Y, false = buy token X.\n    #[clap(long)]\n    pub swap_for_y: bool,\n}\n\npub async fn execute_swap_exact_out<C: Deref<Target = impl Signer> + Clone>(\n    params: SwapExactOutParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SwapExactOutParams {\n        amount_out,\n        lb_pair,\n        swap_for_y,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let (user_token_in, user_token_out) = if swap_for_y {\n        (\n            get_associated_token_address(&program.payer(), &lb_pair_state.token_x_mint),\n            get_associated_token_address(&program.payer(), &lb_pair_state.token_y_mint),\n        )\n    } else {\n        (\n            get_associated_token_address(&program.payer(), &lb_pair_state.token_y_mint),\n            get_associated_token_address(&program.payer(), &lb_pair_state.token_x_mint),\n        )\n    };\n\n    let (bitmap_extension_key, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let bitmap_extension = rpc_client\n        .get_account_and_deserialize(&bitmap_extension_key, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await\n        .ok();\n\n    let bin_arrays_for_swap = get_bin_array_pubkeys_for_swap(\n        lb_pair,\n        &lb_pair_state,\n        bitmap_extension.as_ref(),\n        swap_for_y,\n        3,\n    )?;\n\n    let SwapQuoteAccounts {\n        lb_pair_state,\n        clock,\n        mint_x_account,\n        mint_y_account,\n        bin_arrays,\n        bin_array_keys,\n    } = fetch_quote_required_accounts(&rpc_client, lb_pair, &lb_pair_state, bin_arrays_for_swap)\n        .await?;\n\n    let quote = quote_exact_out(\n        lb_pair,\n        &lb_pair_state,\n        amount_out,\n        swap_for_y,\n        bin_arrays,\n        bitmap_extension.as_ref(),\n        &clock,\n        &mint_x_account,\n        &mint_y_account,\n    )?;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::SwapExactOut2 {\n        lb_pair,\n        bin_array_bitmap_extension: bitmap_extension\n            .map(|_| bitmap_extension_key)\n            .or(Some(dlmm::ID)),\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        token_x_program,\n        token_y_program,\n        user: program.payer(),\n        user_token_in,\n        user_token_out,\n        oracle: lb_pair_state.oracle,\n        host_fee_in: Some(dlmm::ID),\n        event_authority,\n        program: dlmm::ID,\n        memo_program: spl_memo::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    }\n\n    remaining_accounts.extend(\n        bin_array_keys\n            .into_iter()\n            .map(|key| AccountMeta::new(key, false)),\n    );\n\n    let in_amount = quote.amount_in + quote.fee;\n    // 100 bps slippage\n    let max_in_amount = in_amount * 10100 / BASIS_POINT_MAX as u64;\n\n    let data = dlmm::client::args::SwapExactOut2 {\n        out_amount: amount_out,\n        max_in_amount,\n        remaining_accounts_info,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let swap_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(swap_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Swap. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/swap_with_price_impact.rs",
    "content": "use crate::*;\nuse anchor_spl::associated_token::get_associated_token_address_with_program_id;\n\n#[derive(Debug, Parser)]\npub struct SwapWithPriceImpactParams {\n    /// Address of the liquidity pair.\n    pub lb_pair: Pubkey,\n    /// Amount of token to be sell.\n    pub amount_in: u64,\n    /// Buy direction. true = buy token Y, false = buy token X.\n    #[clap(long)]\n    pub swap_for_y: bool,\n    /// Allowed price impact in bps.\n    pub price_impact_bps: u16,\n}\n\npub async fn execute_swap_with_price_impact<C: Deref<Target = impl Signer> + Clone>(\n    params: SwapWithPriceImpactParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n) -> Result<()> {\n    let SwapWithPriceImpactParams {\n        amount_in,\n        lb_pair,\n        swap_for_y,\n        price_impact_bps,\n    } = params;\n\n    let rpc_client = program.rpc();\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n    let (user_token_in, user_token_out) = if swap_for_y {\n        (\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_x_mint,\n                &token_x_program,\n            ),\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_y_mint,\n                &token_y_program,\n            ),\n        )\n    } else {\n        (\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_y_mint,\n                &token_y_program,\n            ),\n            get_associated_token_address_with_program_id(\n                &program.payer(),\n                &lb_pair_state.token_x_mint,\n                &token_x_program,\n            ),\n        )\n    };\n\n    let (bitmap_extension_key, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let bitmap_extension = rpc_client\n        .get_account_and_deserialize(&bitmap_extension_key, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await\n        .ok();\n\n    let bin_arrays_for_swap = get_bin_array_pubkeys_for_swap(\n        lb_pair,\n        &lb_pair_state,\n        bitmap_extension.as_ref(),\n        swap_for_y,\n        3,\n    )?;\n\n    let SwapQuoteAccounts {\n        lb_pair_state,\n        clock,\n        mint_x_account,\n        mint_y_account,\n        bin_arrays,\n        bin_array_keys,\n    } = fetch_quote_required_accounts(&rpc_client, lb_pair, &lb_pair_state, bin_arrays_for_swap)\n        .await?;\n\n    let quote = quote_exact_in(\n        lb_pair,\n        &lb_pair_state,\n        amount_in,\n        swap_for_y,\n        bin_arrays,\n        bitmap_extension.as_ref(),\n        &clock,\n        &mint_x_account,\n        &mint_y_account,\n    )?;\n\n    println!(\"{:#?}\", quote);\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let main_accounts = dlmm::client::accounts::SwapWithPriceImpact2 {\n        lb_pair,\n        bin_array_bitmap_extension: bitmap_extension\n            .map(|_| bitmap_extension_key)\n            .or(Some(dlmm::ID)),\n        reserve_x: lb_pair_state.reserve_x,\n        reserve_y: lb_pair_state.reserve_y,\n        token_x_mint: lb_pair_state.token_x_mint,\n        token_y_mint: lb_pair_state.token_y_mint,\n        token_x_program,\n        token_y_program,\n        user: program.payer(),\n        user_token_in,\n        user_token_out,\n        oracle: lb_pair_state.oracle,\n        host_fee_in: Some(dlmm::ID),\n        event_authority,\n        program: dlmm::ID,\n        memo_program: spl_memo::ID,\n    }\n    .to_account_metas(None);\n\n    let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n    let mut remaining_accounts = vec![];\n\n    if let Some((slices, transfer_hook_remaining_accounts)) =\n        get_potential_token_2022_related_ix_data_and_accounts(\n            &lb_pair_state,\n            program.rpc(),\n            ActionType::Liquidity,\n        )\n        .await?\n    {\n        remaining_accounts_info.slices = slices;\n        remaining_accounts.extend(transfer_hook_remaining_accounts);\n    }\n\n    remaining_accounts.extend(\n        bin_array_keys\n            .into_iter()\n            .map(|key| AccountMeta::new(key, false)),\n    );\n\n    let data = dlmm::client::args::SwapWithPriceImpact2 {\n        amount_in,\n        active_id: Some(lb_pair_state.active_id),\n        remaining_accounts_info,\n        max_price_impact_bps: price_impact_bps,\n    }\n    .data();\n\n    let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n    let swap_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data,\n    };\n\n    let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n    let request_builder = program.request();\n    let signature = request_builder\n        .instruction(compute_budget_ix)\n        .instruction(swap_ix)\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n\n    println!(\"Swap. Signature: {:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/sync_price.rs",
    "content": "use crate::*;\nuse anchor_spl::token_interface::Mint;\n\n#[derive(Debug, Parser)]\npub struct SyncPriceParams {\n    pub lb_pair: Pubkey,\n    pub price: f64,\n}\n\npub async fn execute_sync_price<C: Deref<Target = impl Signer> + Clone>(\n    params: SyncPriceParams,\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    compute_unit_price: Option<Instruction>,\n) -> Result<()> {\n    let SyncPriceParams { lb_pair, price } = params;\n\n    let rpc_client = program.rpc();\n\n    let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n    let lb_pair_state: LbPair = rpc_client\n        .get_account_and_deserialize(&lb_pair, |account| {\n            Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n        })\n        .await?;\n\n    let mut accounts = rpc_client\n        .get_multiple_accounts(&[\n            lb_pair_state.token_x_mint,\n            lb_pair_state.token_y_mint,\n            bin_array_bitmap_extension,\n        ])\n        .await?;\n\n    let token_mint_base_account = accounts[0].take().context(\"token_mint_base not found\")?;\n    let token_mint_quote_account = accounts[1].take().context(\"token_mint_quote not found\")?;\n    let bin_array_bitmap_extension_account = accounts[2].take();\n\n    let token_mint_base = Mint::try_deserialize(&mut token_mint_base_account.data.as_ref())?;\n    let token_mint_quote = Mint::try_deserialize(&mut token_mint_quote_account.data.as_ref())?;\n\n    let price_per_lamport =\n        price_per_token_to_per_lamport(price, token_mint_base.decimals, token_mint_quote.decimals)\n            .context(\"price_per_token_to_per_lamport overflow\")?;\n\n    let computed_active_id =\n        get_id_from_price(lb_pair_state.bin_step, &price_per_lamport, Rounding::Up)\n            .context(\"get_id_from_price overflow\")?;\n\n    let ix_data = dlmm::client::args::GoToABin {\n        bin_id: computed_active_id,\n    }\n    .data();\n\n    let from_bin_array_idx = BinArray::bin_id_to_bin_array_index(lb_pair_state.active_id)?;\n    let to_bin_array_idx = BinArray::bin_id_to_bin_array_index(computed_active_id)?;\n\n    let (from_bin_array, _bump) = derive_bin_array_pda(lb_pair, from_bin_array_idx.into());\n    let (to_bin_array, _bump) = derive_bin_array_pda(lb_pair, to_bin_array_idx.into());\n\n    accounts = rpc_client\n        .get_multiple_accounts(&[from_bin_array, to_bin_array])\n        .await?;\n\n    let from_bin_array_account = accounts[0].take();\n    let to_bin_array_account = accounts[1].take();\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let accounts = dlmm::client::accounts::GoToABin {\n        lb_pair,\n        bin_array_bitmap_extension: bin_array_bitmap_extension_account\n            .map(|_| bin_array_bitmap_extension)\n            .or(Some(dlmm::ID)),\n        from_bin_array: from_bin_array_account\n            .map(|_| from_bin_array)\n            .or(Some(dlmm::ID)),\n        to_bin_array: to_bin_array_account\n            .map(|_| to_bin_array)\n            .or(Some(dlmm::ID)),\n        event_authority,\n        program: dlmm::ID,\n    }\n    .to_account_metas(None);\n\n    let ix = Instruction {\n        program_id: dlmm::ID,\n        accounts,\n        data: ix_data,\n    };\n\n    let mut ixs = vec![];\n\n    if let Some(compute_unit_price_ix) = compute_unit_price {\n        ixs.push(compute_unit_price_ix);\n    }\n\n    ixs.push(ix);\n\n    let builder = program.request();\n    let builder = ixs\n        .into_iter()\n        .fold(builder, |builder, ix| builder.instruction(ix));\n\n    let signature = builder\n        .send_with_spinner_and_config(transaction_config)\n        .await;\n    println!(\"{:#?}\", signature);\n\n    signature?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/instructions/utils.rs",
    "content": "use std::collections::HashMap;\n\nuse crate::*;\nuse anchor_client::solana_client::rpc_client::RpcClient as BlockingRpcClient;\nuse anchor_client::{\n    solana_client::nonblocking::rpc_client::RpcClient, solana_sdk::account::Account,\n};\nuse anchor_spl::{\n    associated_token::get_associated_token_address_with_program_id,\n    token::spl_token,\n    token_2022::spl_token_2022::extension::{transfer_hook, StateWithExtensions},\n};\nuse num_integer::Integer;\nuse solana_sdk::program_pack::Pack;\nuse solana_sdk::sysvar::clock::Clock;\nuse spl_associated_token_account::instruction::create_associated_token_account_idempotent;\nuse spl_transfer_hook_interface::offchain::add_extra_account_metas_for_execute;\n\npub fn position_bin_range_chunks(lower_bin_id: i32, upper_bin_id: i32) -> Vec<(i32, i32)> {\n    let mut chunked_bin_range = vec![];\n    let bin_range = upper_bin_id - lower_bin_id + 1;\n\n    let (quotient, remainder) = bin_range.div_rem(&(DEFAULT_BIN_PER_POSITION as i32));\n    let chunk = quotient + (remainder != 0) as i32;\n\n    for i in 0..chunk {\n        let min_bin_id = lower_bin_id + DEFAULT_BIN_PER_POSITION as i32 * i;\n        let max_bin_id = std::cmp::min(\n            min_bin_id + DEFAULT_BIN_PER_POSITION as i32 - 1,\n            upper_bin_id,\n        );\n\n        chunked_bin_range.push((min_bin_id, max_bin_id));\n    }\n\n    chunked_bin_range\n}\n\n#[allow(dead_code)]\npub async fn get_transfer_instruction(\n    from: Pubkey,\n    to: Pubkey,\n    mint: Pubkey,\n    owner: Pubkey,\n    rpc_client: RpcClient,\n    amount: u64,\n) -> Result<Instruction> {\n    let account = rpc_client.get_account(&mint).await?;\n\n    if account.owner.eq(&spl_token::ID) {\n        let mint_state = spl_token::state::Mint::unpack(account.data.as_ref())?;\n        Ok(spl_token::instruction::transfer_checked(\n            &account.owner,\n            &from,\n            &mint,\n            &to,\n            &owner,\n            &[],\n            amount,\n            mint_state.decimals,\n        )?)\n    } else {\n        let mint_state =\n            StateWithExtensions::<anchor_spl::token_2022::spl_token_2022::state::Mint>::unpack(\n                account.data.as_ref(),\n            )?;\n\n        let mut transfer_ix =\n            anchor_spl::token_2022::spl_token_2022::instruction::transfer_checked(\n                &account.owner,\n                &from,\n                &mint,\n                &to,\n                &owner,\n                &[],\n                amount,\n                mint_state.base.decimals,\n            )?;\n\n        if let Some(transfer_hook_program_id) = transfer_hook::get_program_id(&mint_state) {\n            let blocking_rpc_client = BlockingRpcClient::new(rpc_client.url());\n\n            let data_fetcher = |address: Pubkey| {\n                let account = blocking_rpc_client\n                    .get_account(&address)\n                    .map(|account| account.data);\n                async move {\n                    std::result::Result::Ok::<\n                        Option<Vec<u8>>,\n                        Box<dyn std::error::Error + Send + Sync>,\n                    >(account.ok())\n                }\n            };\n\n            add_extra_account_metas_for_execute(\n                &mut transfer_ix,\n                &transfer_hook_program_id,\n                &Pubkey::default(),\n                &mint,\n                &Pubkey::default(),\n                &Pubkey::default(),\n                0,\n                data_fetcher,\n            )\n            .await\n            .map_err(|e| anyhow!(e))?;\n        }\n\n        Ok(transfer_ix)\n    }\n}\n\npub async fn get_or_create_ata<C: Deref<Target = impl Signer> + Clone>(\n    program: &Program<C>,\n    transaction_config: RpcSendTransactionConfig,\n    token_mint: Pubkey,\n    wallet_address: Pubkey,\n    compute_unit_price: Option<Instruction>,\n) -> Result<Pubkey> {\n    let rpc_client = program.rpc();\n    let token_mint_owner = rpc_client.get_account(&token_mint).await?.owner;\n\n    let user_ata = get_associated_token_address_with_program_id(\n        &wallet_address,\n        &token_mint,\n        &token_mint_owner,\n    );\n    let user_ata_exists = rpc_client.get_account(&user_ata).await.is_ok();\n\n    if !user_ata_exists {\n        let mut builder = program.request();\n\n        if let Some(compute_unit_price) = compute_unit_price {\n            builder = builder.instruction(compute_unit_price);\n        }\n\n        builder = builder.instruction(create_associated_token_account_idempotent(\n            &program.payer(),\n            &wallet_address,\n            &token_mint,\n            &token_mint_owner,\n        ));\n\n        builder\n            .send_with_spinner_and_config(transaction_config)\n            .await?;\n    }\n\n    Ok(user_ata)\n}\n\npub struct SwapQuoteAccounts {\n    pub lb_pair_state: LbPair,\n    pub clock: Clock,\n    pub mint_x_account: Account,\n    pub mint_y_account: Account,\n    pub bin_arrays: HashMap<Pubkey, BinArray>,\n    pub bin_array_keys: Vec<Pubkey>,\n}\n\npub async fn fetch_quote_required_accounts(\n    rpc_client: &RpcClient,\n    lb_pair: Pubkey,\n    lb_pair_state: &LbPair,\n    bin_arrays_for_swap: Vec<Pubkey>,\n) -> Result<SwapQuoteAccounts> {\n    let prerequisite_accounts = [\n        lb_pair,\n        solana_sdk::sysvar::clock::ID,\n        lb_pair_state.token_x_mint,\n        lb_pair_state.token_y_mint,\n    ];\n\n    let accounts_to_fetch = [prerequisite_accounts.to_vec(), bin_arrays_for_swap.clone()].concat();\n\n    let accounts = rpc_client.get_multiple_accounts(&accounts_to_fetch).await?;\n\n    let mut index = 0;\n    let lb_pair_account = accounts\n        .get(index)\n        .and_then(ToOwned::to_owned)\n        .context(\"Failed to fetch lb pair account\")?;\n    let lb_pair_state = bytemuck::pod_read_unaligned(&mut lb_pair_account.data[8..].as_ref());\n\n    index.inc();\n    let clock_account = accounts\n        .get(index)\n        .and_then(ToOwned::to_owned)\n        .context(\"Failed to fetch clock account\")?;\n    let clock: Clock = bincode::deserialize(clock_account.data.as_ref())?;\n\n    index.inc();\n    let mint_x_account = accounts\n        .get(index)\n        .and_then(ToOwned::to_owned)\n        .context(\"Failed to fetch mint account\")?;\n\n    index.inc();\n    let mint_y_account = accounts\n        .get(index)\n        .and_then(ToOwned::to_owned)\n        .context(\"Failed to fetch mint account\")?;\n\n    let bin_array_accounts = accounts\n        .get(prerequisite_accounts.len()..)\n        .context(\"Failed to fetch bin array accounts\")?\n        .to_vec();\n\n    let valid_bin_array_accounts = bin_array_accounts\n        .into_iter()\n        .zip(bin_arrays_for_swap.iter())\n        .filter_map(|(account, &key)| {\n            let account = account?;\n            Some((\n                key,\n                bytemuck::pod_read_unaligned(&account.data[8..].as_ref()),\n            ))\n        })\n        .collect::<Vec<_>>();\n\n    let bin_arrays = valid_bin_array_accounts\n        .clone()\n        .into_iter()\n        .collect::<HashMap<_, _>>();\n\n    let bin_array_keys = valid_bin_array_accounts\n        .into_iter()\n        .map(|(key, _)| key)\n        .collect::<Vec<_>>();\n\n    Ok(SwapQuoteAccounts {\n        lb_pair_state,\n        clock,\n        mint_x_account,\n        mint_y_account,\n        bin_arrays,\n        bin_array_keys,\n    })\n}\n"
  },
  {
    "path": "cli/src/main.rs",
    "content": "use anchor_client::solana_sdk::compute_budget::ComputeBudgetInstruction;\nuse anchor_client::solana_sdk::instruction::Instruction;\nuse anchor_client::*;\nuse anchor_client::{\n    solana_client::rpc_config::RpcSendTransactionConfig,\n    solana_sdk::pubkey::Pubkey,\n    solana_sdk::{\n        commitment_config::CommitmentConfig,\n        signer::{keypair::*, Signer},\n    },\n};\nuse anchor_lang::prelude::AccountMeta;\nuse anchor_lang::AccountDeserialize;\nuse anchor_lang::InstructionData;\nuse anchor_lang::ToAccountMetas;\nuse anyhow::*;\nuse clap::*;\nuse commons::*;\nuse dlmm::accounts::*;\nuse dlmm::types::*;\nuse instructions::set_pair_status_permissionless::execute_set_pair_status_permissionless;\nuse solana_account_decoder::*;\nuse std::ops::Deref;\nuse std::rc::Rc;\nuse std::time::Duration;\n\nmod args;\nmod instructions;\nmod math;\n\nuse args::*;\nuse commons::rpc_client_extension::*;\nuse instructions::*;\nuse math::*;\n\nfn get_set_compute_unit_price_ix(micro_lamports: u64) -> Option<Instruction> {\n    if micro_lamports > 0 {\n        Some(ComputeBudgetInstruction::set_compute_unit_price(\n            micro_lamports,\n        ))\n    } else {\n        None\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n    let cli = Cli::parse();\n\n    let payer =\n        read_keypair_file(cli.config_override.wallet).expect(\"Wallet keypair file not found\");\n\n    println!(\"Wallet {:#?}\", payer.pubkey());\n\n    let commitment_config = CommitmentConfig::confirmed();\n\n    let client = Client::new_with_options(\n        cli.config_override.cluster,\n        Rc::new(Keypair::from_bytes(&payer.to_bytes())?),\n        commitment_config,\n    );\n\n    let program = client.program(dlmm::ID)?;\n\n    let transaction_config: RpcSendTransactionConfig = RpcSendTransactionConfig {\n        skip_preflight: false,\n        preflight_commitment: Some(commitment_config.commitment),\n        encoding: None,\n        max_retries: None,\n        min_context_slot: None,\n    };\n\n    let compute_unit_price_ix = get_set_compute_unit_price_ix(cli.config_override.priority_fee);\n\n    match cli.command {\n        DLMMCommand::InitializePair2(params) => {\n            execute_initialize_lb_pair2(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::InitializePair(params) => {\n            execute_initialize_lb_pair(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::InitializeBinArray(params) => {\n            execute_initialize_bin_array(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::InitializeBinArrayWithPriceRange(params) => {\n            execute_initialize_bin_array_with_price_range(params, &program, transaction_config)\n                .await?;\n        }\n        DLMMCommand::InitializeBinArrayWithBinRange(params) => {\n            execute_initialize_bin_array_with_bin_range(params, &program, transaction_config)\n                .await?;\n        }\n        DLMMCommand::InitializePositionWithPriceRange(params) => {\n            execute_initialize_position_with_price_range(params, &program, transaction_config)\n                .await?;\n        }\n        DLMMCommand::InitializePosition(params) => {\n            execute_initialize_position(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::AddLiquidity(params) => {\n            execute_add_liquidity(params, &program, transaction_config, compute_unit_price_ix)\n                .await?;\n        }\n        DLMMCommand::RemoveLiquidity(params) => {\n            execute_remove_liquidity(params, &program, transaction_config, compute_unit_price_ix)\n                .await?;\n        }\n        DLMMCommand::SwapExactIn(params) => {\n            execute_swap(params, &program, transaction_config).await?;\n        }\n\n        DLMMCommand::ShowPair(params) => {\n            execute_show_pair(params, &program).await?;\n        }\n        DLMMCommand::ShowPosition(params) => {\n            execute_show_position(params, &program).await?;\n        }\n        DLMMCommand::ClaimReward(params) => {\n            execute_claim_reward(params, &program, transaction_config, compute_unit_price_ix)\n                .await?;\n        }\n        DLMMCommand::UpdateRewardDuration(params) => {\n            execute_update_reward_duration(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::UpdateRewardFunder(params) => {\n            execute_update_reward_funder(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::ClosePosition(params) => {\n            execute_close_position(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::ClaimFee(params) => {\n            execute_claim_fee(params, &program, transaction_config, compute_unit_price_ix).await?;\n        }\n        DLMMCommand::IncreaseOracleLength(params) => {\n            execute_increase_oracle_length(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::ShowPresetParameter(params) => {\n            execute_show_preset_parameters(params, &program).await?;\n        }\n\n        DLMMCommand::ListAllBinStep => {\n            execute_list_all_bin_step(&program).await?;\n        }\n        DLMMCommand::SwapExactOut(params) => {\n            execute_swap_exact_out(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::SwapWithPriceImpact(params) => {\n            execute_swap_with_price_impact(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::InitializeCustomizablePermissionlessLbPair2(params) => {\n            execute_initialize_customizable_permissionless_lb_pair2(\n                params,\n                &program,\n                transaction_config,\n                compute_unit_price_ix,\n            )\n            .await?;\n        }\n        DLMMCommand::InitializeCustomizablePermissionlessLbPair(params) => {\n            execute_initialize_customizable_permissionless_lb_pair(\n                params,\n                &program,\n                transaction_config,\n                compute_unit_price_ix,\n            )\n            .await?;\n        }\n        DLMMCommand::SeedLiquidityByOperator(params) => {\n            let mut retry_count = 0;\n            while let Err(err) = execute_seed_liquidity_by_operator(\n                params.clone(),\n                &program,\n                transaction_config,\n                compute_unit_price_ix.clone(),\n            )\n            .await\n            {\n                println!(\"Error: {}\", err);\n                retry_count += 1;\n                if retry_count >= params.max_retries {\n                    println!(\"Exceeded max retries {}\", params.max_retries);\n                    break;\n                }\n                tokio::time::sleep(Duration::from_secs(16)).await;\n            }\n        }\n        DLMMCommand::SeedLiquiditySingleBinByOperator(params) => {\n            execute_seed_liquidity_single_bin_by_operator(\n                params,\n                &program,\n                transaction_config,\n                compute_unit_price_ix,\n            )\n            .await?;\n        }\n        DLMMCommand::GetAllPositionsForAnOwner(params) => {\n            execute_get_all_positions(&program, params).await?;\n        }\n        DLMMCommand::SetPairStatusPermissionless(params) => {\n            execute_set_pair_status_permissionless(params, &program, transaction_config).await?;\n        }\n        DLMMCommand::SyncPrice(params) => {\n            execute_sync_price(params, &program, transaction_config, compute_unit_price_ix).await?;\n        }\n        DLMMCommand::Admin(command) => match command {\n            AdminCommand::InitializePermissionPair(params) => {\n                execute_initialize_permission_lb_pair(params, &program, transaction_config).await?;\n            }\n            AdminCommand::SetPairStatus(params) => {\n                execute_set_pair_status(params, &program, transaction_config).await?;\n            }\n            AdminCommand::RemoveLiquidityByPriceRange(params) => {\n                execute_remove_liquidity_by_price_range(\n                    params,\n                    &program,\n                    transaction_config,\n                    compute_unit_price_ix,\n                )\n                .await?;\n            }\n            AdminCommand::SetActivationPoint(params) => {\n                execute_set_activation_point(params, &program, transaction_config).await?;\n            }\n            AdminCommand::ClosePresetParameter(params) => {\n                execute_close_preset_parameter(params, &program, transaction_config).await?;\n            }\n            AdminCommand::InitializePresetParameter(params) => {\n                execute_initialize_preset_parameter(params, &program, transaction_config).await?;\n            }\n            AdminCommand::WithdrawProtocolFee(params) => {\n                execute_withdraw_protocol_fee(params, &program, transaction_config).await?;\n            }\n            AdminCommand::FundReward(params) => {\n                execute_fund_reward(params, &program, transaction_config, compute_unit_price_ix)\n                    .await?;\n            }\n            AdminCommand::InitializeReward(params) => {\n                execute_initialize_reward(params, &program, transaction_config).await?;\n            }\n            AdminCommand::SetPreActivationSwapAddress(params) => {\n                execute_set_pre_activation_swap_address(params, &program, transaction_config)\n                    .await?;\n            }\n            AdminCommand::SetPreActivationDuration(params) => {\n                execute_set_pre_activation_duration(params, &program, transaction_config).await?;\n            }\n            AdminCommand::InitializeTokenBadge(params) => {\n                execute_initialize_token_badge(params, &program, transaction_config).await?;\n            }\n            AdminCommand::CreateClaimProtocolFeeOperator(params) => {\n                execute_create_claim_protocol_fee_operator(params, &program, transaction_config)\n                    .await?;\n            }\n            AdminCommand::CloseClaimProtocolFeeOperator(params) => {\n                execute_close_claim_protocol_fee_operator(params, &program, transaction_config)\n                    .await?;\n            }\n            AdminCommand::UpdateBaseFee(params) => {\n                execute_update_base_fee(params, &program, transaction_config).await?;\n            }\n        },\n    };\n\n    Ok(())\n}\n"
  },
  {
    "path": "cli/src/math.rs",
    "content": "use anyhow::{anyhow, Result};\nuse commons::dlmm::types::Rounding;\nuse commons::{BASIS_POINT_MAX, SCALE_OFFSET};\nuse rust_decimal::MathematicalOps;\nuse rust_decimal::{\n    prelude::{FromPrimitive, ToPrimitive},\n    Decimal,\n};\n\npub fn compute_base_factor_from_fee_bps(bin_step: u16, fee_bps: u16) -> Result<(u16, u8)> {\n    let computed_base_factor = fee_bps as f64 * 10_000.0f64 / bin_step as f64;\n\n    if computed_base_factor > u16::MAX as f64 {\n        let mut truncated_base_factor = computed_base_factor;\n        let mut base_power_factor = 0u8;\n        loop {\n            if truncated_base_factor < u16::MAX as f64 {\n                break;\n            }\n\n            let remainder = truncated_base_factor % 10.0;\n            if remainder == 0.0 {\n                base_power_factor += 1;\n                truncated_base_factor /= 10.0;\n            } else {\n                return Err(anyhow!(\"have decimals\"));\n            }\n        }\n\n        Ok((truncated_base_factor as u16, base_power_factor))\n    } else {\n        // Sanity check\n        let casted_base_factor = computed_base_factor as u16 as f64;\n        if casted_base_factor != computed_base_factor {\n            if casted_base_factor == u16::MAX as f64 {\n                return Err(anyhow!(\"overflow\"));\n            }\n\n            if casted_base_factor == 0.0f64 {\n                return Err(anyhow!(\"underflow\"));\n            }\n\n            if computed_base_factor.fract() != 0.0 {\n                return Err(anyhow!(\"have decimals\"));\n            }\n\n            return Err(anyhow!(\"unknown error\"));\n        }\n\n        Ok((computed_base_factor as u16, 0u8))\n    }\n}\n\npub fn get_precise_id_from_price(bin_step: u16, price: &Decimal) -> Option<i32> {\n    let bps = Decimal::from_u16(bin_step)?.checked_div(Decimal::from_i32(BASIS_POINT_MAX)?)?;\n    let base = Decimal::ONE.checked_add(bps)?;\n\n    let id = price.log10().checked_div(base.log10())?.to_f64()?;\n    let trimmed_id = id as i32;\n    let trimmed_id_f64 = trimmed_id as f64;\n\n    if trimmed_id_f64 == id {\n        id.to_i32()\n    } else {\n        None\n    }\n}\n\n/// Calculate the bin id based on price. If the bin id is in between 2 bins, it will round up.\npub fn get_id_from_price(bin_step: u16, price: &Decimal, rounding: Rounding) -> Option<i32> {\n    let bps = Decimal::from_u16(bin_step)?.checked_div(Decimal::from_i32(BASIS_POINT_MAX)?)?;\n    let base = Decimal::ONE.checked_add(bps)?;\n\n    let id = match rounding {\n        Rounding::Down => price.log10().checked_div(base.log10())?.floor(),\n        Rounding::Up => price.log10().checked_div(base.log10())?.ceil(),\n    };\n\n    id.to_i32()\n}\n\n/// Convert Q64xQ64 price to human readable decimal. This is price per lamport.\npub fn q64x64_price_to_decimal(q64x64_price: u128) -> Option<Decimal> {\n    let q_price = Decimal::from_u128(q64x64_price)?;\n    let scale_off = Decimal::TWO.powu(SCALE_OFFSET.into());\n    q_price.checked_div(scale_off)\n}\n\n/// price_per_lamport = price_per_token * 10 ** quote_token_decimal / 10 ** base_token_decimal\npub fn price_per_token_to_per_lamport(\n    price_per_token: f64,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n) -> Option<Decimal> {\n    let price_per_token = Decimal::from_f64(price_per_token)?;\n    price_per_token\n        .checked_mul(Decimal::TEN.powu(quote_token_decimal.into()))?\n        .checked_div(Decimal::TEN.powu(base_token_decimal.into()))\n}\n\n/// price_per_token = price_per_lamport * 10 ** base_token_decimal / 10 ** quote_token_decimal, Solve for price_per_lamport\npub fn price_per_lamport_to_price_per_token(\n    price_per_lamport: f64,\n    base_token_decimal: u8,\n    quote_token_decimal: u8,\n) -> Option<Decimal> {\n    let one_ui_base_token_amount = Decimal::TEN.powu(base_token_decimal.into());\n    let one_ui_quote_token_amount = Decimal::TEN.powu(quote_token_decimal.into());\n    let price_per_lamport = Decimal::from_f64(price_per_lamport)?;\n\n    one_ui_base_token_amount\n        .checked_mul(price_per_lamport)?\n        .checked_div(one_ui_quote_token_amount)\n}\n"
  },
  {
    "path": "command_list/claim_fee_from_operator.sh",
    "content": "cluster=https://api.mainnet-beta.solana.com\noperator_kp=~/.config/solana/id.json\npriority_fee=1000\n\nposition=[Position pk]\n./target/debug/cli --provider.cluster $cluster --provider.wallet $operator_kp --priority-fee $priority_fee claim-fee $position\n\n# get all positions\n# lb_pair=[Pool pk]\n# owner=[Owner pk]\n# ./target/debug/cli --provider.cluster $cluster get-all-positions-for-an-owner --lb-pair $lb_pair --owner $owner\n\n"
  },
  {
    "path": "command_list/ilm_curve_by_operator.sh",
    "content": "#!/bin/bash\ncluster=\"https://api.devnet.solana.com\"\n\n# Get from initialize pair\npair=\"[LB pair public key]\"\n\n# ILM parameters\nmin_price=0.003\nmax_price=0.03\ncurvature=0.8\n# Liquidity for seeding. UI amount.\namount=150000000\n# Keypair paths\n# Position owner public key\nposition_owner=\"[Position owner public key]\"\n# Fee owner public key\nfee_owner=\"[Fee owner public key]\"\n# Lock release point, the point when position can be withdraw\nlock_release_point=0\n# Base position keypair path\nbase_position_path=\"[Base position keypair path (can be the same with operator kp path)]\"\n# Deployer keypair path\noperator_kp_path=\"[Deployer keypair path]\"\n# Get base_position_path pubkey by solana-keygen pubkey <base_position_path>\nbase_position_key=\"[Base public key]\"\npriority_fee_microlamport=100000\nmax_retries=1000\n\n# Seed liquidity\n./target/debug/cli seed-liquidity-by-operator --lb-pair $pair --base-position-path $base_position_path --base-pubkey $base_position_key --amount $amount \\\n --min-price $min_price --max-price $max_price --curvature $curvature --position-owner $position_owner --fee-owner $fee_owner --lock-release-point $lock_release_point\\\n --max-retries $max_retries --provider.cluster $cluster --provider.wallet $operator_kp_path --priority-fee $priority_fee_microlamport"
  },
  {
    "path": "command_list/ilm_single_bin_by_operator.sh",
    "content": "#!/bin/bash\ncluster=\"https://api.devnet.solana.com\"\n# Get from initialize pair\npair=\"[LB pair public key]\"\n\n# Liquidity for seeding. UI amount.\namount=1000000\n# Price\nprice=0.25\n# Pool start price rounding if the price cannot be exact. \"up\", \"down\", \"none\". None will terminate the script if the price cannot be exact.\nprice_rounding=\"up\"\n\n# Keypair paths\n# Position owner keypair path\nposition_owner=\"[Position owner public key]\"\nfee_owner=\"[Fee owner public key]\"\nlock_release_point=0\n\n# Base position keypair path\nbase_position_path=\"deployer.json\"\noperator_kp_path=\"deployer.json\"\n# Get base_position_path pubkey by solana-keygen pubkey <base_position_path>\nbase_position_key=\"[Address of deployer.json]\"\npriority_fee_microlamport=100000\n\n# Seed liquidity\n./target/debug/cli seed-liquidity-single-bin-by-operator --lb-pair $pair --base-position-path $base_position_path --base-pubkey $base_position_key --amount $amount \\\n --price $price --position-owner $position_owner --fee-owner $fee_owner --lock-release-point $lock_release_point --selective-rounding $price_rounding\\\n --provider.cluster $cluster --provider.wallet $operator_kp_path --priority-fee $priority_fee_microlamport"
  },
  {
    "path": "command_list/set_bootstrapping_pair_status.sh",
    "content": "#!/bin/bash\n\ncluster=\"https://api.devnet.solana.com\"\n\npair=\"[LB pair public key]\"\npool_creator_path=\"[Pool creator keypair path]\"\n\n# enable / disable pool\nenable=false\n\nif $enable \nthen\n    ./target/debug/cli set-pair-status-permissionless --lb-pair $pair --enable --provider.cluster $cluster --provider.wallet $pool_creator_path\nelse\n    ./target/debug/cli set-pair-status-permissionless --lb-pair $pair --provider.cluster $cluster --provider.wallet $pool_creator_path\nfi\n"
  },
  {
    "path": "commons/Cargo.toml",
    "content": "[package]\nname = \"commons\"\nversion = \"0.3.2\"\nedition = \"2021\"\ndescription = \"Common libraries for DLMM\"\nauthors = [\"tian <tian@racoons.dev>\"]\n\n[features]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nanchor-lang = { workspace = true }\nanchor-client = { workspace = true, features = [\"async\"] }\nanchor-spl = { workspace = true }\nanyhow = { workspace = true }\ntokio = { workspace = true, features = [\"full\", \"parking_lot\"] }\nbincode = { workspace = true }\nsolana-sdk = { workspace = true }\nruint = { workspace = true }\nnum-traits = { workspace = true }\nnum-integer = { workspace = true }\nbytemuck = { workspace = true, features = [\"derive\", \"min_const_generics\"] }\nasync-trait = { workspace = true }\nspl-transfer-hook-interface = { workspace = true }\n\n[dev-dependencies]\nspl-associated-token-account = { workspace = true }\nsolana-program-test = \"2.1.0\"\nassert_matches = \"1.5.0\"\nsolana-program = \"2.1.0\"\nspl-memo = { workspace = true, features = [\"no-entrypoint\"] }\nlitesvm = \"0.6.0\"\nserde_json = { workspace = true }\n"
  },
  {
    "path": "commons/src/account_filters.rs",
    "content": "use anchor_client::solana_client::rpc_filter::{Memcmp, RpcFilterType};\nuse solana_sdk::pubkey::Pubkey;\n\npub fn position_filter_by_wallet_and_pair(wallet: Pubkey, pair: Pubkey) -> Vec<RpcFilterType> {\n    let position_pair_filter =\n        RpcFilterType::Memcmp(Memcmp::new_base58_encoded(8, &pair.to_bytes()));\n\n    let position_owner_filter = RpcFilterType::Memcmp(Memcmp::new_base58_encoded(\n        8 + std::mem::size_of::<Pubkey>(),\n        &wallet.to_bytes(),\n    ));\n\n    vec![position_pair_filter, position_owner_filter]\n}\n"
  },
  {
    "path": "commons/src/constants.rs",
    "content": "pub const BASIS_POINT_MAX: i32 = 10000;\n\n/// Maximum number of bin a bin array able to contains.\npub const MAX_BIN_PER_ARRAY: usize = 70;\n\n/// Default number of bin per position contains.\npub const DEFAULT_BIN_PER_POSITION: usize = 70;\n\n/// Max resize length allowed\npub const MAX_RESIZE_LENGTH: usize = 70;\n\n/// Maximum number of bin per position contains.\npub const POSITION_MAX_LENGTH: usize = 1400;\n\n/// Minimum bin ID supported. Computed based on 1 bps.\npub const MIN_BIN_ID: i32 = -443636;\n\n/// Maximum bin ID supported. Computed based on 1 bps.\npub const MAX_BIN_ID: i32 = 443636;\n\n/// Maximum fee rate. 10%\npub const MAX_FEE_RATE: u64 = 100_000_000;\n\npub const FEE_PRECISION: u64 = 1_000_000_000;\n\n/// Maximum protocol share of the fee. 25%\npub const MAX_PROTOCOL_SHARE: u16 = 2_500;\n\n/// Host fee. 20%\npub const HOST_FEE_BPS: u16 = 2_000;\n\n// Number of rewards supported by pool\npub const NUM_REWARDS: usize = 2;\n\n// Minimum reward duration\npub const MIN_REWARD_DURATION: u64 = 1;\n\npub const MAX_REWARD_DURATION: u64 = 31536000; // 1 year = 365 * 24 * 3600\n\npub const DEFAULT_OBSERVATION_LENGTH: u64 = 100;\n\npub const SAMPLE_LIFETIME: u64 = 120; // 2\n\npub const EXTENSION_BINARRAY_BITMAP_SIZE: usize = 12;\n\npub const BIN_ARRAY_BITMAP_SIZE: i32 = 512;\n\npub const MAX_BASE_FACTOR_STEP: u16 = 100; // 100 bps, 1%\n\npub const MAX_FEE_UPDATE_WINDOW: i64 = 0;\n\npub const MAX_REWARD_BIN_SPLIT: usize = 15;\n\npub const SLOT_BUFFER: u64 = 9000;\n\npub const TIME_BUFFER: u64 = 3600;\n\npub const MAX_ACTIVATION_SLOT_DURATION: u64 = SLOT_BUFFER * 24 * 31; // 31 days\n\npub const MAX_ACTIVATION_TIME_DURATION: u64 = TIME_BUFFER * 24 * 31; // 31 days\n\npub const FIVE_MINUTES_SLOT_BUFFER: u64 = SLOT_BUFFER / 12; // 5 minutes\n\npub const FIVE_MINUTES_TIME_BUFFER: u64 = TIME_BUFFER / 12; // 5 minutes\n\n// ILM token launch protocol fee\npub const ILM_PROTOCOL_SHARE: u16 = 2000; // 20%\n\n/// Maximum bin step\npub const MAX_BIN_STEP: u16 = 400;\n\n/// Maximum base fee, base_fee / 10^9 = fee_in_percentage\npub const MAX_BASE_FEE: u128 = 100_000_000; // 10% (10^9 * 10 / 100)\n\n/// Minimum base fee\npub const MIN_BASE_FEE: u128 = 100_000; // 0.01% (10^9 * 0.01 / 100)\n"
  },
  {
    "path": "commons/src/conversions/activation_type.rs",
    "content": "use crate::*;\n\nimpl TryFrom<u8> for ActivationType {\n    type Error = anyhow::Error;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        match value {\n            0 => Ok(ActivationType::Slot),\n            1 => Ok(ActivationType::Timestamp),\n            _ => Err(anyhow::anyhow!(\"Invalid ActivationType value: {}\", value)),\n        }\n    }\n}\n"
  },
  {
    "path": "commons/src/conversions/mod.rs",
    "content": "#![allow(unused_imports)]\npub mod status;\npub use status::*;\n\npub mod pair_type;\npub use pair_type::*;\n\npub mod activation_type;\npub use activation_type::*;\n\npub mod token_program_flag;\npub use token_program_flag::*;\n"
  },
  {
    "path": "commons/src/conversions/pair_type.rs",
    "content": "use crate::*;\n\nimpl TryFrom<u8> for PairType {\n    type Error = anyhow::Error;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        match value {\n            0 => Ok(PairType::Permissionless),\n            1 => Ok(PairType::Permission),\n            2 => Ok(PairType::CustomizablePermissionless),\n            3 => Ok(PairType::PermissionlessV2),\n            _ => Err(anyhow::anyhow!(\"Invalid PairType value: {}\", value)),\n        }\n    }\n}\n\nimpl PartialEq for PairType {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (&PairType::Permissionless, &PairType::Permissionless) => true,\n            (&PairType::Permission, &PairType::Permission) => true,\n            (&PairType::CustomizablePermissionless, &PairType::CustomizablePermissionless) => true,\n            (&PairType::PermissionlessV2, &PairType::PermissionlessV2) => true,\n            _ => false,\n        }\n    }\n}\n"
  },
  {
    "path": "commons/src/conversions/status.rs",
    "content": "use crate::*;\n\nimpl TryFrom<u8> for PairStatus {\n    type Error = anyhow::Error;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        match value {\n            0 => Ok(PairStatus::Enabled),\n            1 => Ok(PairStatus::Disabled),\n            _ => Err(anyhow::anyhow!(\"Invalid PairStatus value: {}\", value)),\n        }\n    }\n}\n\nimpl PartialEq for PairStatus {\n    fn eq(&self, other: &Self) -> bool {\n        matches!(\n            (self, other),\n            (PairStatus::Enabled, PairStatus::Enabled)\n                | (PairStatus::Disabled, PairStatus::Disabled)\n        )\n    }\n}\n"
  },
  {
    "path": "commons/src/conversions/token_program_flag.rs",
    "content": "use crate::*;\nuse std::ops::Deref;\n\npub struct TokenProgramFlagWrapper(TokenProgramFlags);\n\nimpl Deref for TokenProgramFlagWrapper {\n    type Target = TokenProgramFlags;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl TryFrom<u8> for TokenProgramFlagWrapper {\n    type Error = anyhow::Error;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        match value {\n            0 => Ok(TokenProgramFlagWrapper(TokenProgramFlags::TokenProgram)),\n            1 => Ok(TokenProgramFlagWrapper(TokenProgramFlags::TokenProgram2022)),\n            _ => Err(anyhow::anyhow!(\n                \"Invalid TokenProgramFlags value: {}\",\n                value\n            )),\n        }\n    }\n}\n"
  },
  {
    "path": "commons/src/extensions/bin.rs",
    "content": "use crate::*;\n\npub trait BinExtension {\n    fn get_or_store_bin_price(&mut self, id: i32, bin_step: u16) -> Result<u128>;\n    fn is_empty(&self, is_x: bool) -> bool;\n    fn get_max_amount_out(&self, swap_for_y: bool) -> u64;\n    fn get_max_amount_in(&self, price: u128, swap_for_y: bool) -> Result<u64>;\n    fn calculate_out_amount(&self, liquidity_share: u128) -> Result<(u64, u64)>;\n\n    fn swap(\n        &mut self,\n        amount_in: u64,\n        price: u128,\n        swap_for_y: bool,\n        lb_pair: &LbPair,\n        host_fee_bps: Option<u16>,\n    ) -> Result<SwapResult>;\n\n    fn get_amount_out(amount_in: u64, price: u128, swap_for_y: bool) -> Result<u64>;\n    fn get_amount_in(amount_out: u64, price: u128, swap_for_y: bool) -> Result<u64>;\n}\n\nimpl BinExtension for Bin {\n    fn get_or_store_bin_price(&mut self, id: i32, bin_step: u16) -> Result<u128> {\n        if self.price == 0 {\n            self.price = get_price_from_id(id, bin_step)?;\n        }\n\n        Ok(self.price)\n    }\n\n    fn is_empty(&self, is_x: bool) -> bool {\n        if is_x {\n            self.amount_x == 0\n        } else {\n            self.amount_y == 0\n        }\n    }\n\n    fn get_max_amount_out(&self, swap_for_y: bool) -> u64 {\n        if swap_for_y {\n            self.amount_y\n        } else {\n            self.amount_x\n        }\n    }\n\n    fn get_max_amount_in(&self, price: u128, swap_for_y: bool) -> Result<u64> {\n        if swap_for_y {\n            safe_shl_div_cast(self.amount_y.into(), price, SCALE_OFFSET, Rounding::Up)\n        } else {\n            safe_mul_shr_cast(self.amount_x.into(), price, SCALE_OFFSET, Rounding::Up)\n        }\n    }\n\n    fn get_amount_in(amount_out: u64, price: u128, swap_for_y: bool) -> Result<u64> {\n        if swap_for_y {\n            safe_shl_div_cast(amount_out.into(), price, SCALE_OFFSET, Rounding::Up)\n        } else {\n            safe_mul_shr_cast(amount_out.into(), price, SCALE_OFFSET, Rounding::Up)\n        }\n    }\n\n    fn get_amount_out(amount_in: u64, price: u128, swap_for_y: bool) -> Result<u64> {\n        if swap_for_y {\n            safe_mul_shr_cast(price, amount_in.into(), SCALE_OFFSET, Rounding::Down)\n        } else {\n            safe_shl_div_cast(amount_in.into(), price, SCALE_OFFSET, Rounding::Down)\n        }\n    }\n\n    fn calculate_out_amount(&self, liquidity_share: u128) -> Result<(u64, u64)> {\n        let out_amount_x = safe_mul_div_cast(\n            liquidity_share,\n            self.amount_x.into(),\n            self.liquidity_supply,\n            Rounding::Down,\n        )?;\n\n        let out_amount_y = safe_mul_div_cast(\n            liquidity_share,\n            self.amount_y.into(),\n            self.liquidity_supply,\n            Rounding::Down,\n        )?;\n        Ok((out_amount_x, out_amount_y))\n    }\n\n    fn swap(\n        &mut self,\n        amount_in: u64,\n        price: u128,\n        swap_for_y: bool,\n        lb_pair: &LbPair,\n        host_fee_bps: Option<u16>,\n    ) -> Result<SwapResult> {\n        let max_amount_out = self.get_max_amount_out(swap_for_y);\n        let mut max_amount_in = self.get_max_amount_in(price, swap_for_y)?;\n\n        let max_fee = lb_pair.compute_fee(max_amount_in)?;\n        max_amount_in = max_amount_in.checked_add(max_fee).context(\"overflow\")?;\n\n        let (amount_in_with_fees, amount_out, fee, protocol_fee) = if amount_in > max_amount_in {\n            (\n                max_amount_in,\n                max_amount_out,\n                max_fee,\n                lb_pair.compute_protocol_fee(max_fee)?,\n            )\n        } else {\n            let fee = lb_pair.compute_fee_from_amount(amount_in)?;\n            let amount_in_after_fee = amount_in.checked_sub(fee).context(\"overflow\")?;\n            let amount_out = Bin::get_amount_out(amount_in_after_fee, price, swap_for_y)?;\n            (\n                amount_in,\n                std::cmp::min(amount_out, max_amount_out),\n                fee,\n                lb_pair.compute_protocol_fee(fee)?,\n            )\n        };\n\n        let host_fee = match host_fee_bps {\n            Some(bps) => protocol_fee\n                .checked_mul(bps.into())\n                .context(\"overflow\")?\n                .checked_div(BASIS_POINT_MAX as u64)\n                .context(\"overflow\")?,\n            None => 0,\n        };\n\n        let protocol_fee_after_host_fee = protocol_fee.checked_sub(host_fee).context(\"overflow\")?;\n\n        let amount_into_bin = amount_in_with_fees.checked_sub(fee).context(\"overflow\")?;\n\n        if swap_for_y {\n            self.amount_x = self\n                .amount_x\n                .checked_add(amount_into_bin)\n                .context(\"overflow\")?;\n            self.amount_y = self.amount_y.checked_sub(amount_out).context(\"overflow\")?;\n        } else {\n            self.amount_y = self\n                .amount_y\n                .checked_add(amount_into_bin)\n                .context(\"overflow\")?;\n            self.amount_x = self.amount_x.checked_sub(amount_out).context(\"overflow\")?;\n        }\n\n        Ok(SwapResult {\n            amount_in_with_fees,\n            amount_out,\n            fee,\n            protocol_fee_after_host_fee,\n            host_fee,\n            is_exact_out_amount: false,\n        })\n    }\n}\n"
  },
  {
    "path": "commons/src/extensions/bin_array.rs",
    "content": "use crate::*;\nuse num_integer::Integer;\nuse solana_sdk::{instruction::AccountMeta, pubkey::Pubkey};\n\npub trait BinArrayExtension {\n    fn is_bin_id_within_range(&self, bin_id: i32) -> Result<bool>;\n    fn get_bin_index_in_array(&self, bin_id: i32) -> Result<usize>;\n\n    fn get_bin_array_lower_upper_bin_id(index: i32) -> Result<(i32, i32)>;\n    fn bin_id_to_bin_array_index(bin_id: i32) -> Result<i32>;\n    fn bin_id_to_bin_array_key(lb_pair: Pubkey, bin_id: i32) -> Result<Pubkey>;\n\n    fn get_bin_mut<'a>(&'a mut self, bin_id: i32) -> Result<&'a mut Bin>;\n    fn get_bin<'a>(&'a self, bin_id: i32) -> Result<&'a Bin>;\n\n    fn get_bin_array_account_metas_coverage(\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n        lb_pair: Pubkey,\n    ) -> Result<Vec<AccountMeta>>;\n\n    fn get_bin_array_indexes_coverage(lower_bin_id: i32, upper_bin_id: i32) -> Result<Vec<i32>>;\n}\n\nimpl BinArrayExtension for BinArray {\n    fn get_bin_array_lower_upper_bin_id(index: i32) -> Result<(i32, i32)> {\n        let lower_bin_id = index\n            .checked_mul(MAX_BIN_PER_ARRAY as i32)\n            .context(\"overflow\")?;\n\n        let upper_bin_id = lower_bin_id\n            .checked_add(MAX_BIN_PER_ARRAY as i32)\n            .context(\"overflow\")?\n            .checked_sub(1)\n            .context(\"overflow\")?;\n\n        Ok((lower_bin_id, upper_bin_id))\n    }\n\n    fn is_bin_id_within_range(&self, bin_id: i32) -> Result<bool> {\n        let (lower_bin_id, upper_bin_id) =\n            BinArray::get_bin_array_lower_upper_bin_id(self.index as i32)?;\n\n        Ok(bin_id >= lower_bin_id && bin_id <= upper_bin_id)\n    }\n\n    fn get_bin_mut<'a>(&'a mut self, bin_id: i32) -> Result<&'a mut Bin> {\n        Ok(&mut self.bins[self.get_bin_index_in_array(bin_id)?])\n    }\n\n    fn get_bin<'a>(&'a self, bin_id: i32) -> Result<&'a Bin> {\n        Ok(&self.bins[self.get_bin_index_in_array(bin_id)?])\n    }\n\n    fn get_bin_index_in_array(&self, bin_id: i32) -> Result<usize> {\n        ensure!(self.is_bin_id_within_range(bin_id)?, \"Bin id out of range\");\n        let (lower_bin_id, _) = BinArray::get_bin_array_lower_upper_bin_id(self.index as i32)?;\n        let index = bin_id.checked_sub(lower_bin_id).context(\"overflow\")?;\n        Ok(index as usize)\n    }\n\n    fn bin_id_to_bin_array_index(bin_id: i32) -> Result<i32> {\n        let (idx, rem) = bin_id.div_rem(&(MAX_BIN_PER_ARRAY as i32));\n\n        if bin_id.is_negative() && rem != 0 {\n            Ok(idx.checked_sub(1).context(\"overflow\")?)\n        } else {\n            Ok(idx)\n        }\n    }\n\n    fn bin_id_to_bin_array_key(lb_pair: Pubkey, bin_id: i32) -> Result<Pubkey> {\n        let bin_array_index = Self::bin_id_to_bin_array_index(bin_id)?;\n        Ok(derive_bin_array_pda(lb_pair, bin_array_index.into()).0)\n    }\n\n    fn get_bin_array_indexes_coverage(lower_bin_id: i32, upper_bin_id: i32) -> Result<Vec<i32>> {\n        let lower_idx = BinArray::bin_id_to_bin_array_index(lower_bin_id)?;\n        let upper_idx = BinArray::bin_id_to_bin_array_index(upper_bin_id)?;\n\n        let mut indexes = vec![];\n\n        for i in lower_idx..=upper_idx {\n            indexes.push(i);\n        }\n\n        Ok(indexes)\n    }\n\n    fn get_bin_array_account_metas_coverage(\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n        lb_pair: Pubkey,\n    ) -> Result<Vec<AccountMeta>> {\n        let bin_array_indexes =\n            BinArray::get_bin_array_indexes_coverage(lower_bin_id, upper_bin_id)?;\n\n        Ok(bin_array_indexes\n            .into_iter()\n            .map(|index| AccountMeta {\n                pubkey: derive_bin_array_pda(lb_pair, index.into()).0,\n                is_signer: false,\n                is_writable: true,\n            })\n            .collect())\n    }\n}\n"
  },
  {
    "path": "commons/src/extensions/bin_array_bitmap.rs",
    "content": "use crate::*;\nuse ruint::aliases::U512;\n\npub trait BinArrayBitmapExtExtension {\n    fn bitmap_range() -> (i32, i32);\n    fn get_bitmap_offset(bin_array_index: i32) -> Result<usize>;\n    fn bin_array_offset_in_bitmap(bin_array_index: i32) -> Result<usize>;\n    fn to_bin_array_index(offset: usize, bin_array_offset: usize, is_positive: bool)\n        -> Result<i32>;\n\n    fn get_bitmap(&self, bin_array_index: i32) -> Result<(usize, [u64; 8])>;\n    fn bit(&self, bin_array_index: i32) -> Result<bool>;\n    fn iter_bitmap(&self, start_index: i32, end_index: i32) -> Result<Option<i32>>;\n    fn next_bin_array_index_with_liquidity(\n        &self,\n        swap_for_y: bool,\n        start_index: i32,\n    ) -> Result<(i32, bool)>;\n}\n\nimpl BinArrayBitmapExtExtension for BinArrayBitmapExtension {\n    fn bitmap_range() -> (i32, i32) {\n        return (\n            -BIN_ARRAY_BITMAP_SIZE * (EXTENSION_BINARRAY_BITMAP_SIZE as i32 + 1),\n            BIN_ARRAY_BITMAP_SIZE * (EXTENSION_BINARRAY_BITMAP_SIZE as i32 + 1) - 1,\n        );\n    }\n\n    fn next_bin_array_index_with_liquidity(\n        &self,\n        swap_for_y: bool,\n        start_index: i32,\n    ) -> Result<(i32, bool)> {\n        let (min_bitmap_id, max_bit_map_id) = BinArrayBitmapExtension::bitmap_range();\n        if start_index > 0 {\n            if swap_for_y {\n                match self.iter_bitmap(start_index, BIN_ARRAY_BITMAP_SIZE)? {\n                    Some(value) => return Ok((value, true)),\n                    None => return Ok((BIN_ARRAY_BITMAP_SIZE - 1, false)),\n                }\n            } else {\n                match self.iter_bitmap(start_index, max_bit_map_id)? {\n                    Some(value) => return Ok((value, true)),\n                    None => return Err(anyhow!(\"Cannot find non-zero liquidity bin array id\")),\n                }\n            }\n        } else if swap_for_y {\n            match self.iter_bitmap(start_index, min_bitmap_id)? {\n                Some(value) => return Ok((value, true)),\n                None => return Err(anyhow!(\"Cannot find non-zero liquidity bin array id\")),\n            }\n        } else {\n            match self.iter_bitmap(start_index, -BIN_ARRAY_BITMAP_SIZE - 1)? {\n                Some(value) => return Ok((value, true)),\n                None => return Ok((-BIN_ARRAY_BITMAP_SIZE, false)),\n            }\n        }\n    }\n\n    fn bit(&self, bin_array_index: i32) -> Result<bool> {\n        let (_, bin_array_bitmap) = self.get_bitmap(bin_array_index)?;\n        let bin_array_offset_in_bitmap = Self::bin_array_offset_in_bitmap(bin_array_index)?;\n        let bin_array_bitmap = U512::from_limbs(bin_array_bitmap);\n        Ok(bin_array_bitmap.bit(bin_array_offset_in_bitmap as usize))\n    }\n\n    fn get_bitmap(&self, bin_array_index: i32) -> Result<(usize, [u64; 8])> {\n        let offset = Self::get_bitmap_offset(bin_array_index)?;\n        if bin_array_index < 0 {\n            Ok((offset, self.negative_bin_array_bitmap[offset]))\n        } else {\n            Ok((offset, self.positive_bin_array_bitmap[offset]))\n        }\n    }\n\n    fn to_bin_array_index(\n        offset: usize,\n        bin_array_offset: usize,\n        is_positive: bool,\n    ) -> Result<i32> {\n        let offset = offset as i32;\n        let bin_array_offset = bin_array_offset as i32;\n        if is_positive {\n            Ok((offset + 1) * BIN_ARRAY_BITMAP_SIZE + bin_array_offset)\n        } else {\n            Ok(-((offset + 1) * BIN_ARRAY_BITMAP_SIZE + bin_array_offset) - 1)\n        }\n    }\n\n    fn bin_array_offset_in_bitmap(bin_array_index: i32) -> Result<usize> {\n        if bin_array_index > 0 {\n            Ok(bin_array_index\n                .checked_rem(BIN_ARRAY_BITMAP_SIZE)\n                .context(\"overflow\")? as usize)\n        } else {\n            Ok((-(bin_array_index + 1))\n                .checked_rem(BIN_ARRAY_BITMAP_SIZE)\n                .context(\"overflow\")? as usize)\n        }\n    }\n\n    fn get_bitmap_offset(bin_array_index: i32) -> Result<usize> {\n        let offset = if bin_array_index > 0 {\n            bin_array_index / BIN_ARRAY_BITMAP_SIZE - 1\n        } else {\n            -(bin_array_index + 1) / BIN_ARRAY_BITMAP_SIZE - 1\n        };\n        Ok(offset as usize)\n    }\n\n    fn iter_bitmap(&self, start_index: i32, end_index: i32) -> Result<Option<i32>> {\n        if start_index == end_index {\n            if self.bit(start_index)? {\n                return Ok(Some(start_index));\n            } else {\n                return Ok(None);\n            }\n        }\n        let offset: usize = Self::get_bitmap_offset(start_index)?;\n        let bin_array_offset = Self::bin_array_offset_in_bitmap(start_index)?;\n        if start_index < 0 {\n            // iter in negative_bin_array_bitmap\n            if start_index < end_index {\n                for i in (0..=offset).rev() {\n                    let mut bin_array_bitmap = U512::from_limbs(self.negative_bin_array_bitmap[i]);\n\n                    if i == offset {\n                        bin_array_bitmap = bin_array_bitmap\n                            << BIN_ARRAY_BITMAP_SIZE as usize - bin_array_offset - 1;\n                        if bin_array_bitmap.eq(&U512::ZERO) {\n                            continue;\n                        }\n\n                        let bin_array_offset_in_bitmap =\n                            bin_array_offset - bin_array_bitmap.leading_zeros();\n\n                        return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                            i,\n                            bin_array_offset_in_bitmap,\n                            false,\n                        )?));\n                    }\n                    if bin_array_bitmap.eq(&U512::ZERO) {\n                        continue;\n                    }\n                    let bin_array_offset_in_bitmap =\n                        BIN_ARRAY_BITMAP_SIZE as usize - bin_array_bitmap.leading_zeros() - 1;\n                    return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                        i,\n                        bin_array_offset_in_bitmap,\n                        false,\n                    )?));\n                }\n            } else {\n                for i in offset..EXTENSION_BINARRAY_BITMAP_SIZE {\n                    let mut bin_array_bitmap = U512::from_limbs(self.negative_bin_array_bitmap[i]);\n                    if i == offset {\n                        bin_array_bitmap = bin_array_bitmap >> bin_array_offset;\n                        if bin_array_bitmap.eq(&U512::ZERO) {\n                            continue;\n                        }\n\n                        let bin_array_offset_in_bitmap =\n                            bin_array_offset + bin_array_bitmap.trailing_zeros();\n\n                        return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                            i,\n                            bin_array_offset_in_bitmap,\n                            false,\n                        )?));\n                    }\n\n                    if bin_array_bitmap.eq(&U512::ZERO) {\n                        continue;\n                    }\n                    let bin_array_offset_in_bitmap = bin_array_bitmap.trailing_zeros();\n\n                    return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                        i,\n                        bin_array_offset_in_bitmap,\n                        false,\n                    )?));\n                }\n            }\n        } else {\n            // iter in possitive_bin_array_bitmap\n            if start_index < end_index {\n                for i in offset..EXTENSION_BINARRAY_BITMAP_SIZE {\n                    let mut bin_array_bitmap = U512::from_limbs(self.positive_bin_array_bitmap[i]);\n                    if i == offset {\n                        bin_array_bitmap = bin_array_bitmap >> bin_array_offset;\n                        if bin_array_bitmap.eq(&U512::ZERO) {\n                            continue;\n                        }\n\n                        let bin_array_offset_in_bitmap =\n                            bin_array_offset + bin_array_bitmap.trailing_zeros();\n                        return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                            i,\n                            bin_array_offset_in_bitmap,\n                            true,\n                        )?));\n                    }\n\n                    if bin_array_bitmap.eq(&U512::ZERO) {\n                        continue;\n                    }\n\n                    let bin_array_offset_in_bitmap = bin_array_bitmap.trailing_zeros();\n                    return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                        i,\n                        bin_array_offset_in_bitmap,\n                        true,\n                    )?));\n                }\n            } else {\n                for i in (0..=offset).rev() {\n                    let mut bin_array_bitmap = U512::from_limbs(self.positive_bin_array_bitmap[i]);\n\n                    if i == offset {\n                        bin_array_bitmap = bin_array_bitmap\n                            << BIN_ARRAY_BITMAP_SIZE as usize - bin_array_offset - 1;\n\n                        if bin_array_bitmap.eq(&U512::ZERO) {\n                            continue;\n                        }\n                        let bin_array_offset_in_bitmap =\n                            bin_array_offset - bin_array_bitmap.leading_zeros();\n                        return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                            i,\n                            bin_array_offset_in_bitmap,\n                            true,\n                        )?));\n                    }\n\n                    if bin_array_bitmap.eq(&U512::ZERO) {\n                        continue;\n                    }\n                    let bin_array_offset_in_bitmap =\n                        BIN_ARRAY_BITMAP_SIZE as usize - bin_array_bitmap.leading_zeros() - 1;\n                    return Ok(Some(BinArrayBitmapExtension::to_bin_array_index(\n                        i,\n                        bin_array_offset_in_bitmap,\n                        true,\n                    )?));\n                }\n            }\n        }\n        Ok(None)\n    }\n}\n"
  },
  {
    "path": "commons/src/extensions/lb_pair.rs",
    "content": "use crate::*;\nuse anchor_spl::token::spl_token;\nuse anchor_spl::token_2022::spl_token_2022;\nuse ruint::aliases::U1024;\nuse solana_sdk::pubkey::Pubkey;\nuse std::ops::Deref;\nuse std::ops::Shl;\nuse std::ops::Shr;\n\npub trait LbPairExtension {\n    fn bitmap_range() -> (i32, i32);\n    fn get_bin_array_offset(bin_array_index: i32) -> usize;\n\n    fn status(&self) -> Result<PairStatus>;\n    fn pair_type(&self) -> Result<PairType>;\n    fn activation_type(&self) -> Result<ActivationType>;\n    fn compute_fee(&self, amount: u64) -> Result<u64>;\n    fn get_total_fee(&self) -> Result<u128>;\n    fn get_base_fee(&self) -> Result<u128>;\n    fn get_variable_fee(&self) -> Result<u128>;\n    fn get_token_programs(&self) -> Result<[Pubkey; 2]>;\n    fn compute_variable_fee(&self, volatility_accumulator: u32) -> Result<u128>;\n    fn compute_protocol_fee(&self, fee_amount: u64) -> Result<u64>;\n    fn compute_fee_from_amount(&self, amount_with_fees: u64) -> Result<u64>;\n    fn is_overflow_default_bin_array_bitmap(&self, bin_array_index: i32) -> bool;\n    fn next_bin_array_index_with_liquidity_internal(\n        &self,\n        swap_for_y: bool,\n        start_array_index: i32,\n    ) -> Result<(i32, bool)>;\n\n    fn update_references(&mut self, current_timestamp: i64) -> Result<()>;\n    fn update_volatility_accumulator(&mut self) -> Result<()>;\n    fn advance_active_bin(&mut self, swap_for_y: bool) -> Result<()>;\n}\n\nimpl LbPairExtension for LbPair {\n    fn status(&self) -> Result<PairStatus> {\n        Ok(self.status.try_into()?)\n    }\n\n    fn get_token_programs(&self) -> Result<[Pubkey; 2]> {\n        let mut token_programs_id = [Pubkey::default(); 2];\n\n        for (i, token_program_flag) in [\n            self.token_mint_x_program_flag,\n            self.token_mint_y_program_flag,\n        ]\n        .into_iter()\n        .enumerate()\n        {\n            let flag: TokenProgramFlagWrapper = token_program_flag.try_into()?;\n            let token_program_id = match flag.deref() {\n                TokenProgramFlags::TokenProgram => spl_token::ID,\n                TokenProgramFlags::TokenProgram2022 => spl_token_2022::ID,\n            };\n            token_programs_id[i] = token_program_id;\n        }\n\n        Ok(token_programs_id)\n    }\n\n    fn pair_type(&self) -> Result<PairType> {\n        Ok(self.pair_type.try_into()?)\n    }\n\n    fn activation_type(&self) -> Result<ActivationType> {\n        Ok(self.activation_type.try_into()?)\n    }\n\n    fn update_references(&mut self, current_timestamp: i64) -> Result<()> {\n        let v_params = &mut self.v_parameters;\n        let s_params = &self.parameters;\n\n        let elapsed = current_timestamp\n            .checked_sub(v_params.last_update_timestamp)\n            .context(\"overflow\")?;\n\n        // Not high frequency trade\n        if elapsed >= s_params.filter_period as i64 {\n            // Update active id of last transaction\n            v_params.index_reference = self.active_id;\n            // filter period < t < decay_period. Decay time window.\n            if elapsed < s_params.decay_period as i64 {\n                let volatility_reference = v_params\n                    .volatility_accumulator\n                    .checked_mul(s_params.reduction_factor as u32)\n                    .context(\"overflow\")?\n                    .checked_div(BASIS_POINT_MAX as u32)\n                    .context(\"overflow\")?;\n\n                v_params.volatility_reference = volatility_reference;\n            }\n            // Out of decay time window\n            else {\n                v_params.volatility_reference = 0;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn update_volatility_accumulator(&mut self) -> Result<()> {\n        let v_params = &mut self.v_parameters;\n        let s_params = &self.parameters;\n\n        let delta_id = i64::from(v_params.index_reference)\n            .checked_sub(self.active_id.into())\n            .context(\"overflow\")?\n            .unsigned_abs();\n\n        let volatility_accumulator = u64::from(v_params.volatility_reference)\n            .checked_add(\n                delta_id\n                    .checked_mul(BASIS_POINT_MAX as u64)\n                    .context(\"overflow\")?,\n            )\n            .context(\"overflow\")?;\n\n        v_params.volatility_accumulator = std::cmp::min(\n            volatility_accumulator,\n            s_params.max_volatility_accumulator.into(),\n        )\n        .try_into()\n        .context(\"overflow\")?;\n\n        Ok(())\n    }\n\n    fn get_base_fee(&self) -> Result<u128> {\n        Ok(u128::from(self.parameters.base_factor)\n            .checked_mul(self.bin_step.into())\n            .context(\"overflow\")?\n            .checked_mul(10u128)\n            .context(\"overflow\")?\n            .checked_mul(10u128.pow(self.parameters.base_fee_power_factor.into()))\n            .context(\"overflow\")?)\n    }\n\n    fn get_variable_fee(&self) -> Result<u128> {\n        self.compute_variable_fee(self.v_parameters.volatility_accumulator)\n    }\n\n    fn compute_variable_fee(&self, volatility_accumulator: u32) -> Result<u128> {\n        if self.parameters.variable_fee_control > 0 {\n            let volatility_accumulator: u128 = volatility_accumulator.into();\n            let bin_step: u128 = self.bin_step.into();\n            let variable_fee_control: u128 = self.parameters.variable_fee_control.into();\n\n            let square_vfa_bin = volatility_accumulator\n                .checked_mul(bin_step)\n                .context(\"overflow\")?\n                .checked_pow(2)\n                .context(\"overflow\")?;\n\n            let v_fee = variable_fee_control\n                .checked_mul(square_vfa_bin)\n                .context(\"overflow\")?;\n\n            let scaled_v_fee = v_fee\n                .checked_add(99_999_999_999)\n                .context(\"overflow\")?\n                .checked_div(100_000_000_000)\n                .context(\"overflow\")?;\n\n            return Ok(scaled_v_fee);\n        }\n\n        Ok(0)\n    }\n\n    fn get_total_fee(&self) -> Result<u128> {\n        let total_fee_rate = self\n            .get_base_fee()?\n            .checked_add(self.get_variable_fee()?)\n            .context(\"overflow\")?;\n        let total_fee_rate_cap = std::cmp::min(total_fee_rate, MAX_FEE_RATE.into());\n        Ok(total_fee_rate_cap)\n    }\n\n    fn compute_fee(&self, amount: u64) -> Result<u64> {\n        let total_fee_rate = self.get_total_fee()?;\n        let denominator = u128::from(FEE_PRECISION)\n            .checked_sub(total_fee_rate)\n            .context(\"overflow\")?;\n\n        // Ceil division\n        let fee = u128::from(amount)\n            .checked_mul(total_fee_rate)\n            .context(\"overflow\")?\n            .checked_add(denominator)\n            .context(\"overflow\")?\n            .checked_sub(1)\n            .context(\"overflow\")?;\n\n        let scaled_down_fee = fee.checked_div(denominator).context(\"overflow\")?;\n\n        Ok(scaled_down_fee.try_into().context(\"overflow\")?)\n    }\n\n    fn advance_active_bin(&mut self, swap_for_y: bool) -> Result<()> {\n        let next_active_bin_id = if swap_for_y {\n            self.active_id.checked_sub(1)\n        } else {\n            self.active_id.checked_add(1)\n        }\n        .context(\"overflow\")?;\n\n        ensure!(\n            next_active_bin_id >= MIN_BIN_ID && next_active_bin_id <= MAX_BIN_ID,\n            \"Insufficient liquidity\"\n        );\n\n        self.active_id = next_active_bin_id;\n\n        Ok(())\n    }\n\n    fn compute_protocol_fee(&self, fee_amount: u64) -> Result<u64> {\n        let protocol_fee = u128::from(fee_amount)\n            .checked_mul(self.parameters.protocol_share.into())\n            .context(\"overflow\")?\n            .checked_div(BASIS_POINT_MAX as u128)\n            .context(\"overflow\")?;\n\n        Ok(protocol_fee.try_into().context(\"overflow\")?)\n    }\n\n    fn compute_fee_from_amount(&self, amount_with_fees: u64) -> Result<u64> {\n        let total_fee_rate = self.get_total_fee()?;\n\n        let fee_amount = u128::from(amount_with_fees)\n            .checked_mul(total_fee_rate)\n            .context(\"overflow\")?\n            .checked_add((FEE_PRECISION - 1).into())\n            .context(\"overflow\")?;\n\n        let scaled_down_fee = fee_amount\n            .checked_div(FEE_PRECISION.into())\n            .context(\"overflow\")?;\n\n        Ok(scaled_down_fee.try_into().context(\"overflow\")?)\n    }\n\n    fn bitmap_range() -> (i32, i32) {\n        (-BIN_ARRAY_BITMAP_SIZE, BIN_ARRAY_BITMAP_SIZE - 1)\n    }\n\n    fn is_overflow_default_bin_array_bitmap(&self, bin_array_index: i32) -> bool {\n        let (min_bitmap_id, max_bitmap_id) = Self::bitmap_range();\n        bin_array_index > max_bitmap_id || bin_array_index < min_bitmap_id\n    }\n\n    fn get_bin_array_offset(bin_array_index: i32) -> usize {\n        (bin_array_index + BIN_ARRAY_BITMAP_SIZE) as usize\n    }\n\n    fn next_bin_array_index_with_liquidity_internal(\n        &self,\n        swap_for_y: bool,\n        start_array_index: i32,\n    ) -> Result<(i32, bool)> {\n        let bin_array_bitmap = U1024::from_limbs(self.bin_array_bitmap);\n        let array_offset: usize = Self::get_bin_array_offset(start_array_index);\n        let (min_bitmap_id, max_bitmap_id) = LbPair::bitmap_range();\n        if swap_for_y {\n            let bitmap_range: usize = max_bitmap_id\n                .checked_sub(min_bitmap_id)\n                .context(\"overflow\")?\n                .try_into()\n                .context(\"overflow\")?;\n            let offset_bit_map =\n                bin_array_bitmap.shl(bitmap_range.checked_sub(array_offset).context(\"overflow\")?);\n\n            if offset_bit_map.eq(&U1024::ZERO) {\n                return Ok((min_bitmap_id.checked_sub(1).context(\"overflow\")?, false));\n            } else {\n                let next_bit = offset_bit_map.leading_zeros();\n                return Ok((\n                    start_array_index\n                        .checked_sub(next_bit as i32)\n                        .context(\"overflow\")?,\n                    true,\n                ));\n            }\n        } else {\n            let offset_bit_map = bin_array_bitmap.shr(array_offset);\n            if offset_bit_map.eq(&U1024::ZERO) {\n                return Ok((max_bitmap_id.checked_add(1).context(\"overflow\")?, false));\n            } else {\n                let next_bit = offset_bit_map.trailing_zeros();\n                return Ok((\n                    start_array_index\n                        .checked_add(next_bit as i32)\n                        .context(\"overflow\")?,\n                    true,\n                ));\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "commons/src/extensions/mod.rs",
    "content": "pub mod lb_pair;\npub use lb_pair::*;\n\npub mod bin_array;\npub use bin_array::*;\n\npub mod bin;\npub use bin::*;\n\npub mod bin_array_bitmap;\npub use bin_array_bitmap::*;\n\npub mod position;\npub use position::*;\n"
  },
  {
    "path": "commons/src/extensions/position.rs",
    "content": "use crate::*;\nuse solana_sdk::{instruction::AccountMeta, pubkey::Pubkey};\n\npub trait PositionExtension {\n    fn get_bin_array_indexes_bound(&self) -> Result<(i32, i32)>;\n    fn get_bin_array_keys_coverage(&self) -> Result<Vec<Pubkey>>;\n    fn get_bin_array_accounts_meta_coverage(&self) -> Result<Vec<AccountMeta>>;\n\n    fn get_bin_array_indexes_bound_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<(i32, i32)>;\n\n    fn get_bin_array_keys_coverage_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<Vec<Pubkey>>;\n\n    fn get_bin_array_accounts_meta_coverage_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<Vec<AccountMeta>>;\n\n    fn is_empty(&self) -> bool;\n}\n\nimpl PositionExtension for PositionV2 {\n    fn get_bin_array_indexes_bound(&self) -> Result<(i32, i32)> {\n        self.get_bin_array_indexes_bound_by_chunk(self.lower_bin_id, self.upper_bin_id)\n    }\n\n    fn get_bin_array_indexes_bound_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<(i32, i32)> {\n        ensure!(lower_bin_id >= self.lower_bin_id && upper_bin_id <= self.upper_bin_id);\n        let lower_bin_array_index = BinArray::bin_id_to_bin_array_index(lower_bin_id)?;\n        let upper_bin_array_index = lower_bin_array_index + 1;\n        Ok((lower_bin_array_index, upper_bin_array_index))\n    }\n\n    fn get_bin_array_keys_coverage(&self) -> Result<Vec<Pubkey>> {\n        self.get_bin_array_keys_coverage_by_chunk(self.lower_bin_id, self.upper_bin_id)\n    }\n\n    fn get_bin_array_keys_coverage_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<Vec<Pubkey>> {\n        let (lower_bin_array_index, upper_bin_array_index) =\n            self.get_bin_array_indexes_bound_by_chunk(lower_bin_id, upper_bin_id)?;\n        let mut bin_array_keys = Vec::new();\n        for bin_array_index in lower_bin_array_index..=upper_bin_array_index {\n            bin_array_keys.push(derive_bin_array_pda(self.lb_pair, bin_array_index.into()).0);\n        }\n        Ok(bin_array_keys)\n    }\n\n    fn get_bin_array_accounts_meta_coverage(&self) -> Result<Vec<AccountMeta>> {\n        self.get_bin_array_accounts_meta_coverage_by_chunk(self.lower_bin_id, self.upper_bin_id)\n    }\n\n    fn get_bin_array_accounts_meta_coverage_by_chunk(\n        &self,\n        lower_bin_id: i32,\n        upper_bin_id: i32,\n    ) -> Result<Vec<AccountMeta>> {\n        let bin_array_keys =\n            self.get_bin_array_keys_coverage_by_chunk(lower_bin_id, upper_bin_id)?;\n        Ok(bin_array_keys\n            .into_iter()\n            .map(|key| AccountMeta::new(key, false))\n            .collect())\n    }\n\n    fn is_empty(&self) -> bool {\n        for i in 0..self.liquidity_shares.len() {\n            if self.liquidity_shares[i] != 0 {\n                return false;\n            }\n\n            if self.fee_infos[i].fee_x_pending != 0 || self.fee_infos[i].fee_y_pending != 0 {\n                return false;\n            }\n\n            for pending_reward in self.reward_infos[i].reward_pendings {\n                if pending_reward != 0 {\n                    return false;\n                }\n            }\n        }\n\n        true\n    }\n}\n"
  },
  {
    "path": "commons/src/lib.rs",
    "content": "use anchor_lang::prelude::declare_program;\nuse anyhow::*;\n\ndeclare_program!(dlmm);\n\nuse dlmm::accounts::*;\nuse dlmm::types::*;\n\npub mod constants;\npub use constants::*;\n\npub mod conversions;\npub use conversions::*;\n\npub mod extensions;\npub use extensions::*;\n\npub mod pda;\npub use pda::*;\n\npub mod quote;\npub use quote::*;\n\npub mod seeds;\npub use seeds::*;\n\npub mod math;\npub use math::*;\n\npub mod typedefs;\npub use typedefs::*;\n\npub mod rpc_client_extension;\n\npub mod account_filters;\npub use account_filters::*;\n\npub mod token_2022;\npub use token_2022::*;\n"
  },
  {
    "path": "commons/src/math/mod.rs",
    "content": "pub mod price_math;\npub use price_math::*;\n\npub mod u64x64_math;\npub use u64x64_math::*;\n\npub mod u128x128_math;\npub use u128x128_math::*;\n\npub mod utils;\npub use utils::*;\n"
  },
  {
    "path": "commons/src/math/price_math.rs",
    "content": "use crate::*;\n\npub fn get_price_from_id(active_id: i32, bin_step: u16) -> Result<u128> {\n    let bps = u128::from(bin_step)\n        .checked_shl(SCALE_OFFSET.into())\n        .context(\"overflow\")?\n        .checked_div(BASIS_POINT_MAX as u128)\n        .context(\"overflow\")?;\n\n    let base = ONE.checked_add(bps).context(\"overflow\")?;\n\n    pow(base, active_id).context(\"overflow\")\n}\n"
  },
  {
    "path": "commons/src/math/u128x128_math.rs",
    "content": "use crate::Rounding;\nuse ruint::aliases::U256;\n\n/// (x * y) / denominator\npub fn mul_div(x: u128, y: u128, denominator: u128, rounding: Rounding) -> Option<u128> {\n    if denominator == 0 {\n        return None;\n    }\n\n    let x = U256::from(x);\n    let y = U256::from(y);\n    let denominator = U256::from(denominator);\n\n    let prod = x.checked_mul(y)?;\n\n    match rounding {\n        Rounding::Up => prod.div_ceil(denominator).try_into().ok(),\n        Rounding::Down => {\n            let (quotient, _) = prod.div_rem(denominator);\n            quotient.try_into().ok()\n        }\n    }\n}\n\n/// (x * y) >> offset\n#[inline]\npub fn mul_shr(x: u128, y: u128, offset: u8, rounding: Rounding) -> Option<u128> {\n    let denominator = 1u128.checked_shl(offset.into())?;\n    mul_div(x, y, denominator, rounding)\n}\n\n/// (x << offset) / y\n#[inline]\npub fn shl_div(x: u128, y: u128, offset: u8, rounding: Rounding) -> Option<u128> {\n    let scale = 1u128.checked_shl(offset.into())?;\n    mul_div(x, scale, y, rounding)\n}\n"
  },
  {
    "path": "commons/src/math/u64x64_math.rs",
    "content": "// Precision when converting from decimal to fixed point. Or the other way around. 10^12\npub const PRECISION: u128 = 1_000_000_000_000;\n\n// Number of bits to scale. This will decide the position of the radix point.\npub const SCALE_OFFSET: u8 = 64;\n\n// Where does this value come from ?\n// When smallest bin is used (1 bps), the maximum of bin limit is 887272 (Check: https://docs.traderjoexyz.com/concepts/bin-math).\n// But in solana, the token amount is represented in 64 bits, therefore, it will be (1 + 0.0001)^n < 2 ** 64, solve for n, n ~= 443636\n// Then we calculate bits needed to represent 443636 exponential, 2^n >= 443636, ~= 19\n// If we convert 443636 to binary form, it will be 1101100010011110100 (19 bits).\n// Which, the 19 bits are the bits the binary exponential will loop through.\n// The 20th bit will be 0x80000,  which the exponential already > the maximum number of bin Q64.64 can support\nconst MAX_EXPONENTIAL: u32 = 0x80000; // 1048576\n\n// 1.0000... representation of 64x64\npub const ONE: u128 = 1u128 << SCALE_OFFSET;\n\npub fn pow(base: u128, exp: i32) -> Option<u128> {\n    // If exponent is negative. We will invert the result later by 1 / base^exp.abs()\n    let mut invert = exp.is_negative();\n\n    // When exponential is 0, result will always be 1\n    if exp == 0 {\n        return Some(1u128 << 64);\n    }\n\n    // Make the exponential positive. Which will compute the result later by 1 / base^exp\n    let exp: u32 = if invert { exp.abs() as u32 } else { exp as u32 };\n\n    // No point to continue the calculation as it will overflow the maximum value Q64.64 can support\n    if exp >= MAX_EXPONENTIAL {\n        return None;\n    }\n\n    let mut squared_base = base;\n    let mut result = ONE;\n\n    // When multiply the base twice, the number of bits double from 128 -> 256, which overflow.\n    // The trick here is to inverse the calculation, which make the upper 64 bits (number bits) to be 0s.\n    // For example:\n    // let base = 1.001, exp = 5\n    // let neg = 1 / (1.001 ^ 5)\n    // Inverse the neg: 1 / neg\n    // By using a calculator, you will find out that 1.001^5 == 1 / (1 / 1.001^5)\n    if squared_base >= result {\n        // This inverse the base: 1 / base\n        squared_base = u128::MAX.checked_div(squared_base)?;\n        // If exponent is negative, the above already inverted the result. Therefore, at the end of the function, we do not need to invert again.\n        invert = !invert;\n    }\n\n    // The following code is equivalent to looping through each binary value of the exponential.\n    // As explained in MAX_EXPONENTIAL, 19 exponential bits are enough to covert the full bin price.\n    // Therefore, there will be 19 if statements, which similar to the following pseudo code.\n    /*\n        let mut result = 1;\n        while exponential > 0 {\n            if exponential & 1 > 0 {\n                result *= base;\n            }\n            base *= base;\n            exponential >>= 1;\n        }\n    */\n\n    // From right to left\n    // squared_base = 1 * base^1\n    // 1st bit is 1\n    if exp & 0x1 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    // squared_base = base^2\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    // 2nd bit is 1\n    if exp & 0x2 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    // Example:\n    // If the base is 1.001, exponential is 3. Binary form of 3 is ..0011. The last 2 1's bit fulfill the above 2 bitwise condition.\n    // The result will be 1 * base^1 * base^2 == base^3. The process continues until reach the 20th bit\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x4 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x8 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x10 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x20 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x40 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x80 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x100 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x200 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x400 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x800 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x1000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x2000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x4000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x8000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x10000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x20000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    squared_base = (squared_base.checked_mul(squared_base)?) >> SCALE_OFFSET;\n    if exp & 0x40000 > 0 {\n        result = (result.checked_mul(squared_base)?) >> SCALE_OFFSET\n    }\n\n    // Stop here as the next is 20th bit, which > MAX_EXPONENTIAL\n    if result == 0 {\n        return None;\n    }\n\n    if invert {\n        result = u128::MAX.checked_div(result)?;\n    }\n\n    Some(result)\n}\n"
  },
  {
    "path": "commons/src/math/utils.rs",
    "content": "use crate::*;\nuse num_traits::FromPrimitive;\n\n#[inline]\npub fn safe_mul_shr_cast<T: FromPrimitive>(\n    x: u128,\n    y: u128,\n    offset: u8,\n    rounding: Rounding,\n) -> Result<T> {\n    T::from_u128(mul_shr(x, y, offset, rounding).context(\"overflow\")?).context(\"overflow\")\n}\n\n#[inline]\npub fn safe_shl_div_cast<T: FromPrimitive>(\n    x: u128,\n    y: u128,\n    offset: u8,\n    rounding: Rounding,\n) -> Result<T> {\n    T::from_u128(shl_div(x, y, offset, rounding).context(\"overflow\")?).context(\"overflow\")\n}\n\npub fn safe_mul_div_cast<T: FromPrimitive>(\n    x: u128,\n    y: u128,\n    denominator: u128,\n    rounding: Rounding,\n) -> Result<T> {\n    T::from_u128(mul_div(x, y, denominator, rounding).context(\"overflow\")?).context(\"overflow\")\n}\n"
  },
  {
    "path": "commons/src/pda.rs",
    "content": "use super::seeds::*;\nuse crate::*;\nuse anchor_client::solana_sdk::pubkey::Pubkey;\nuse std::{cmp::max, cmp::min};\n\npub fn derive_lb_pair_with_preset_parameter_key(\n    preset_parameter: Pubkey,\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            preset_parameter.as_ref(),\n            min(token_x_mint, token_y_mint).as_ref(),\n            max(token_x_mint, token_y_mint).as_ref(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_lb_pair_pda2(\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n    bin_step: u16,\n    base_factor: u16,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            min(token_x_mint, token_y_mint).as_ref(),\n            max(token_x_mint, token_y_mint).as_ref(),\n            &bin_step.to_le_bytes(),\n            &base_factor.to_le_bytes(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_customizable_permissionless_lb_pair(\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            ILM_BASE_KEY.as_ref(),\n            min(token_x_mint, token_y_mint).as_ref(),\n            max(token_x_mint, token_y_mint).as_ref(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_permission_lb_pair_pda(\n    base: Pubkey,\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n    bin_step: u16,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            base.as_ref(),\n            min(token_x_mint, token_y_mint).as_ref(),\n            max(token_x_mint, token_y_mint).as_ref(),\n            &bin_step.to_le_bytes(),\n        ],\n        &dlmm::ID,\n    )\n}\n\n#[deprecated]\npub fn derive_lb_pair_pda(\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n    bin_step: u16,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            min(token_x_mint, token_y_mint).as_ref(),\n            max(token_x_mint, token_y_mint).as_ref(),\n            &bin_step.to_le_bytes(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_position_pda(\n    lb_pair: Pubkey,\n    base: Pubkey,\n    lower_bin_id: i32,\n    width: i32,\n) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            POSITION,\n            lb_pair.as_ref(),\n            base.as_ref(),\n            lower_bin_id.to_le_bytes().as_ref(),\n            width.to_le_bytes().as_ref(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_oracle_pda(lb_pair: Pubkey) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[ORACLE, lb_pair.as_ref()], &dlmm::ID)\n}\n\npub fn derive_bin_array_pda(lb_pair: Pubkey, bin_array_index: i64) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[BIN_ARRAY, lb_pair.as_ref(), &bin_array_index.to_le_bytes()],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_bin_array_bitmap_extension(lb_pair: Pubkey) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[BIN_ARRAY_BITMAP_SEED, lb_pair.as_ref()], &dlmm::ID)\n}\n\npub fn derive_reserve_pda(token_mint: Pubkey, lb_pair: Pubkey) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[lb_pair.as_ref(), token_mint.as_ref()], &dlmm::ID)\n}\n\npub fn derive_reward_vault_pda(lb_pair: Pubkey, reward_index: u64) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[lb_pair.as_ref(), reward_index.to_le_bytes().as_ref()],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_event_authority_pda() -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[b\"__event_authority\"], &dlmm::ID)\n}\n\n#[deprecated]\npub fn derive_preset_parameter_pda(bin_step: u16) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[PRESET_PARAMETER, &bin_step.to_le_bytes()], &dlmm::ID)\n}\n\npub fn derive_preset_parameter_pda2(bin_step: u16, base_factor: u16) -> (Pubkey, u8) {\n    Pubkey::find_program_address(\n        &[\n            PRESET_PARAMETER,\n            &bin_step.to_le_bytes(),\n            &base_factor.to_le_bytes(),\n        ],\n        &dlmm::ID,\n    )\n}\n\npub fn derive_preset_parameter_pda_v2(index: u16) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[PRESET_PARAMETER2, &index.to_le_bytes()], &dlmm::ID)\n}\n\npub fn derive_token_badge_pda(mint: Pubkey) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[TOKEN_BADGE, mint.as_ref()], &dlmm::ID)\n}\n\npub fn derive_claim_protocol_fee_operator_pda(operator: Pubkey) -> (Pubkey, u8) {\n    Pubkey::find_program_address(&[CLAIM_PROTOCOL_FEE_OPERATOR, operator.as_ref()], &dlmm::ID)\n}\n"
  },
  {
    "path": "commons/src/quote.rs",
    "content": "use crate::*;\nuse anchor_client::solana_sdk::pubkey::Pubkey;\nuse core::result::Result::Ok;\nuse solana_sdk::{account::Account, clock::Clock};\nuse std::collections::HashMap;\n\n#[derive(Debug)]\npub struct SwapExactInQuote {\n    pub amount_out: u64,\n    pub fee: u64,\n}\n\n#[derive(Debug)]\npub struct SwapExactOutQuote {\n    pub amount_in: u64,\n    pub fee: u64,\n}\n\nfn validate_swap_activation(\n    lb_pair: &LbPair,\n    current_timestamp: u64,\n    current_slot: u64,\n) -> Result<()> {\n    ensure!(\n        lb_pair.status()?.eq(&PairStatus::Enabled),\n        \"Pair is disabled\"\n    );\n\n    let pair_type = lb_pair.pair_type()?;\n    if pair_type.eq(&PairType::Permission) || pair_type.eq(&PairType::CustomizablePermissionless) {\n        let activation_type = lb_pair.activation_type()?;\n        let current_point = match activation_type {\n            ActivationType::Slot => current_slot,\n            ActivationType::Timestamp => current_timestamp,\n        };\n\n        ensure!(\n            current_point >= lb_pair.activation_point,\n            \"Pair is disabled\"\n        );\n    }\n\n    Ok(())\n}\n\nfn shift_active_bin_if_empty_gap(\n    lb_pair: &mut LbPair,\n    active_bin_array: &BinArray,\n    swap_for_y: bool,\n) -> Result<()> {\n    let lb_pair_bin_array_index = BinArray::bin_id_to_bin_array_index(lb_pair.active_id)?;\n\n    if i64::from(lb_pair_bin_array_index) != active_bin_array.index {\n        if swap_for_y {\n            let (_, upper_bin_id) =\n                BinArray::get_bin_array_lower_upper_bin_id(active_bin_array.index as i32)?;\n            lb_pair.active_id = upper_bin_id;\n        } else {\n            let (lower_bin_id, _) =\n                BinArray::get_bin_array_lower_upper_bin_id(active_bin_array.index as i32)?;\n            lb_pair.active_id = lower_bin_id;\n        }\n    }\n\n    Ok(())\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn quote_exact_out(\n    lb_pair_pubkey: Pubkey,\n    lb_pair: &LbPair,\n    mut amount_out: u64,\n    swap_for_y: bool,\n    bin_arrays: HashMap<Pubkey, BinArray>,\n    bitmap_extension: Option<&BinArrayBitmapExtension>,\n    clock: &Clock,\n    mint_x_account: &Account,\n    mint_y_account: &Account,\n) -> Result<SwapExactOutQuote> {\n    let current_timestamp = clock.unix_timestamp as u64;\n    let current_slot = clock.slot;\n    let epoch = clock.epoch;\n\n    validate_swap_activation(lb_pair, current_timestamp, current_slot)?;\n\n    let mut lb_pair = *lb_pair;\n    lb_pair.update_references(current_timestamp as i64)?;\n\n    let mut total_amount_in: u64 = 0;\n    let mut total_fee: u64 = 0;\n\n    let (in_mint_account, out_mint_account) = if swap_for_y {\n        (mint_x_account, mint_y_account)\n    } else {\n        (mint_y_account, mint_x_account)\n    };\n\n    amount_out =\n        calculate_transfer_fee_included_amount(out_mint_account, amount_out, epoch)?.amount;\n\n    while amount_out > 0 {\n        let active_bin_array_pubkey = get_bin_array_pubkeys_for_swap(\n            lb_pair_pubkey,\n            &lb_pair,\n            bitmap_extension,\n            swap_for_y,\n            1,\n        )?\n        .pop()\n        .context(\"Pool out of liquidity\")?;\n\n        let mut active_bin_array = bin_arrays\n            .get(&active_bin_array_pubkey)\n            .cloned()\n            .context(\"Active bin array not found\")?;\n\n        shift_active_bin_if_empty_gap(&mut lb_pair, &active_bin_array, swap_for_y)?;\n\n        loop {\n            if !active_bin_array.is_bin_id_within_range(lb_pair.active_id)? || amount_out == 0 {\n                break;\n            }\n\n            lb_pair.update_volatility_accumulator()?;\n\n            let active_bin = active_bin_array.get_bin_mut(lb_pair.active_id)?;\n            let price = active_bin.get_or_store_bin_price(lb_pair.active_id, lb_pair.bin_step)?;\n\n            if !active_bin.is_empty(!swap_for_y) {\n                let bin_max_amount_out = active_bin.get_max_amount_out(swap_for_y);\n                if amount_out >= bin_max_amount_out {\n                    let max_amount_in = active_bin.get_max_amount_in(price, swap_for_y)?;\n                    let max_fee = lb_pair.compute_fee(max_amount_in)?;\n\n                    total_amount_in = total_amount_in\n                        .checked_add(max_amount_in)\n                        .context(\"MathOverflow\")?;\n\n                    total_fee = total_fee.checked_add(max_fee).context(\"MathOverflow\")?;\n\n                    amount_out = amount_out\n                        .checked_sub(bin_max_amount_out)\n                        .context(\"MathOverflow\")?;\n                } else {\n                    let amount_in = Bin::get_amount_in(amount_out, price, swap_for_y)?;\n                    let fee = lb_pair.compute_fee(amount_in)?;\n\n                    total_amount_in = total_amount_in\n                        .checked_add(amount_in)\n                        .context(\"MathOverflow\")?;\n\n                    total_fee = total_fee.checked_add(fee).context(\"MathOverflow\")?;\n\n                    amount_out = 0;\n                }\n            }\n\n            if amount_out > 0 {\n                lb_pair.advance_active_bin(swap_for_y)?;\n            }\n        }\n    }\n\n    total_amount_in = total_amount_in\n        .checked_add(total_fee)\n        .context(\"MathOverflow\")?;\n\n    total_amount_in =\n        calculate_transfer_fee_included_amount(in_mint_account, total_amount_in, epoch)?.amount;\n\n    Ok(SwapExactOutQuote {\n        amount_in: total_amount_in,\n        fee: total_fee,\n    })\n}\n\n#[allow(clippy::too_many_arguments)]\npub fn quote_exact_in(\n    lb_pair_pubkey: Pubkey,\n    lb_pair: &LbPair,\n    amount_in: u64,\n    swap_for_y: bool,\n    bin_arrays: HashMap<Pubkey, BinArray>,\n    bitmap_extension: Option<&BinArrayBitmapExtension>,\n    clock: &Clock,\n    mint_x_account: &Account,\n    mint_y_account: &Account,\n) -> Result<SwapExactInQuote> {\n    let current_timestamp = clock.unix_timestamp as u64;\n    let current_slot = clock.slot;\n    let epoch = clock.epoch;\n\n    validate_swap_activation(lb_pair, current_timestamp, current_slot)?;\n\n    let mut lb_pair = *lb_pair;\n    lb_pair.update_references(current_timestamp as i64)?;\n\n    let mut total_amount_out: u64 = 0;\n    let mut total_fee: u64 = 0;\n\n    let (in_mint_account, out_mint_account) = if swap_for_y {\n        (mint_x_account, mint_y_account)\n    } else {\n        (mint_y_account, mint_x_account)\n    };\n\n    let transfer_fee_excluded_amount_in =\n        calculate_transfer_fee_excluded_amount(in_mint_account, amount_in, epoch)?.amount;\n\n    let mut amount_left = transfer_fee_excluded_amount_in;\n\n    while amount_left > 0 {\n        let active_bin_array_pubkey = get_bin_array_pubkeys_for_swap(\n            lb_pair_pubkey,\n            &lb_pair,\n            bitmap_extension,\n            swap_for_y,\n            1,\n        )?\n        .pop()\n        .context(\"Pool out of liquidity\")?;\n\n        let mut active_bin_array = bin_arrays\n            .get(&active_bin_array_pubkey)\n            .cloned()\n            .context(\"Active bin array not found\")?;\n\n        shift_active_bin_if_empty_gap(&mut lb_pair, &active_bin_array, swap_for_y)?;\n\n        loop {\n            if !active_bin_array.is_bin_id_within_range(lb_pair.active_id)? || amount_left == 0 {\n                break;\n            }\n\n            lb_pair.update_volatility_accumulator()?;\n\n            let active_bin = active_bin_array.get_bin_mut(lb_pair.active_id)?;\n            let price = active_bin.get_or_store_bin_price(lb_pair.active_id, lb_pair.bin_step)?;\n\n            if !active_bin.is_empty(!swap_for_y) {\n                let SwapResult {\n                    amount_in_with_fees,\n                    amount_out,\n                    fee,\n                    ..\n                } = active_bin.swap(amount_left, price, swap_for_y, &lb_pair, None)?;\n\n                amount_left = amount_left\n                    .checked_sub(amount_in_with_fees)\n                    .context(\"MathOverflow\")?;\n\n                total_amount_out = total_amount_out\n                    .checked_add(amount_out)\n                    .context(\"MathOverflow\")?;\n                total_fee = total_fee.checked_add(fee).context(\"MathOverflow\")?;\n            }\n\n            if amount_left > 0 {\n                lb_pair.advance_active_bin(swap_for_y)?;\n            }\n        }\n    }\n\n    let transfer_fee_excluded_amount_out =\n        calculate_transfer_fee_excluded_amount(out_mint_account, total_amount_out, epoch)?.amount;\n\n    Ok(SwapExactInQuote {\n        amount_out: transfer_fee_excluded_amount_out,\n        fee: total_fee,\n    })\n}\n\npub fn get_bin_array_pubkeys_for_swap(\n    lb_pair_pubkey: Pubkey,\n    lb_pair: &LbPair,\n    bitmap_extension: Option<&BinArrayBitmapExtension>,\n    swap_for_y: bool,\n    take_count: u8,\n) -> Result<Vec<Pubkey>> {\n    let mut start_bin_array_idx = BinArray::bin_id_to_bin_array_index(lb_pair.active_id)?;\n    let mut bin_array_idx = vec![];\n    let increment = if swap_for_y { -1 } else { 1 };\n\n    loop {\n        if bin_array_idx.len() == take_count as usize {\n            break;\n        }\n\n        if lb_pair.is_overflow_default_bin_array_bitmap(start_bin_array_idx) {\n            let Some(bitmap_extension) = bitmap_extension else {\n                break;\n            };\n            let Ok((next_bin_array_idx, has_liquidity)) = bitmap_extension\n                .next_bin_array_index_with_liquidity(swap_for_y, start_bin_array_idx)\n            else {\n                // Out of search range. No liquidity.\n                break;\n            };\n            if has_liquidity {\n                bin_array_idx.push(next_bin_array_idx);\n                start_bin_array_idx = next_bin_array_idx + increment;\n            } else {\n                // Switch to internal bitmap\n                start_bin_array_idx = next_bin_array_idx;\n            }\n        } else {\n            let Ok((next_bin_array_idx, has_liquidity)) = lb_pair\n                .next_bin_array_index_with_liquidity_internal(swap_for_y, start_bin_array_idx)\n            else {\n                break;\n            };\n            if has_liquidity {\n                bin_array_idx.push(next_bin_array_idx);\n                start_bin_array_idx = next_bin_array_idx + increment;\n            } else {\n                // Switch to external bitmap\n                start_bin_array_idx = next_bin_array_idx;\n            }\n        }\n    }\n\n    let bin_array_pubkeys = bin_array_idx\n        .into_iter()\n        .map(|idx| derive_bin_array_pda(lb_pair_pubkey, idx.into()).0)\n        .collect();\n\n    Ok(bin_array_pubkeys)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use anchor_client::solana_client::rpc_response::RpcKeyedAccount;\n    use anchor_client::solana_sdk::clock::Clock;\n    use anchor_client::{\n        solana_client::nonblocking::rpc_client::RpcClient, solana_sdk::pubkey::Pubkey, Cluster,\n    };\n    use litesvm::LiteSVM;\n\n    pub const DLMM_PROGRAM_FILE_PATH: &str = \"../artifacts/lb_clmm.so\";\n\n    /// Get on chain clock\n    async fn get_clock(rpc_client: RpcClient) -> Result<Clock> {\n        let clock_account = rpc_client\n            .get_account(&anchor_client::solana_sdk::sysvar::clock::ID)\n            .await?;\n\n        let clock_state: Clock = bincode::deserialize(clock_account.data.as_ref())?;\n\n        Ok(clock_state)\n    }\n\n    #[tokio::test]\n    async fn test_swap_quote_exact_out() {\n        // RPC client. No gPA is required.\n        let rpc_client = RpcClient::new(Cluster::Mainnet.url().to_string());\n\n        let sol_usdc = Pubkey::from_str_const(\"HTvjzsfX3yU6BUodCjZ5vZkUrAxMDTrBs3CJaq43ashR\");\n\n        let lb_pair_account = rpc_client.get_account(&sol_usdc).await.unwrap();\n\n        let lb_pair: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n        let mut mint_accounts = rpc_client\n            .get_multiple_accounts(&[lb_pair.token_x_mint, lb_pair.token_y_mint])\n            .await\n            .unwrap();\n\n        let mint_x_account = mint_accounts[0].take().unwrap();\n        let mint_y_account = mint_accounts[1].take().unwrap();\n\n        // 3 bin arrays to left, and right is enough to cover most of the swap, and stay under 1.4m CU constraint.\n        // Get 3 bin arrays to the left from the active bin\n        let left_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(sol_usdc, &lb_pair, None, true, 3).unwrap();\n\n        // Get 3 bin arrays to the right the from active bin\n        let right_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(sol_usdc, &lb_pair, None, false, 3).unwrap();\n\n        // Fetch bin arrays\n        let bin_array_pubkeys = left_bin_array_pubkeys\n            .into_iter()\n            .chain(right_bin_array_pubkeys.into_iter())\n            .collect::<Vec<Pubkey>>();\n\n        let accounts = rpc_client\n            .get_multiple_accounts(&bin_array_pubkeys)\n            .await\n            .unwrap();\n\n        let bin_arrays = accounts\n            .into_iter()\n            .zip(bin_array_pubkeys.into_iter())\n            .map(|(account, key)| {\n                (\n                    key,\n                    bytemuck::pod_read_unaligned(&account.unwrap().data[8..]),\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        let usdc_token_multiplier = 1_000_000.0;\n        let sol_token_multiplier = 1_000_000_000.0;\n\n        let out_sol_amount = 1_000_000_000;\n        let clock = get_clock(rpc_client).await.unwrap();\n\n        let quote_result = quote_exact_out(\n            sol_usdc,\n            &lb_pair,\n            out_sol_amount,\n            false,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        let in_amount = quote_result.amount_in + quote_result.fee;\n\n        println!(\n            \"{} USDC -> exact 1 SOL\",\n            in_amount as f64 / usdc_token_multiplier\n        );\n\n        let quote_result = quote_exact_in(\n            sol_usdc,\n            &lb_pair,\n            in_amount,\n            false,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\n            \"{} USDC -> {} SOL\",\n            in_amount as f64 / usdc_token_multiplier,\n            quote_result.amount_out as f64 / sol_token_multiplier\n        );\n\n        let out_usdc_amount = 200_000_000;\n\n        let quote_result = quote_exact_out(\n            sol_usdc,\n            &lb_pair,\n            out_usdc_amount,\n            true,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        let in_amount = quote_result.amount_in + quote_result.fee;\n\n        println!(\n            \"{} SOL -> exact 200 USDC\",\n            in_amount as f64 / sol_token_multiplier\n        );\n\n        let quote_result = quote_exact_in(\n            sol_usdc,\n            &lb_pair,\n            in_amount,\n            true,\n            bin_arrays,\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\n            \"{} SOL -> {} USDC\",\n            in_amount as f64 / sol_token_multiplier,\n            quote_result.amount_out as f64 / usdc_token_multiplier\n        );\n    }\n\n    #[tokio::test]\n    async fn test_swap_quote_exact_in() {\n        // RPC client. No gPA is required.\n        let rpc_client = RpcClient::new(Cluster::Mainnet.url().to_string());\n\n        let sol_usdc = Pubkey::from_str_const(\"HTvjzsfX3yU6BUodCjZ5vZkUrAxMDTrBs3CJaq43ashR\");\n\n        let lb_pair_account = rpc_client.get_account(&sol_usdc).await.unwrap();\n\n        let lb_pair: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n        let mut mint_accounts = rpc_client\n            .get_multiple_accounts(&[lb_pair.token_x_mint, lb_pair.token_y_mint])\n            .await\n            .unwrap();\n\n        let mint_x_account = mint_accounts[0].take().unwrap();\n        let mint_y_account = mint_accounts[1].take().unwrap();\n\n        // 3 bin arrays to left, and right is enough to cover most of the swap, and stay under 1.4m CU constraint.\n        // Get 3 bin arrays to the left from the active bin\n        let left_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(sol_usdc, &lb_pair, None, true, 3).unwrap();\n\n        // Get 3 bin arrays to the right the from active bin\n        let right_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(sol_usdc, &lb_pair, None, false, 3).unwrap();\n\n        // Fetch bin arrays\n        let bin_array_pubkeys = left_bin_array_pubkeys\n            .into_iter()\n            .chain(right_bin_array_pubkeys.into_iter())\n            .collect::<Vec<Pubkey>>();\n\n        let accounts = rpc_client\n            .get_multiple_accounts(&bin_array_pubkeys)\n            .await\n            .unwrap();\n\n        let bin_arrays = accounts\n            .into_iter()\n            .zip(bin_array_pubkeys.into_iter())\n            .map(|(account, key)| {\n                (\n                    key,\n                    bytemuck::pod_read_unaligned(&account.unwrap().data[8..]),\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        // 1 SOL -> USDC\n        let in_sol_amount = 5_000_000_000;\n\n        let clock = get_clock(rpc_client).await.unwrap();\n\n        let quote_result = quote_exact_in(\n            sol_usdc,\n            &lb_pair,\n            in_sol_amount,\n            true,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\n            \"1 SOL -> {:?} USDC\",\n            quote_result.amount_out as f64 / 1_000_000.0\n        );\n\n        // 100 USDC -> SOL\n        let in_usdc_amount = 100_000_000;\n\n        let quote_result = quote_exact_in(\n            sol_usdc,\n            &lb_pair,\n            in_usdc_amount,\n            false,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\n            \"100 USDC -> {:?} SOL\",\n            quote_result.amount_out as f64 / 1_000_000_000.0\n        );\n    }\n\n    #[test]\n    fn test_swap_quote_infinite_loop() {\n        let test_pair = Pubkey::from_str_const(\"FJbEo74c2W4QLBBVUfUvi8VBWXtMdJVPuFpq2f6UV1iB\");\n        let associated_accounts_folder_path = format!(\"../artifacts/{}\", test_pair);\n\n        let mut svm = LiteSVM::new().with_sysvars();\n        let program_bytes = std::fs::read(DLMM_PROGRAM_FILE_PATH).unwrap();\n        svm.add_program(dlmm::ID, &program_bytes);\n\n        let accounts_dir = std::fs::read_dir(associated_accounts_folder_path).unwrap();\n        for entry in accounts_dir {\n            let account_data = std::fs::read_to_string(entry.unwrap().path()).unwrap();\n            let rpc_account: RpcKeyedAccount =\n                serde_json::from_str(&account_data).expect(\"Failed to deserialize account data\");\n            let account: anchor_client::solana_sdk::account::Account =\n                rpc_account.account.decode().unwrap();\n            let account_pubkey = Pubkey::from_str_const(&rpc_account.pubkey);\n\n            svm.set_account(account_pubkey, account.clone()).unwrap();\n        }\n\n        let lb_pair_account = svm.get_account(&test_pair).unwrap();\n        let lb_pair: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n        let left_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(test_pair, &lb_pair, None, true, 3).unwrap();\n\n        let right_bin_array_pubkeys =\n            get_bin_array_pubkeys_for_swap(test_pair, &lb_pair, None, false, 3).unwrap();\n\n        let bin_array_pubkeys = [left_bin_array_pubkeys, right_bin_array_pubkeys].concat();\n\n        let mut bin_arrays = HashMap::new();\n\n        for bin_array_pubkey in bin_array_pubkeys {\n            let bin_array_account = svm.get_account(&bin_array_pubkey).unwrap();\n            let bin_array: BinArray = bytemuck::pod_read_unaligned(&bin_array_account.data[8..]);\n            bin_arrays.insert(bin_array_pubkey, bin_array);\n        }\n\n        let in_base_amount = 5_000_000_000;\n        let clock: Clock = svm.get_sysvar();\n\n        let mint_x_account = svm.get_account(&lb_pair.token_x_mint).unwrap();\n        let mint_y_account = svm.get_account(&lb_pair.token_y_mint).unwrap();\n\n        // 1. Quote in ask\n        let quote_result = quote_exact_in(\n            test_pair,\n            &lb_pair,\n            in_base_amount,\n            true,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        );\n\n        assert!(quote_result.is_err());\n        let err = quote_result.unwrap_err();\n        assert_eq!(err.to_string(), \"Pool out of liquidity\");\n\n        // 2. Quote in bid\n        let in_quote_amount = 5_000_000_000;\n        let quote_result = quote_exact_in(\n            test_pair,\n            &lb_pair,\n            in_quote_amount,\n            false,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        );\n        assert!(quote_result.is_err());\n        let err = quote_result.unwrap_err();\n        assert_eq!(err.to_string(), \"Pool out of liquidity\");\n\n        // 3. Quote out ask\n        let out_quote_amount = 5_000_000_000;\n        let quote_result = quote_exact_out(\n            test_pair,\n            &lb_pair,\n            out_quote_amount,\n            true,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        );\n\n        assert!(quote_result.is_err());\n        let err = quote_result.unwrap_err();\n        assert_eq!(err.to_string(), \"Pool out of liquidity\");\n\n        // 4. Quote out bid\n        let out_base_amount = 5_000_000_000;\n        let quote_result = quote_exact_out(\n            test_pair,\n            &lb_pair,\n            out_base_amount,\n            false,\n            bin_arrays.clone(),\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        );\n\n        assert!(quote_result.is_err());\n        let err = quote_result.unwrap_err();\n        assert_eq!(err.to_string(), \"Pool out of liquidity\");\n    }\n}\n"
  },
  {
    "path": "commons/src/rpc_client_extension.rs",
    "content": "use crate::*;\nuse anchor_client::solana_client::nonblocking::rpc_client::RpcClient;\nuse async_trait::async_trait;\nuse solana_sdk::{account::Account, pubkey::Pubkey};\n\n#[async_trait]\npub trait RpcClientExtension {\n    async fn get_account_and_deserialize<T>(\n        &self,\n        pubkey: &Pubkey,\n        deserialize_fn: fn(Account) -> Result<T>,\n    ) -> Result<T>;\n}\n\n#[async_trait]\nimpl RpcClientExtension for RpcClient {\n    async fn get_account_and_deserialize<T>(\n        &self,\n        pubkey: &Pubkey,\n        deserialize_fn: fn(Account) -> Result<T>,\n    ) -> Result<T> {\n        let account = self.get_account(pubkey).await?;\n        let data = deserialize_fn(account)?;\n        Ok(data)\n    }\n}\n"
  },
  {
    "path": "commons/src/seeds.rs",
    "content": "use solana_sdk::pubkey;\nuse solana_sdk::pubkey::Pubkey;\n\npub const BIN_ARRAY: &[u8] = b\"bin_array\";\n\npub const ORACLE: &[u8] = b\"oracle\";\n\npub const BIN_ARRAY_BITMAP_SEED: &[u8] = b\"bitmap\";\n\npub const PRESET_PARAMETER: &[u8] = b\"preset_parameter\";\n\npub const PRESET_PARAMETER2: &[u8] = b\"preset_parameter2\";\n\npub const POSITION: &[u8] = b\"position\";\n\npub const ILM_BASE_KEY: Pubkey = pubkey!(\"MFGQxwAmB91SwuYX36okv2Qmdc9aMuHTwWGUrp4AtB1\");\n\npub const TOKEN_BADGE: &[u8] = b\"token_badge\";\n\npub const CLAIM_PROTOCOL_FEE_OPERATOR: &[u8] = b\"cf_operator\";\n"
  },
  {
    "path": "commons/src/token_2022.rs",
    "content": "use crate::*;\nuse anchor_client::solana_client::nonblocking::rpc_client::RpcClient;\nuse anchor_client::solana_client::rpc_client::RpcClient as BlockingRpcClient;\nuse anchor_spl::token_2022::spl_token_2022::extension;\nuse anchor_spl::token_2022::spl_token_2022::extension::transfer_fee::*;\nuse anchor_spl::{token::spl_token, token_2022::spl_token_2022::extension::*};\nuse solana_sdk::account::Account;\nuse solana_sdk::{instruction::AccountMeta, pubkey::Pubkey};\nuse spl_transfer_hook_interface::offchain::add_extra_account_metas_for_execute;\n\nconst ONE_IN_BASIS_POINTS: u128 = MAX_FEE_BASIS_POINTS as u128;\n\npub enum ActionType {\n    Liquidity,\n    Reward(usize),\n}\n\npub async fn get_potential_token_2022_related_ix_data_and_accounts(\n    lb_pair: &LbPair,\n    rpc_client: RpcClient,\n    action_type: ActionType,\n) -> Result<Option<(Vec<RemainingAccountsSlice>, Vec<AccountMeta>)>> {\n    let potential_token_2022_mints = match action_type {\n        ActionType::Liquidity => {\n            vec![\n                (lb_pair.token_x_mint, AccountsType::TransferHookX),\n                (lb_pair.token_y_mint, AccountsType::TransferHookY),\n            ]\n        }\n        ActionType::Reward(idx) => {\n            vec![(\n                lb_pair.reward_infos[idx].mint,\n                AccountsType::TransferHookReward,\n            )]\n        }\n    };\n\n    let mut slices = vec![];\n    let mut accounts = vec![];\n\n    for (mint, accounts_type) in potential_token_2022_mints {\n        let extra_account_metas =\n            get_extra_account_metas_for_transfer_hook(mint, RpcClient::new(rpc_client.url()))\n                .await?;\n\n        if !extra_account_metas.is_empty() {\n            slices.push(RemainingAccountsSlice {\n                accounts_type,\n                length: extra_account_metas.len() as u8,\n            });\n\n            accounts.extend(extra_account_metas);\n        }\n    }\n\n    if !slices.is_empty() {\n        Ok(Some((slices, accounts)))\n    } else {\n        Ok(None)\n    }\n}\n\npub async fn get_extra_account_metas_for_transfer_hook(\n    mint: Pubkey,\n    rpc_client: RpcClient,\n) -> Result<Vec<AccountMeta>> {\n    let mint_account = rpc_client.get_account(&mint).await?;\n    if mint_account.owner.eq(&spl_token::ID) {\n        return Ok(vec![]);\n    }\n\n    let mint_state =\n        StateWithExtensions::<anchor_spl::token_2022::spl_token_2022::state::Mint>::unpack(\n            mint_account.data.as_ref(),\n        )?;\n\n    if let Some(transfer_hook_program_id) = transfer_hook::get_program_id(&mint_state) {\n        let mut transfer_ix =\n            anchor_spl::token_2022::spl_token_2022::instruction::transfer_checked(\n                &mint_account.owner,\n                &Pubkey::default(),\n                &mint,\n                &Pubkey::default(),\n                &Pubkey::default(),\n                &[],\n                0,\n                mint_state.base.decimals,\n            )?;\n\n        let blocking_rpc_client = BlockingRpcClient::new(rpc_client.url());\n\n        let data_fetcher = |address: Pubkey| {\n            let account = blocking_rpc_client\n                .get_account(&address)\n                .map(|account| account.data);\n            async move {\n                std::result::Result::Ok::<Option<Vec<u8>>, Box<dyn std::error::Error + Send + Sync>>(\n                    account.ok(),\n                )\n            }\n        };\n\n        add_extra_account_metas_for_execute(\n            &mut transfer_ix,\n            &transfer_hook_program_id,\n            &Pubkey::default(),\n            &mint,\n            &Pubkey::default(),\n            &Pubkey::default(),\n            0,\n            data_fetcher,\n        )\n        .await\n        .map_err(|e| anyhow!(e))?;\n\n        // Skip 4, source, mint, destination, authority\n        let transfer_hook_required_accounts = transfer_ix.accounts[4..].to_vec();\n        return Ok(transfer_hook_required_accounts);\n    }\n\n    Ok(vec![])\n}\n\npub fn get_epoch_transfer_fee(mint_account: &Account, epoch: u64) -> Result<Option<TransferFee>> {\n    if mint_account.owner == spl_token::ID {\n        return Ok(None);\n    }\n\n    let token_mint_data = mint_account.data.as_ref();\n    let token_mint_unpacked = StateWithExtensions::<\n        anchor_spl::token_2022::spl_token_2022::state::Mint,\n    >::unpack(token_mint_data)?;\n\n    if let std::result::Result::Ok(transfer_fee_config) =\n        token_mint_unpacked.get_extension::<extension::transfer_fee::TransferFeeConfig>()\n    {\n        return Ok(Some(*transfer_fee_config.get_epoch_fee(epoch)));\n    }\n\n    Ok(None)\n}\n\n#[derive(Debug)]\npub struct TransferFeeExcludedAmount {\n    pub amount: u64,\n    pub transfer_fee: u64,\n}\n\npub fn calculate_transfer_fee_excluded_amount(\n    mint_account: &Account,\n    transfer_fee_included_amount: u64,\n    epoch: u64,\n) -> Result<TransferFeeExcludedAmount> {\n    if let Some(epoch_transfer_fee) = get_epoch_transfer_fee(mint_account, epoch)? {\n        let transfer_fee = epoch_transfer_fee\n            .calculate_fee(transfer_fee_included_amount)\n            .context(\"MathOverflow\")?;\n        let transfer_fee_excluded_amount = transfer_fee_included_amount\n            .checked_sub(transfer_fee)\n            .context(\"MathOverflow\")?;\n\n        return Ok(TransferFeeExcludedAmount {\n            amount: transfer_fee_excluded_amount,\n            transfer_fee,\n        });\n    }\n\n    Ok(TransferFeeExcludedAmount {\n        amount: transfer_fee_included_amount,\n        transfer_fee: 0,\n    })\n}\n\n#[derive(Debug)]\npub struct TransferFeeIncludedAmount {\n    pub amount: u64,\n    pub transfer_fee: u64,\n}\n\npub fn calculate_transfer_fee_included_amount(\n    mint_account: &Account,\n    transfer_fee_excluded_amount: u64,\n    epoch: u64,\n) -> Result<TransferFeeIncludedAmount> {\n    if transfer_fee_excluded_amount == 0 {\n        return Ok(TransferFeeIncludedAmount {\n            amount: 0,\n            transfer_fee: 0,\n        });\n    }\n\n    if let Some(epoch_transfer_fee) = get_epoch_transfer_fee(mint_account, epoch)? {\n        let transfer_fee: u64 =\n            if u16::from(epoch_transfer_fee.transfer_fee_basis_points) == MAX_FEE_BASIS_POINTS {\n                u64::from(epoch_transfer_fee.maximum_fee)\n            } else {\n                calculate_inverse_fee(&epoch_transfer_fee, transfer_fee_excluded_amount)\n                    .context(\"MathOverflow\")?\n            };\n\n        let transfer_fee_included_amount = transfer_fee_excluded_amount\n            .checked_add(transfer_fee)\n            .context(\"MathOverflow\")?;\n\n        return Ok(TransferFeeIncludedAmount {\n            amount: transfer_fee_included_amount,\n            transfer_fee,\n        });\n    }\n\n    Ok(TransferFeeIncludedAmount {\n        amount: transfer_fee_excluded_amount,\n        transfer_fee: 0,\n    })\n}\n\npub fn calculate_pre_fee_amount(transfer_fee: &TransferFee, post_fee_amount: u64) -> Option<u64> {\n    if post_fee_amount == 0 {\n        return Some(0);\n    }\n    let maximum_fee = u64::from(transfer_fee.maximum_fee);\n    let transfer_fee_basis_points = u16::from(transfer_fee.transfer_fee_basis_points) as u128;\n    if transfer_fee_basis_points == 0 {\n        Some(post_fee_amount)\n    } else if transfer_fee_basis_points == ONE_IN_BASIS_POINTS {\n        Some(maximum_fee.checked_add(post_fee_amount)?)\n    } else {\n        let numerator = (post_fee_amount as u128).checked_mul(ONE_IN_BASIS_POINTS)?;\n        let denominator = ONE_IN_BASIS_POINTS.checked_sub(transfer_fee_basis_points)?;\n        let raw_pre_fee_amount = numerator\n            .checked_add(denominator)?\n            .checked_sub(1)?\n            .checked_div(denominator)?;\n\n        if raw_pre_fee_amount.checked_sub(post_fee_amount as u128)? >= maximum_fee as u128 {\n            post_fee_amount.checked_add(maximum_fee)\n        } else {\n            u64::try_from(raw_pre_fee_amount).ok()\n        }\n    }\n}\n\npub fn calculate_inverse_fee(transfer_fee: &TransferFee, post_fee_amount: u64) -> Option<u64> {\n    let pre_fee_amount = calculate_pre_fee_amount(transfer_fee, post_fee_amount)?;\n    transfer_fee.calculate_fee(pre_fee_amount)\n}\n"
  },
  {
    "path": "commons/src/typedefs.rs",
    "content": "#[derive(Debug)]\npub struct SwapResult {\n    /// Amount of token swap into the bin\n    pub amount_in_with_fees: u64,\n    /// Amount of token swap out from the bin\n    pub amount_out: u64,\n    /// Swap fee, includes protocol fee\n    pub fee: u64,\n    /// Part of fee\n    pub protocol_fee_after_host_fee: u64,\n    /// Part of protocol fee\n    pub host_fee: u64,\n    /// Indicate whether we reach exact out amount\n    pub is_exact_out_amount: bool,\n}\n"
  },
  {
    "path": "commons/tests/integration/helpers/mod.rs",
    "content": "pub mod utils;\n"
  },
  {
    "path": "commons/tests/integration/helpers/utils.rs",
    "content": "use anchor_spl::associated_token::*;\nuse anchor_spl::token::spl_token;\nuse assert_matches::assert_matches;\nuse solana_program_test::BanksClient;\nuse solana_sdk::{\n    instruction::Instruction,\n    pubkey::Pubkey,\n    signature::{Keypair, Signer},\n    transaction::Transaction,\n};\npub async fn process_and_assert_ok(\n    instructions: &[Instruction],\n    payer: &Keypair,\n    signers: &[&Keypair],\n    banks_client: &mut BanksClient,\n) {\n    let recent_blockhash = banks_client.get_latest_blockhash().await.unwrap();\n\n    let mut all_signers = vec![payer];\n    all_signers.extend_from_slice(signers);\n\n    let tx = Transaction::new_signed_with_payer(\n        instructions,\n        Some(&payer.pubkey()),\n        &all_signers,\n        recent_blockhash,\n    );\n\n    let result = banks_client.process_transaction(tx).await.inspect_err(|e| {\n        println!(\"Transaction error: {}\", e);\n    });\n\n    assert_matches!(result, Ok(()));\n}\n\npub async fn get_or_create_ata(\n    payer: &Keypair,\n    token_mint: &Pubkey,\n    authority: &Pubkey,\n    banks_client: &mut BanksClient,\n) -> Pubkey {\n    let token_mint_owner = banks_client\n        .get_account(*token_mint)\n        .await\n        .ok()\n        .flatten()\n        .unwrap()\n        .owner;\n    let ata_address =\n        get_associated_token_address_with_program_id(authority, token_mint, &token_mint_owner);\n    let ata_account = banks_client.get_account(ata_address).await.unwrap();\n    if ata_account.is_none() {\n        create_associated_token_account(\n            payer,\n            token_mint,\n            authority,\n            &token_mint_owner,\n            banks_client,\n        )\n        .await;\n    }\n    ata_address\n}\n\npub async fn create_associated_token_account(\n    payer: &Keypair,\n    token_mint: &Pubkey,\n    authority: &Pubkey,\n    program_id: &Pubkey,\n    banks_client: &mut BanksClient,\n) {\n    println!(\"{}\", program_id);\n    let ins = vec![\n        spl_associated_token_account::instruction::create_associated_token_account(\n            &payer.pubkey(),\n            authority,\n            token_mint,\n            program_id,\n        ),\n    ];\n\n    process_and_assert_ok(&ins, payer, &[payer], banks_client).await;\n}\n\npub async fn warp_sol(\n    payer: &Keypair,\n    wallet: Pubkey,\n    amount: u64,\n    banks_client: &mut BanksClient,\n) {\n    let wsol_ata = spl_associated_token_account::get_associated_token_address(\n        &wallet,\n        &spl_token::native_mint::id(),\n    );\n\n    let create_wsol_ata_ix =\n        spl_associated_token_account::instruction::create_associated_token_account(\n            &payer.pubkey(),\n            &payer.pubkey(),\n            &spl_token::native_mint::id(),\n            &spl_token::id(),\n        );\n\n    let transfer_sol_ix =\n        solana_program::system_instruction::transfer(&payer.pubkey(), &wsol_ata, amount);\n\n    let sync_native_ix = spl_token::instruction::sync_native(&spl_token::id(), &wsol_ata).unwrap();\n\n    process_and_assert_ok(\n        &[create_wsol_ata_ix, transfer_sol_ix, sync_native_ix],\n        &payer,\n        &[&payer],\n        banks_client,\n    )\n    .await;\n}\n\npub async fn get_clock(banks_client: &mut BanksClient) -> solana_program::clock::Clock {\n    let clock_account = banks_client\n        .get_account(solana_program::sysvar::clock::id())\n        .await\n        .unwrap()\n        .unwrap();\n\n    let clock_state =\n        bincode::deserialize::<solana_program::clock::Clock>(clock_account.data.as_ref()).unwrap();\n\n    clock_state\n}\n"
  },
  {
    "path": "commons/tests/integration/main.rs",
    "content": "mod helpers;\nmod test_swap;\nmod test_swap_token2022;\n\nuse anchor_lang::*;\nuse anchor_spl::token::spl_token;\nuse anchor_spl::token_2022::spl_token_2022;\nuse anchor_spl::token_interface::*;\nuse commons::dlmm::accounts::*;\nuse commons::dlmm::types::*;\nuse commons::*;\nuse helpers::utils::*;\nuse solana_program_test::*;\nuse solana_sdk::instruction::{AccountMeta, Instruction};\nuse solana_sdk::native_token::LAMPORTS_PER_SOL;\nuse solana_sdk::pubkey::Pubkey;\nuse solana_sdk::signature::Signer;\nuse std::collections::HashMap;\n"
  },
  {
    "path": "commons/tests/integration/test_swap.rs",
    "content": "use crate::*;\n\nstruct SplTestPair {\n    lb_pair: Pubkey,\n    reserve_x: Pubkey,\n    reserve_y: Pubkey,\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n    oracle: Pubkey,\n    bin_array_1: Pubkey,\n    bin_array_2: Pubkey,\n}\n\nfn setup_spl_test_pair() -> (ProgramTest, SplTestPair) {\n    let mut test = ProgramTest::default();\n    test.prefer_bpf(true);\n    test.add_program(\"./tests/artifacts/lb_clmm_prod\", dlmm::ID, None);\n\n    let lb_pair = Pubkey::from_str_const(\"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig\");\n    let reserve_x = Pubkey::from_str_const(\"BmW4cCRpJwwL8maFB1AoAuEQf96t64Eq5gUvXikZardM\");\n    let reserve_y = Pubkey::from_str_const(\"FDZDrPtCjmSHeq14goCxp5pCJSRekSXY3XSgGz5Rvass\");\n    let token_x_mint = Pubkey::from_str_const(\"Df6yfrKC8kZE3KNkrHERKzAetSxbrWeniQfyJY4Jpump\");\n    let token_y_mint = anchor_spl::token::spl_token::native_mint::id();\n    let oracle = Pubkey::from_str_const(\"Fnkg415DEx72GSPooKUWTbPS9wzKucQe4qnvFrrvcZK2\");\n    let bin_array_1 = Pubkey::from_str_const(\"5Sm2ecMeqohRkNpFJPWSqHL1BkA7AEW4ck8TmdF1gD4t\");\n    let bin_array_2 = Pubkey::from_str_const(\"E6gur9Jw8675DCR7GpJVhoSrkruRgt8EdEVqLAc5RLUt\");\n\n    test.add_account_with_file_data(\n        lb_pair,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/lb_pair.bin\",\n    );\n\n    test.add_account_with_file_data(\n        oracle,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/oracle.bin\",\n    );\n\n    test.add_account_with_file_data(\n        bin_array_1,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/bin_array_1.bin\",\n    );\n\n    test.add_account_with_file_data(\n        bin_array_2,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/bin_array_2.bin\",\n    );\n\n    test.add_account_with_file_data(\n        token_x_mint,\n        10 * LAMPORTS_PER_SOL,\n        spl_token::id(),\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/token_x_mint.bin\",\n    );\n\n    test.add_account_with_file_data(\n        reserve_x,\n        10 * LAMPORTS_PER_SOL,\n        spl_token::id(),\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/reserve_x.bin\",\n    );\n\n    test.add_account_with_file_data(\n        reserve_y,\n        10 * LAMPORTS_PER_SOL,\n        spl_token::id(),\n        \"EtAdVRLFH22rjWh3mcUasKFF27WtHhsaCvK27tPFFWig/reserve_y.bin\",\n    );\n\n    (\n        test,\n        SplTestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    )\n}\n\n#[tokio::test]\nasync fn test_swap_exact_out() {\n    let (\n        test,\n        SplTestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    ) = setup_spl_test_pair();\n\n    let (mut banks_client, payer, _recent_blockhash) = test.start().await;\n\n    warp_sol(\n        &payer,\n        payer.pubkey(),\n        1 * LAMPORTS_PER_SOL,\n        &mut banks_client,\n    )\n    .await;\n\n    let user_token_in =\n        get_or_create_ata(&payer, &token_y_mint, &payer.pubkey(), &mut banks_client).await;\n\n    let user_token_out =\n        get_or_create_ata(&payer, &token_x_mint, &payer.pubkey(), &mut banks_client).await;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let lb_pair_account = banks_client\n        .get_account(lb_pair)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let lb_pair_state: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n    let bin_array_1_account = banks_client\n        .get_account(bin_array_1)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let bin_array_1_state: BinArray = bytemuck::pod_read_unaligned(&bin_array_1_account.data[8..]);\n\n    let bin_array_2_account = banks_client\n        .get_account(bin_array_2)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let bin_array_2_state: BinArray = bytemuck::pod_read_unaligned(&bin_array_2_account.data[8..]);\n\n    let mut bin_arrays = HashMap::new();\n    bin_arrays.insert(bin_array_1, bin_array_1_state);\n    bin_arrays.insert(bin_array_2, bin_array_2_state);\n\n    let clock = get_clock(&mut banks_client).await;\n\n    let out_amount = 1_000_000;\n\n    let mint_x_account = banks_client\n        .get_account(lb_pair_state.token_x_mint)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let mint_y_account = banks_client\n        .get_account(lb_pair_state.token_y_mint)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let quote_result = commons::quote::quote_exact_out(\n        lb_pair,\n        &lb_pair_state,\n        out_amount,\n        false,\n        bin_arrays,\n        None,\n        &clock,\n        &mint_x_account,\n        &mint_y_account,\n    )\n    .unwrap();\n\n    println!(\"quote_result {:?}\", quote_result);\n\n    let user_token_out_account_before = banks_client\n        .get_account(user_token_out)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_in_account_before = banks_client\n        .get_account(user_token_in)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_in_state_before =\n        TokenAccount::try_deserialize(&mut user_token_in_account_before.data.as_ref()).unwrap();\n\n    let user_token_out_state_before =\n        TokenAccount::try_deserialize(&mut user_token_out_account_before.data.as_ref()).unwrap();\n\n    let main_accounts = dlmm::client::accounts::SwapExactOut2 {\n        lb_pair,\n        oracle,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        user_token_in,\n        user_token_out,\n        token_x_mint,\n        token_y_mint,\n        host_fee_in: Some(dlmm::ID),\n        user: payer.pubkey(),\n        token_x_program: spl_token::id(),\n        token_y_program: spl_token::id(),\n        program: dlmm::ID,\n        event_authority,\n        memo_program: spl_memo::ID,\n    }\n    .to_account_metas(None);\n\n    let mut all_accounts = main_accounts.to_vec();\n\n    let mut remaining_accounts = vec![\n        AccountMeta::new(bin_array_1, false),\n        AccountMeta::new(bin_array_2, false),\n    ];\n    all_accounts.append(&mut remaining_accounts);\n\n    let swap_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts: all_accounts,\n        data: dlmm::client::args::SwapExactOut2 {\n            max_in_amount: quote_result.amount_in,\n            out_amount,\n            remaining_accounts_info: RemainingAccountsInfo { slices: vec![] },\n        }\n        .data(),\n    };\n\n    process_and_assert_ok(&[swap_ix], &payer, &[&payer], &mut banks_client).await;\n\n    let user_token_out_account_after = banks_client\n        .get_account(user_token_out)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_in_account_after = banks_client\n        .get_account(user_token_in)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_out_state_after =\n        TokenAccount::try_deserialize(&mut user_token_out_account_after.data.as_ref()).unwrap();\n\n    let user_token_in_state_after =\n        TokenAccount::try_deserialize(&mut user_token_in_account_after.data.as_ref()).unwrap();\n\n    assert_eq!(\n        user_token_in_state_before.amount - user_token_in_state_after.amount,\n        quote_result.amount_in\n    );\n\n    assert_eq!(\n        user_token_out_state_after.amount - user_token_out_state_before.amount,\n        out_amount\n    );\n}\n\n#[tokio::test]\nasync fn test_swap() {\n    let (\n        test,\n        SplTestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    ) = setup_spl_test_pair();\n\n    let (mut banks_client, payer, _recent_blockhash) = test.start().await;\n\n    let amount_in = 100_000;\n\n    warp_sol(&payer, payer.pubkey(), amount_in, &mut banks_client).await;\n\n    let user_token_in =\n        get_or_create_ata(&payer, &token_y_mint, &payer.pubkey(), &mut banks_client).await;\n\n    let user_token_out =\n        get_or_create_ata(&payer, &token_x_mint, &payer.pubkey(), &mut banks_client).await;\n\n    let (event_authority, _bump) = derive_event_authority_pda();\n\n    let lb_pair_account = banks_client\n        .get_account(lb_pair)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let lb_pair_state: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n    let bin_array_1_account = banks_client\n        .get_account(bin_array_1)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let bin_array_1_state = bytemuck::pod_read_unaligned(&bin_array_1_account.data[8..]);\n\n    let bin_array_2_account = banks_client\n        .get_account(bin_array_2)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let bin_array_2_state = bytemuck::pod_read_unaligned(&bin_array_2_account.data[8..]);\n\n    let mut bin_arrays = HashMap::new();\n    bin_arrays.insert(bin_array_1, bin_array_1_state);\n    bin_arrays.insert(bin_array_2, bin_array_2_state);\n\n    let clock = get_clock(&mut banks_client).await;\n\n    let mint_x_account = banks_client\n        .get_account(lb_pair_state.token_x_mint)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let mint_y_account = banks_client\n        .get_account(lb_pair_state.token_y_mint)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let quote_result = commons::quote::quote_exact_in(\n        lb_pair,\n        &lb_pair_state,\n        amount_in,\n        false,\n        bin_arrays,\n        None,\n        &clock,\n        &mint_x_account,\n        &mint_y_account,\n    )\n    .unwrap();\n\n    println!(\"quote_result {:?}\", quote_result);\n\n    let user_token_out_account_before = banks_client\n        .get_account(user_token_out)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_out_state_before =\n        TokenAccount::try_deserialize(&mut user_token_out_account_before.data.as_ref()).unwrap();\n\n    let main_accounts = dlmm::client::accounts::Swap2 {\n        lb_pair,\n        oracle,\n        bin_array_bitmap_extension: Some(dlmm::ID),\n        reserve_x,\n        reserve_y,\n        user_token_in,\n        user_token_out,\n        token_x_mint,\n        token_y_mint,\n        host_fee_in: Some(dlmm::ID),\n        user: payer.pubkey(),\n        token_x_program: spl_token::id(),\n        token_y_program: spl_token::id(),\n        program: dlmm::ID,\n        event_authority,\n        memo_program: spl_memo::id(),\n    }\n    .to_account_metas(None);\n\n    let mut all_accounts = main_accounts.to_vec();\n\n    let mut remaining_accounts = vec![\n        AccountMeta::new(bin_array_1, false),\n        AccountMeta::new(bin_array_2, false),\n    ];\n    all_accounts.append(&mut remaining_accounts);\n\n    let swap_ix = Instruction {\n        program_id: dlmm::ID,\n        accounts: all_accounts,\n        data: dlmm::client::args::Swap2 {\n            amount_in,\n            min_amount_out: 0,\n            remaining_accounts_info: RemainingAccountsInfo { slices: vec![] },\n        }\n        .data(),\n    };\n\n    process_and_assert_ok(&[swap_ix], &payer, &[&payer], &mut banks_client).await;\n\n    let user_token_out_account_after = banks_client\n        .get_account(user_token_out)\n        .await\n        .ok()\n        .flatten()\n        .unwrap();\n\n    let user_token_out_state_after =\n        TokenAccount::try_deserialize(&mut user_token_out_account_after.data.as_ref()).unwrap();\n\n    assert_eq!(\n        user_token_out_state_after.amount - user_token_out_state_before.amount,\n        quote_result.amount_out\n    );\n}\n"
  },
  {
    "path": "commons/tests/integration/test_swap_token2022.rs",
    "content": "use crate::*;\n\nstruct Token2022TestPair {\n    lb_pair: Pubkey,\n    reserve_x: Pubkey,\n    reserve_y: Pubkey,\n    token_x_mint: Pubkey,\n    token_y_mint: Pubkey,\n    oracle: Pubkey,\n    bin_array_1: Pubkey,\n    bin_array_2: Pubkey,\n}\n\nfn setup_token_2022_test_pair() -> (ProgramTest, Token2022TestPair) {\n    let mut test = ProgramTest::default();\n    test.prefer_bpf(true);\n    test.add_program(\"./tests/artifacts/lb_clmm_prod\", dlmm::ID, None);\n    test.add_program(\"./tests/artifacts/token_2022\", spl_token_2022::ID, None);\n\n    let lb_pair = Pubkey::from_str_const(\"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc\");\n    let reserve_x = Pubkey::from_str_const(\"HmAJViUS3iMSzuedDs1z4QxAPitnK8oNC6dwAaNrRTBE\");\n    let reserve_y = Pubkey::from_str_const(\"2LAbjR3C5pWMVKh7HUWyEZ6wwubHwHB6B91vu5jaB3mr\");\n    let token_x_mint = Pubkey::from_str_const(\"B4rGSdcBrmLEPUQXpZa91PMsRE3GqNcjLd6EMvM3yaj2\");\n    let token_y_mint = anchor_spl::token::spl_token::native_mint::ID;\n    let oracle = Pubkey::from_str_const(\"HeC6TwhrT9eusRp8wMWuswpMAp1eUmr4mUB5csYMPsjU\");\n    let bin_array_1 = Pubkey::from_str_const(\"4adaMF2BRtenYAtsQfJCYjR5NG3B1GU6twc7eosKr7rL\");\n    let bin_array_2 = Pubkey::from_str_const(\"9Tp5Ym4rH1sEmwkQcjVHyXvaY5zCwVGofYSdcH4WETVJ\");\n\n    test.add_account_with_file_data(\n        lb_pair,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/lb_pair.bin\",\n    );\n\n    test.add_account_with_file_data(\n        oracle,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/oracle.bin\",\n    );\n\n    test.add_account_with_file_data(\n        bin_array_1,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/bin_array_1.bin\",\n    );\n\n    test.add_account_with_file_data(\n        bin_array_2,\n        10 * LAMPORTS_PER_SOL,\n        dlmm::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/bin_array_2.bin\",\n    );\n\n    test.add_account_with_file_data(\n        token_x_mint,\n        10 * LAMPORTS_PER_SOL,\n        spl_token_2022::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/token_x_mint.bin\",\n    );\n\n    test.add_account_with_file_data(\n        reserve_x,\n        10 * LAMPORTS_PER_SOL,\n        spl_token_2022::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/reserve_x.bin\",\n    );\n\n    test.add_account_with_file_data(\n        reserve_y,\n        10 * LAMPORTS_PER_SOL,\n        spl_token::ID,\n        \"B5Eia4cE71tKuEDaqPHucJLG2fxySKyKzLMewd2nUvoc/reserve_y.bin\",\n    );\n\n    (\n        test,\n        Token2022TestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    )\n}\n\n#[tokio::test]\nasync fn test_swap_exact_out() {\n    let (\n        test,\n        Token2022TestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    ) = setup_token_2022_test_pair();\n\n    let (mut banks_client, payer, _recent_blockhash) = test.start().await;\n\n    warp_sol(\n        &payer,\n        payer.pubkey(),\n        1 * LAMPORTS_PER_SOL,\n        &mut banks_client,\n    )\n    .await;\n\n    for (in_mint, out_mint, out_amount) in [\n        (token_y_mint, token_x_mint, 10_000_000),\n        (token_x_mint, token_y_mint, 1_000_000),\n    ] {\n        let user_token_in =\n            get_or_create_ata(&payer, &in_mint, &payer.pubkey(), &mut banks_client).await;\n\n        let user_token_out =\n            get_or_create_ata(&payer, &out_mint, &payer.pubkey(), &mut banks_client).await;\n\n        let (event_authority, _bump) = derive_event_authority_pda();\n\n        let lb_pair_account = banks_client\n            .get_account(lb_pair)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let lb_pair_state: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n        let bin_array_1_account = banks_client\n            .get_account(bin_array_1)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let bin_array_1_state = bytemuck::pod_read_unaligned(&bin_array_1_account.data[8..]);\n\n        let bin_array_2_account = banks_client\n            .get_account(bin_array_2)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let bin_array_2_state = bytemuck::pod_read_unaligned(&bin_array_2_account.data[8..]);\n\n        let mut bin_arrays = HashMap::new();\n        bin_arrays.insert(bin_array_1, bin_array_1_state);\n        bin_arrays.insert(bin_array_2, bin_array_2_state);\n\n        let clock = get_clock(&mut banks_client).await;\n\n        let mint_x_account = banks_client\n            .get_account(lb_pair_state.token_x_mint)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let mint_y_account = banks_client\n            .get_account(lb_pair_state.token_y_mint)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let swap_for_y = out_mint == lb_pair_state.token_y_mint;\n\n        let quote_result = commons::quote::quote_exact_out(\n            lb_pair,\n            &lb_pair_state,\n            out_amount,\n            swap_for_y,\n            bin_arrays,\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\"quote_result {:?}\", quote_result);\n\n        let user_token_out_account_before = banks_client\n            .get_account(user_token_out)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_in_account_before = banks_client\n            .get_account(user_token_in)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_in_state_before =\n            TokenAccount::try_deserialize(&mut user_token_in_account_before.data.as_ref()).unwrap();\n\n        let user_token_out_state_before =\n            TokenAccount::try_deserialize(&mut user_token_out_account_before.data.as_ref())\n                .unwrap();\n\n        let main_accounts = dlmm::client::accounts::SwapExactOut2 {\n            lb_pair,\n            oracle,\n            bin_array_bitmap_extension: Some(dlmm::ID),\n            reserve_x,\n            reserve_y,\n            user_token_in,\n            user_token_out,\n            token_x_mint,\n            token_y_mint,\n            host_fee_in: Some(dlmm::ID),\n            user: payer.pubkey(),\n            token_x_program: spl_token_2022::ID,\n            token_y_program: spl_token::ID,\n            program: dlmm::ID,\n            event_authority,\n            memo_program: spl_memo::ID,\n        }\n        .to_account_metas(None);\n\n        let mut all_accounts = main_accounts.to_vec();\n\n        let mut remaining_accounts = vec![\n            AccountMeta::new(bin_array_1, false),\n            AccountMeta::new(bin_array_2, false),\n        ];\n        all_accounts.append(&mut remaining_accounts);\n\n        let swap_ix = Instruction {\n            program_id: dlmm::ID,\n            accounts: all_accounts,\n            data: dlmm::client::args::SwapExactOut2 {\n                max_in_amount: quote_result.amount_in,\n                out_amount,\n                remaining_accounts_info: RemainingAccountsInfo { slices: vec![] },\n            }\n            .data(),\n        };\n\n        process_and_assert_ok(&[swap_ix], &payer, &[&payer], &mut banks_client).await;\n\n        let user_token_out_account_after = banks_client\n            .get_account(user_token_out)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_in_account_after = banks_client\n            .get_account(user_token_in)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_out_state_after =\n            TokenAccount::try_deserialize(&mut user_token_out_account_after.data.as_ref()).unwrap();\n\n        let user_token_in_state_after =\n            TokenAccount::try_deserialize(&mut user_token_in_account_after.data.as_ref()).unwrap();\n\n        assert_eq!(\n            user_token_in_state_before.amount - user_token_in_state_after.amount,\n            quote_result.amount_in\n        );\n\n        assert_eq!(\n            user_token_out_state_after.amount - user_token_out_state_before.amount,\n            out_amount\n        );\n    }\n}\n\n#[tokio::test]\nasync fn test_swap() {\n    let (\n        test,\n        Token2022TestPair {\n            lb_pair,\n            reserve_x,\n            reserve_y,\n            token_x_mint,\n            token_y_mint,\n            oracle,\n            bin_array_1,\n            bin_array_2,\n        },\n    ) = setup_token_2022_test_pair();\n\n    let (mut banks_client, payer, _recent_blockhash) = test.start().await;\n\n    warp_sol(\n        &payer,\n        payer.pubkey(),\n        1 * LAMPORTS_PER_SOL,\n        &mut banks_client,\n    )\n    .await;\n\n    for (in_mint, out_mint, amount_in) in [\n        (token_y_mint, token_x_mint, 10_000_000),\n        (token_x_mint, token_y_mint, 1_000_000),\n    ] {\n        let user_token_in =\n            get_or_create_ata(&payer, &in_mint, &payer.pubkey(), &mut banks_client).await;\n\n        let user_token_out =\n            get_or_create_ata(&payer, &out_mint, &payer.pubkey(), &mut banks_client).await;\n\n        let (event_authority, _bump) = derive_event_authority_pda();\n\n        let lb_pair_account = banks_client\n            .get_account(lb_pair)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let lb_pair_state: LbPair = bytemuck::pod_read_unaligned(&lb_pair_account.data[8..]);\n\n        let bin_array_1_account = banks_client\n            .get_account(bin_array_1)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let bin_array_1_state = bytemuck::pod_read_unaligned(&bin_array_1_account.data[8..]);\n\n        let bin_array_2_account = banks_client\n            .get_account(bin_array_2)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let bin_array_2_state = bytemuck::pod_read_unaligned(&bin_array_2_account.data[8..]);\n\n        let mut bin_arrays = HashMap::new();\n        bin_arrays.insert(bin_array_1, bin_array_1_state);\n        bin_arrays.insert(bin_array_2, bin_array_2_state);\n\n        let clock = get_clock(&mut banks_client).await;\n\n        let mint_x_account = banks_client\n            .get_account(lb_pair_state.token_x_mint)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let mint_y_account = banks_client\n            .get_account(lb_pair_state.token_y_mint)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let swap_for_y = out_mint == lb_pair_state.token_y_mint;\n\n        let quote_result = commons::quote::quote_exact_in(\n            lb_pair,\n            &lb_pair_state,\n            amount_in,\n            swap_for_y,\n            bin_arrays,\n            None,\n            &clock,\n            &mint_x_account,\n            &mint_y_account,\n        )\n        .unwrap();\n\n        println!(\"quote_result {:?}\", quote_result);\n\n        let user_token_out_account_before = banks_client\n            .get_account(user_token_out)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_out_state_before =\n            TokenAccount::try_deserialize(&mut user_token_out_account_before.data.as_ref())\n                .unwrap();\n\n        let main_accounts = dlmm::client::accounts::Swap2 {\n            lb_pair,\n            oracle,\n            bin_array_bitmap_extension: Some(dlmm::ID),\n            reserve_x,\n            reserve_y,\n            user_token_in,\n            user_token_out,\n            token_x_mint,\n            token_y_mint,\n            host_fee_in: Some(dlmm::ID),\n            user: payer.pubkey(),\n            token_x_program: spl_token_2022::ID,\n            token_y_program: spl_token::ID,\n            program: dlmm::ID,\n            event_authority,\n            memo_program: spl_memo::ID,\n        }\n        .to_account_metas(None);\n\n        let mut all_accounts = main_accounts.to_vec();\n\n        let mut remaining_accounts = vec![\n            AccountMeta::new(bin_array_1, false),\n            AccountMeta::new(bin_array_2, false),\n        ];\n        all_accounts.append(&mut remaining_accounts);\n\n        let swap_ix = Instruction {\n            program_id: dlmm::ID,\n            accounts: all_accounts,\n            data: dlmm::client::args::Swap2 {\n                amount_in,\n                min_amount_out: quote_result.amount_out,\n                remaining_accounts_info: RemainingAccountsInfo { slices: vec![] },\n            }\n            .data(),\n        };\n\n        process_and_assert_ok(&[swap_ix], &payer, &[&payer], &mut banks_client).await;\n\n        let user_token_out_account_after = banks_client\n            .get_account(user_token_out)\n            .await\n            .ok()\n            .flatten()\n            .unwrap();\n\n        let user_token_out_state_after =\n            TokenAccount::try_deserialize(&mut user_token_out_account_after.data.as_ref()).unwrap();\n\n        assert_eq!(\n            user_token_out_state_after.amount - user_token_out_state_before.amount,\n            quote_result.amount_out\n        );\n    }\n}\n"
  },
  {
    "path": "idls/dlmm.json",
    "content": "{\n  \"address\": \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\n  \"metadata\": {\n    \"name\": \"lb_clmm\",\n    \"version\": \"0.10.1\",\n    \"spec\": \"0.1.0\",\n    \"description\": \"Created with Anchor\"\n  },\n  \"instructions\": [\n    {\n      \"name\": \"add_liquidity\",\n      \"discriminator\": [181, 157, 89, 67, 143, 182, 52, 72],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity2\",\n      \"discriminator\": [228, 162, 78, 28, 70, 219, 116, 115],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameter\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy\",\n      \"discriminator\": [7, 3, 150, 127, 148, 40, 61, 200],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategy\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy2\",\n      \"discriminator\": [3, 221, 149, 218, 111, 141, 118, 213],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategy\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy_one_side\",\n      \"discriminator\": [41, 5, 238, 175, 100, 225, 6, 205],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategyOneSide\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_weight\",\n      \"discriminator\": [28, 140, 238, 99, 231, 162, 21, 149],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByWeight\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side\",\n      \"discriminator\": [94, 155, 103, 151, 70, 95, 220, 165],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityOneSideParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side_precise\",\n      \"discriminator\": [161, 194, 103, 84, 171, 71, 250, 154],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"AddLiquiditySingleSidePreciseParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side_precise2\",\n      \"discriminator\": [33, 51, 163, 201, 117, 98, 125, 231],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"AddLiquiditySingleSidePreciseParameter2\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_fee\",\n      \"discriminator\": [169, 32, 79, 137, 136, 232, 70, 137],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_lower\", \"bin_array_upper\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"claim_fee2\",\n      \"discriminator\": [112, 191, 101, 171, 28, 144, 127, 187],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_reward\",\n      \"discriminator\": [149, 95, 181, 242, 94, 90, 158, 162],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_lower\", \"bin_array_upper\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"user_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_reward2\",\n      \"discriminator\": [190, 3, 127, 119, 178, 87, 157, 183],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"user_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"close_claim_protocol_fee_operator\",\n      \"discriminator\": [8, 41, 87, 35, 80, 48, 121, 26],\n      \"accounts\": [\n        {\n          \"name\": \"claim_fee_operator\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position\",\n      \"discriminator\": [123, 134, 81, 0, 49, 68, 98, 98],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_lower\", \"bin_array_upper\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position2\",\n      \"discriminator\": [174, 90, 35, 115, 186, 40, 147, 226],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position_if_empty\",\n      \"discriminator\": [59, 124, 212, 118, 91, 152, 110, 157],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_preset_parameter\",\n      \"discriminator\": [4, 148, 145, 100, 134, 26, 181, 61],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_preset_parameter2\",\n      \"discriminator\": [39, 25, 95, 107, 116, 17, 115, 28],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_token_badge\",\n      \"discriminator\": [108, 146, 86, 110, 179, 254, 10, 104],\n      \"accounts\": [\n        {\n          \"name\": \"token_badge\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"create_claim_protocol_fee_operator\",\n      \"discriminator\": [51, 19, 150, 252, 105, 157, 48, 91],\n      \"accounts\": [\n        {\n          \"name\": \"claim_fee_operator\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [99, 102, 95, 111, 112, 101, 114, 97, 116, 111, 114]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"operator\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"decrease_position_length\",\n      \"discriminator\": [194, 219, 136, 32, 25, 96, 105, 37],\n      \"accounts\": [\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_remove\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"side\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"for_idl_type_generation_do_not_call\",\n      \"discriminator\": [180, 105, 69, 80, 95, 50, 73, 108],\n      \"accounts\": [\n        {\n          \"name\": \"dummy_zc_account\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"_ix\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"DummyIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"fund_reward\",\n      \"discriminator\": [188, 50, 249, 165, 93, 151, 38, 63],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array\"]\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"funder_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"carry_forward\",\n          \"type\": \"bool\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"go_to_a_bin\",\n      \"discriminator\": [146, 72, 174, 224, 40, 253, 84, 174],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\",\n            \"from_bin_array\",\n            \"to_bin_array\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"from_bin_array\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"to_bin_array\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_oracle_length\",\n      \"discriminator\": [190, 61, 125, 87, 103, 79, 158, 173],\n      \"accounts\": [\n        {\n          \"name\": \"oracle\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_add\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_position_length\",\n      \"discriminator\": [80, 83, 117, 211, 66, 13, 33, 149],\n      \"accounts\": [\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_add\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"side\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_position_length2\",\n      \"discriminator\": [255, 210, 204, 71, 115, 137, 225, 113],\n      \"accounts\": [\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"minimum_upper_bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_bin_array\",\n      \"discriminator\": [35, 86, 19, 185, 78, 212, 75, 211],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 110, 95, 97, 114, 114, 97, 121]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"index\",\n          \"type\": \"i64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_bin_array_bitmap_extension\",\n      \"discriminator\": [47, 157, 226, 180, 12, 240, 33, 71],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"docs\": [\n            \"Initialize an account to store if a bin array is initialized.\"\n          ],\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"initialize_customizable_permissionless_lb_pair\",\n      \"discriminator\": [46, 39, 41, 135, 111, 183, 200, 64],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [111, 114, 97, 99, 108, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"user_token_x\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"user_token_y\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"CustomizableParams\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_customizable_permissionless_lb_pair2\",\n      \"discriminator\": [243, 73, 129, 126, 51, 19, 241, 107],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [111, 114, 97, 99, 108, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"user_token_x\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"user_token_y\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"CustomizableParams\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_lb_pair\",\n      \"discriminator\": [45, 154, 237, 210, 221, 15, 166, 92],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [111, 114, 97, 99, 108, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"preset_parameter\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"active_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bin_step\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_lb_pair2\",\n      \"discriminator\": [73, 59, 36, 120, 237, 83, 108, 198],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [111, 114, 97, 99, 108, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"preset_parameter\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitializeLbPair2Params\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_permission_lb_pair\",\n      \"discriminator\": [108, 102, 213, 85, 251, 3, 53, 21],\n      \"accounts\": [\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [98, 105, 116, 109, 97, 112]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [111, 114, 97, 99, 108, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"ix_data\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitPermissionPairIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position\",\n      \"discriminator\": [219, 192, 234, 71, 190, 191, 102, 80],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position2\",\n      \"discriminator\": [143, 19, 242, 145, 213, 15, 104, 115],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position_by_operator\",\n      \"discriminator\": [251, 189, 190, 244, 117, 254, 35, 148],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [112, 111, 115, 105, 116, 105, 111, 110]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"base\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"lower_bin_id\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"width\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\"\n        },\n        {\n          \"name\": \"operator\",\n          \"docs\": [\"operator\"],\n          \"signer\": true\n        },\n        {\n          \"name\": \"operator_token_x\"\n        },\n        {\n          \"name\": \"owner_token_x\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"fee_owner\",\n          \"type\": \"pubkey\"\n        },\n        {\n          \"name\": \"lock_release_point\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position_pda\",\n      \"discriminator\": [46, 82, 125, 146, 85, 141, 228, 153],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [112, 111, 115, 105, 116, 105, 111, 110]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"base\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"lower_bin_id\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"width\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"docs\": [\"owner\"],\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_preset_parameter\",\n      \"discriminator\": [66, 188, 71, 211, 98, 109, 14, 186],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101,\n                  116, 101, 114\n                ]\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"ix.bin_step\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"ix.base_factor\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"ix\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitPresetParametersIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_preset_parameter2\",\n      \"discriminator\": [184, 7, 240, 171, 103, 47, 183, 121],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101,\n                  116, 101, 114, 50\n                ]\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"ix.index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"ix\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitPresetParameters2Ix\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_reward\",\n      \"discriminator\": [95, 135, 192, 196, 242, 129, 230, 68],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"reward_index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"token_badge\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\",\n          \"address\": \"SysvarRent111111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"reward_duration\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"funder\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_token_badge\",\n      \"discriminator\": [253, 77, 205, 95, 27, 224, 89, 223],\n      \"accounts\": [\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"token_badge\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [116, 111, 107, 101, 110, 95, 98, 97, 100, 103, 101]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"migrate_bin_array\",\n      \"discriminator\": [17, 23, 159, 211, 101, 184, 41, 241],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"migrate_position\",\n      \"discriminator\": [15, 132, 59, 50, 199, 6, 251, 46],\n      \"accounts\": [\n        {\n          \"name\": \"position_v2\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position_v1\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\"position_v1\", \"bin_array_lower\", \"bin_array_upper\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"writable\": true,\n          \"signer\": true,\n          \"relations\": [\"position_v1\"]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"rebalance_liquidity\",\n      \"discriminator\": [92, 4, 176, 193, 119, 185, 83, 9],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"rent_payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RebalanceLiquidityParams\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_all_liquidity\",\n      \"discriminator\": [10, 51, 61, 35, 112, 105, 24, 85],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"remove_liquidity\",\n      \"discriminator\": [80, 85, 209, 72, 24, 206, 177, 108],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_liquidity_removal\",\n          \"type\": {\n            \"vec\": {\n              \"defined\": {\n                \"name\": \"BinLiquidityReduction\"\n              }\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity2\",\n      \"discriminator\": [230, 215, 82, 127, 241, 101, 227, 146],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_liquidity_removal\",\n          \"type\": {\n            \"vec\": {\n              \"defined\": {\n                \"name\": \"BinLiquidityReduction\"\n              }\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity_by_range\",\n      \"discriminator\": [26, 82, 102, 152, 240, 74, 105, 26],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"from_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"to_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bps_to_remove\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity_by_range2\",\n      \"discriminator\": [204, 2, 195, 145, 53, 145, 145, 205],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"from_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"to_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bps_to_remove\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"set_activation_point\",\n      \"discriminator\": [91, 249, 15, 165, 26, 129, 254, 125],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"writable\": true,\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"activation_point\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pair_status\",\n      \"discriminator\": [67, 248, 231, 137, 154, 149, 217, 174],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"status\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pair_status_permissionless\",\n      \"discriminator\": [78, 59, 152, 211, 70, 183, 46, 208],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"creator\",\n          \"signer\": true,\n          \"relations\": [\"lb_pair\"]\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"status\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pre_activation_duration\",\n      \"discriminator\": [165, 61, 201, 244, 130, 159, 22, 100],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"creator\",\n          \"signer\": true,\n          \"relations\": [\"lb_pair\"]\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"pre_activation_duration\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pre_activation_swap_address\",\n      \"discriminator\": [57, 139, 47, 123, 216, 80, 223, 10],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"creator\",\n          \"signer\": true,\n          \"relations\": [\"lb_pair\"]\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"pre_activation_swap_address\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap\",\n      \"discriminator\": [248, 198, 158, 145, 225, 117, 135, 200],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_amount_out\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap2\",\n      \"discriminator\": [65, 75, 63, 76, 235, 91, 91, 136],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_amount_out\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_exact_out\",\n      \"discriminator\": [250, 73, 101, 33, 38, 207, 75, 184],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_in_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"out_amount\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_exact_out2\",\n      \"discriminator\": [43, 215, 247, 132, 137, 60, 243, 81],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_in_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"out_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_with_price_impact\",\n      \"discriminator\": [56, 173, 230, 208, 173, 228, 156, 205],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"active_id\",\n          \"type\": {\n            \"option\": \"i32\"\n          }\n        },\n        {\n          \"name\": \"max_price_impact_bps\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_with_price_impact2\",\n      \"discriminator\": [74, 98, 192, 214, 177, 51, 75, 51],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array_bitmap_extension\"]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"active_id\",\n          \"type\": {\n            \"option\": \"i32\"\n          }\n        },\n        {\n          \"name\": \"max_price_impact_bps\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_base_fee_parameters\",\n      \"discriminator\": [75, 168, 223, 161, 16, 195, 3, 47],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"fee_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"BaseFeeParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_dynamic_fee_parameters\",\n      \"discriminator\": [92, 161, 46, 246, 255, 189, 22, 22],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"fee_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"DynamicFeeParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_fees_and_reward2\",\n      \"discriminator\": [32, 142, 184, 154, 103, 65, 184, 88],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_fees_and_rewards\",\n      \"discriminator\": [154, 230, 250, 13, 236, 209, 75, 223],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"position\", \"bin_array_lower\", \"bin_array_upper\"]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"update_position_operator\",\n      \"discriminator\": [202, 184, 103, 143, 180, 191, 116, 217],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\"position\"]\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"operator\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_reward_duration\",\n      \"discriminator\": [138, 174, 196, 169, 213, 235, 254, 107],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array\"]\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"new_duration\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_reward_funder\",\n      \"discriminator\": [211, 28, 48, 32, 215, 160, 35, 23],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"admin\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"new_funder\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"withdraw_ineligible_reward\",\n      \"discriminator\": [148, 206, 42, 195, 247, 49, 103, 8],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\"bin_array\"]\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"funder_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111,\n                  114, 105, 116, 121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"withdraw_protocol_fee\",\n      \"discriminator\": [158, 201, 158, 189, 33, 93, 162, 103],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\"lb_pair\"]\n        },\n        {\n          \"name\": \"receiver_token_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  8, 234, 192, 109, 87, 125, 190, 55, 129, 173, 227, 8, 104,\n                  201, 104, 13, 31, 178, 74, 80, 54, 14, 77, 78, 226, 57, 47,\n                  122, 166, 165, 57, 144\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_x_program\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_x_mint\"\n              }\n            ],\n            \"program\": {\n              \"kind\": \"const\",\n              \"value\": [\n                140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142,\n                13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216,\n                219, 233, 248, 89\n              ]\n            }\n          }\n        },\n        {\n          \"name\": \"receiver_token_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  8, 234, 192, 109, 87, 125, 190, 55, 129, 173, 227, 8, 104,\n                  201, 104, 13, 31, 178, 74, 80, 54, 14, 77, 78, 226, 57, 47,\n                  122, 166, 165, 57, 144\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_y_program\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_y_mint\"\n              }\n            ],\n            \"program\": {\n              \"kind\": \"const\",\n              \"value\": [\n                140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142,\n                13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216,\n                219, 233, 248, 89\n              ]\n            }\n          }\n        },\n        {\n          \"name\": \"claim_fee_operator\"\n        },\n        {\n          \"name\": \"operator\",\n          \"docs\": [\"operator\"],\n          \"signer\": true,\n          \"relations\": [\"claim_fee_operator\"]\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_amount_x\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"max_amount_y\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"accounts\": [\n    {\n      \"name\": \"BinArray\",\n      \"discriminator\": [92, 142, 92, 220, 5, 148, 70, 181]\n    },\n    {\n      \"name\": \"BinArrayBitmapExtension\",\n      \"discriminator\": [80, 111, 124, 113, 55, 237, 18, 5]\n    },\n    {\n      \"name\": \"ClaimFeeOperator\",\n      \"discriminator\": [166, 48, 134, 86, 34, 200, 188, 150]\n    },\n    {\n      \"name\": \"DummyZcAccount\",\n      \"discriminator\": [94, 107, 238, 80, 208, 48, 180, 8]\n    },\n    {\n      \"name\": \"LbPair\",\n      \"discriminator\": [33, 11, 49, 98, 181, 101, 177, 13]\n    },\n    {\n      \"name\": \"Oracle\",\n      \"discriminator\": [139, 194, 131, 179, 140, 179, 229, 244]\n    },\n    {\n      \"name\": \"Position\",\n      \"discriminator\": [170, 188, 143, 228, 122, 64, 247, 208]\n    },\n    {\n      \"name\": \"PositionV2\",\n      \"discriminator\": [117, 176, 212, 199, 245, 180, 133, 182]\n    },\n    {\n      \"name\": \"PresetParameter\",\n      \"discriminator\": [242, 62, 244, 34, 181, 112, 58, 170]\n    },\n    {\n      \"name\": \"PresetParameter2\",\n      \"discriminator\": [171, 236, 148, 115, 162, 113, 222, 174]\n    },\n    {\n      \"name\": \"TokenBadge\",\n      \"discriminator\": [116, 219, 204, 229, 249, 116, 255, 150]\n    }\n  ],\n  \"events\": [\n    {\n      \"name\": \"AddLiquidity\",\n      \"discriminator\": [31, 94, 125, 90, 227, 52, 61, 186]\n    },\n    {\n      \"name\": \"ClaimFee\",\n      \"discriminator\": [75, 122, 154, 48, 140, 74, 123, 163]\n    },\n    {\n      \"name\": \"ClaimFee2\",\n      \"discriminator\": [232, 171, 242, 97, 58, 77, 35, 45]\n    },\n    {\n      \"name\": \"ClaimReward\",\n      \"discriminator\": [148, 116, 134, 204, 22, 171, 85, 95]\n    },\n    {\n      \"name\": \"ClaimReward2\",\n      \"discriminator\": [27, 143, 244, 33, 80, 43, 110, 146]\n    },\n    {\n      \"name\": \"CompositionFee\",\n      \"discriminator\": [128, 151, 123, 106, 17, 102, 113, 142]\n    },\n    {\n      \"name\": \"DecreasePositionLength\",\n      \"discriminator\": [52, 118, 235, 85, 172, 169, 15, 128]\n    },\n    {\n      \"name\": \"DynamicFeeParameterUpdate\",\n      \"discriminator\": [88, 88, 178, 135, 194, 146, 91, 243]\n    },\n    {\n      \"name\": \"FeeParameterUpdate\",\n      \"discriminator\": [48, 76, 241, 117, 144, 215, 242, 44]\n    },\n    {\n      \"name\": \"FundReward\",\n      \"discriminator\": [246, 228, 58, 130, 145, 170, 79, 204]\n    },\n    {\n      \"name\": \"GoToABin\",\n      \"discriminator\": [59, 138, 76, 68, 138, 131, 176, 67]\n    },\n    {\n      \"name\": \"IncreaseObservation\",\n      \"discriminator\": [99, 249, 17, 121, 166, 156, 207, 215]\n    },\n    {\n      \"name\": \"IncreasePositionLength\",\n      \"discriminator\": [157, 239, 42, 204, 30, 56, 223, 46]\n    },\n    {\n      \"name\": \"InitializeReward\",\n      \"discriminator\": [211, 153, 88, 62, 149, 60, 177, 70]\n    },\n    {\n      \"name\": \"LbPairCreate\",\n      \"discriminator\": [185, 74, 252, 125, 27, 215, 188, 111]\n    },\n    {\n      \"name\": \"PositionClose\",\n      \"discriminator\": [255, 196, 16, 107, 28, 202, 53, 128]\n    },\n    {\n      \"name\": \"PositionCreate\",\n      \"discriminator\": [144, 142, 252, 84, 157, 53, 37, 121]\n    },\n    {\n      \"name\": \"Rebalancing\",\n      \"discriminator\": [0, 109, 117, 179, 61, 91, 199, 200]\n    },\n    {\n      \"name\": \"RemoveLiquidity\",\n      \"discriminator\": [116, 244, 97, 232, 103, 31, 152, 58]\n    },\n    {\n      \"name\": \"Swap\",\n      \"discriminator\": [81, 108, 227, 190, 205, 208, 10, 196]\n    },\n    {\n      \"name\": \"UpdatePositionLockReleasePoint\",\n      \"discriminator\": [133, 214, 66, 224, 64, 12, 7, 191]\n    },\n    {\n      \"name\": \"UpdatePositionOperator\",\n      \"discriminator\": [39, 115, 48, 204, 246, 47, 66, 57]\n    },\n    {\n      \"name\": \"UpdateRewardDuration\",\n      \"discriminator\": [223, 245, 224, 153, 49, 29, 163, 172]\n    },\n    {\n      \"name\": \"UpdateRewardFunder\",\n      \"discriminator\": [224, 178, 174, 74, 252, 165, 85, 180]\n    },\n    {\n      \"name\": \"WithdrawIneligibleReward\",\n      \"discriminator\": [231, 189, 65, 149, 102, 215, 154, 244]\n    }\n  ],\n  \"errors\": [\n    {\n      \"code\": 6000,\n      \"name\": \"InvalidStartBinIndex\",\n      \"msg\": \"Invalid start bin index\"\n    },\n    {\n      \"code\": 6001,\n      \"name\": \"InvalidBinId\",\n      \"msg\": \"Invalid bin id\"\n    },\n    {\n      \"code\": 6002,\n      \"name\": \"InvalidInput\",\n      \"msg\": \"Invalid input data\"\n    },\n    {\n      \"code\": 6003,\n      \"name\": \"ExceededAmountSlippageTolerance\",\n      \"msg\": \"Exceeded amount slippage tolerance\"\n    },\n    {\n      \"code\": 6004,\n      \"name\": \"ExceededBinSlippageTolerance\",\n      \"msg\": \"Exceeded bin slippage tolerance\"\n    },\n    {\n      \"code\": 6005,\n      \"name\": \"CompositionFactorFlawed\",\n      \"msg\": \"Composition factor flawed\"\n    },\n    {\n      \"code\": 6006,\n      \"name\": \"NonPresetBinStep\",\n      \"msg\": \"Non preset bin step\"\n    },\n    {\n      \"code\": 6007,\n      \"name\": \"ZeroLiquidity\",\n      \"msg\": \"Zero liquidity\"\n    },\n    {\n      \"code\": 6008,\n      \"name\": \"InvalidPosition\",\n      \"msg\": \"Invalid position\"\n    },\n    {\n      \"code\": 6009,\n      \"name\": \"BinArrayNotFound\",\n      \"msg\": \"Bin array not found\"\n    },\n    {\n      \"code\": 6010,\n      \"name\": \"InvalidTokenMint\",\n      \"msg\": \"Invalid token mint\"\n    },\n    {\n      \"code\": 6011,\n      \"name\": \"InvalidAccountForSingleDeposit\",\n      \"msg\": \"Invalid account for single deposit\"\n    },\n    {\n      \"code\": 6012,\n      \"name\": \"PairInsufficientLiquidity\",\n      \"msg\": \"Pair insufficient liquidity\"\n    },\n    {\n      \"code\": 6013,\n      \"name\": \"InvalidFeeOwner\",\n      \"msg\": \"Invalid fee owner\"\n    },\n    {\n      \"code\": 6014,\n      \"name\": \"InvalidFeeWithdrawAmount\",\n      \"msg\": \"Invalid fee withdraw amount\"\n    },\n    {\n      \"code\": 6015,\n      \"name\": \"InvalidAdmin\",\n      \"msg\": \"Invalid admin\"\n    },\n    {\n      \"code\": 6016,\n      \"name\": \"IdenticalFeeOwner\",\n      \"msg\": \"Identical fee owner\"\n    },\n    {\n      \"code\": 6017,\n      \"name\": \"InvalidBps\",\n      \"msg\": \"Invalid basis point\"\n    },\n    {\n      \"code\": 6018,\n      \"name\": \"MathOverflow\",\n      \"msg\": \"Math operation overflow\"\n    },\n    {\n      \"code\": 6019,\n      \"name\": \"TypeCastFailed\",\n      \"msg\": \"Type cast error\"\n    },\n    {\n      \"code\": 6020,\n      \"name\": \"InvalidRewardIndex\",\n      \"msg\": \"Invalid reward index\"\n    },\n    {\n      \"code\": 6021,\n      \"name\": \"InvalidRewardDuration\",\n      \"msg\": \"Invalid reward duration\"\n    },\n    {\n      \"code\": 6022,\n      \"name\": \"RewardInitialized\",\n      \"msg\": \"Reward already initialized\"\n    },\n    {\n      \"code\": 6023,\n      \"name\": \"RewardUninitialized\",\n      \"msg\": \"Reward not initialized\"\n    },\n    {\n      \"code\": 6024,\n      \"name\": \"IdenticalFunder\",\n      \"msg\": \"Identical funder\"\n    },\n    {\n      \"code\": 6025,\n      \"name\": \"RewardCampaignInProgress\",\n      \"msg\": \"Reward campaign in progress\"\n    },\n    {\n      \"code\": 6026,\n      \"name\": \"IdenticalRewardDuration\",\n      \"msg\": \"Reward duration is the same\"\n    },\n    {\n      \"code\": 6027,\n      \"name\": \"InvalidBinArray\",\n      \"msg\": \"Invalid bin array\"\n    },\n    {\n      \"code\": 6028,\n      \"name\": \"NonContinuousBinArrays\",\n      \"msg\": \"Bin arrays must be continuous\"\n    },\n    {\n      \"code\": 6029,\n      \"name\": \"InvalidRewardVault\",\n      \"msg\": \"Invalid reward vault\"\n    },\n    {\n      \"code\": 6030,\n      \"name\": \"NonEmptyPosition\",\n      \"msg\": \"Position is not empty\"\n    },\n    {\n      \"code\": 6031,\n      \"name\": \"UnauthorizedAccess\",\n      \"msg\": \"Unauthorized access\"\n    },\n    {\n      \"code\": 6032,\n      \"name\": \"InvalidFeeParameter\",\n      \"msg\": \"Invalid fee parameter\"\n    },\n    {\n      \"code\": 6033,\n      \"name\": \"MissingOracle\",\n      \"msg\": \"Missing oracle account\"\n    },\n    {\n      \"code\": 6034,\n      \"name\": \"InsufficientSample\",\n      \"msg\": \"Insufficient observation sample\"\n    },\n    {\n      \"code\": 6035,\n      \"name\": \"InvalidLookupTimestamp\",\n      \"msg\": \"Invalid lookup timestamp\"\n    },\n    {\n      \"code\": 6036,\n      \"name\": \"BitmapExtensionAccountIsNotProvided\",\n      \"msg\": \"Bitmap extension account is not provided\"\n    },\n    {\n      \"code\": 6037,\n      \"name\": \"CannotFindNonZeroLiquidityBinArrayId\",\n      \"msg\": \"Cannot find non-zero liquidity binArrayId\"\n    },\n    {\n      \"code\": 6038,\n      \"name\": \"BinIdOutOfBound\",\n      \"msg\": \"Bin id out of bound\"\n    },\n    {\n      \"code\": 6039,\n      \"name\": \"InsufficientOutAmount\",\n      \"msg\": \"Insufficient amount in for minimum out\"\n    },\n    {\n      \"code\": 6040,\n      \"name\": \"InvalidPositionWidth\",\n      \"msg\": \"Invalid position width\"\n    },\n    {\n      \"code\": 6041,\n      \"name\": \"ExcessiveFeeUpdate\",\n      \"msg\": \"Excessive fee update\"\n    },\n    {\n      \"code\": 6042,\n      \"name\": \"PoolDisabled\",\n      \"msg\": \"Pool disabled\"\n    },\n    {\n      \"code\": 6043,\n      \"name\": \"InvalidPoolType\",\n      \"msg\": \"Invalid pool type\"\n    },\n    {\n      \"code\": 6044,\n      \"name\": \"ExceedMaxWhitelist\",\n      \"msg\": \"Whitelist for wallet is full\"\n    },\n    {\n      \"code\": 6045,\n      \"name\": \"InvalidIndex\",\n      \"msg\": \"Invalid index\"\n    },\n    {\n      \"code\": 6046,\n      \"name\": \"RewardNotEnded\",\n      \"msg\": \"Reward not ended\"\n    },\n    {\n      \"code\": 6047,\n      \"name\": \"MustWithdrawnIneligibleReward\",\n      \"msg\": \"Must withdraw ineligible reward\"\n    },\n    {\n      \"code\": 6048,\n      \"name\": \"UnauthorizedAddress\",\n      \"msg\": \"Unauthorized address\"\n    },\n    {\n      \"code\": 6049,\n      \"name\": \"OperatorsAreTheSame\",\n      \"msg\": \"Cannot update because operators are the same\"\n    },\n    {\n      \"code\": 6050,\n      \"name\": \"WithdrawToWrongTokenAccount\",\n      \"msg\": \"Withdraw to wrong token account\"\n    },\n    {\n      \"code\": 6051,\n      \"name\": \"WrongRentReceiver\",\n      \"msg\": \"Wrong rent receiver\"\n    },\n    {\n      \"code\": 6052,\n      \"name\": \"AlreadyPassActivationPoint\",\n      \"msg\": \"Already activated\"\n    },\n    {\n      \"code\": 6053,\n      \"name\": \"ExceedMaxSwappedAmount\",\n      \"msg\": \"Swapped amount is exceeded max swapped amount\"\n    },\n    {\n      \"code\": 6054,\n      \"name\": \"InvalidStrategyParameters\",\n      \"msg\": \"Invalid strategy parameters\"\n    },\n    {\n      \"code\": 6055,\n      \"name\": \"LiquidityLocked\",\n      \"msg\": \"Liquidity locked\"\n    },\n    {\n      \"code\": 6056,\n      \"name\": \"BinRangeIsNotEmpty\",\n      \"msg\": \"Bin range is not empty\"\n    },\n    {\n      \"code\": 6057,\n      \"name\": \"NotExactAmountOut\",\n      \"msg\": \"Amount out is not matched with exact amount out\"\n    },\n    {\n      \"code\": 6058,\n      \"name\": \"InvalidActivationType\",\n      \"msg\": \"Invalid activation type\"\n    },\n    {\n      \"code\": 6059,\n      \"name\": \"InvalidActivationDuration\",\n      \"msg\": \"Invalid activation duration\"\n    },\n    {\n      \"code\": 6060,\n      \"name\": \"MissingTokenAmountAsTokenLaunchProof\",\n      \"msg\": \"Missing token amount as token launch owner proof\"\n    },\n    {\n      \"code\": 6061,\n      \"name\": \"InvalidQuoteToken\",\n      \"msg\": \"Quote token must be SOL or USDC\"\n    },\n    {\n      \"code\": 6062,\n      \"name\": \"InvalidBinStep\",\n      \"msg\": \"Invalid bin step\"\n    },\n    {\n      \"code\": 6063,\n      \"name\": \"InvalidBaseFee\",\n      \"msg\": \"Invalid base fee\"\n    },\n    {\n      \"code\": 6064,\n      \"name\": \"InvalidPreActivationDuration\",\n      \"msg\": \"Invalid pre-activation duration\"\n    },\n    {\n      \"code\": 6065,\n      \"name\": \"AlreadyPassPreActivationSwapPoint\",\n      \"msg\": \"Already pass pre-activation swap point\"\n    },\n    {\n      \"code\": 6066,\n      \"name\": \"InvalidStatus\",\n      \"msg\": \"Invalid status\"\n    },\n    {\n      \"code\": 6067,\n      \"name\": \"ExceededMaxOracleLength\",\n      \"msg\": \"Exceed max oracle length\"\n    },\n    {\n      \"code\": 6068,\n      \"name\": \"InvalidMinimumLiquidity\",\n      \"msg\": \"Invalid minimum liquidity\"\n    },\n    {\n      \"code\": 6069,\n      \"name\": \"NotSupportMint\",\n      \"msg\": \"Not support token_2022 mint extension\"\n    },\n    {\n      \"code\": 6070,\n      \"name\": \"UnsupportedMintExtension\",\n      \"msg\": \"Unsupported mint extension\"\n    },\n    {\n      \"code\": 6071,\n      \"name\": \"UnsupportNativeMintToken2022\",\n      \"msg\": \"Unsupported native mint token2022\"\n    },\n    {\n      \"code\": 6072,\n      \"name\": \"UnmatchTokenMint\",\n      \"msg\": \"Unmatch token mint\"\n    },\n    {\n      \"code\": 6073,\n      \"name\": \"UnsupportedTokenMint\",\n      \"msg\": \"Unsupported token mint\"\n    },\n    {\n      \"code\": 6074,\n      \"name\": \"InsufficientRemainingAccounts\",\n      \"msg\": \"Insufficient remaining accounts\"\n    },\n    {\n      \"code\": 6075,\n      \"name\": \"InvalidRemainingAccountSlice\",\n      \"msg\": \"Invalid remaining account slice\"\n    },\n    {\n      \"code\": 6076,\n      \"name\": \"DuplicatedRemainingAccountTypes\",\n      \"msg\": \"Duplicated remaining account types\"\n    },\n    {\n      \"code\": 6077,\n      \"name\": \"MissingRemainingAccountForTransferHook\",\n      \"msg\": \"Missing remaining account for transfer hook\"\n    },\n    {\n      \"code\": 6078,\n      \"name\": \"NoTransferHookProgram\",\n      \"msg\": \"Remaining account was passed for transfer hook but there's no hook program\"\n    },\n    {\n      \"code\": 6079,\n      \"name\": \"ZeroFundedAmount\",\n      \"msg\": \"Zero funded amount\"\n    },\n    {\n      \"code\": 6080,\n      \"name\": \"InvalidSide\",\n      \"msg\": \"Invalid side\"\n    },\n    {\n      \"code\": 6081,\n      \"name\": \"InvalidResizeLength\",\n      \"msg\": \"Invalid resize length\"\n    },\n    {\n      \"code\": 6082,\n      \"name\": \"NotSupportAtTheMoment\",\n      \"msg\": \"Not support at the moment\"\n    },\n    {\n      \"code\": 6083,\n      \"name\": \"InvalidRebalanceParameters\",\n      \"msg\": \"Invalid rebalance parameters\"\n    },\n    {\n      \"code\": 6084,\n      \"name\": \"InvalidRewardAccounts\",\n      \"msg\": \"Invalid reward accounts\"\n    },\n    {\n      \"code\": 6085,\n      \"name\": \"UndeterminedError\",\n      \"msg\": \"Undetermined error\"\n    },\n    {\n      \"code\": 6086,\n      \"name\": \"ReallocExceedMaxLengthPerInstruction\",\n      \"msg\": \"Realloc exceed max length per instruction\"\n    },\n    {\n      \"code\": 6087,\n      \"name\": \"InvalidBaseFeeMantissa\",\n      \"msg\": \"Mantissa cannot more than two significant digits\"\n    },\n    {\n      \"code\": 6088,\n      \"name\": \"InvalidPositionOwner\",\n      \"msg\": \"Invalid position owner\"\n    },\n    {\n      \"code\": 6089,\n      \"name\": \"InvalidPoolAddress\",\n      \"msg\": \"Invalid pool address\"\n    }\n  ],\n  \"types\": [\n    {\n      \"name\": \"AccountsType\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"TransferHookX\"\n          },\n          {\n            \"name\": \"TransferHookY\"\n          },\n          {\n            \"name\": \"TransferHookReward\"\n          },\n          {\n            \"name\": \"TransferHookMultiReward\",\n            \"fields\": [\"u8\"]\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ActivationType\",\n      \"docs\": [\"Type of the activation\"],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Slot\"\n          },\n          {\n            \"name\": \"Timestamp\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquidity\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amounts\",\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_delta_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_delta_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"x0\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y0\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"delta_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"delta_y\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"bit_flag\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"favor_x_in_active_id\",\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"padding\",\n            \"type\": {\n              \"array\": [\"u8\", 16]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquiditySingleSidePreciseParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"CompressedBinDepositAmount\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"decompress_multiplier\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquiditySingleSidePreciseParameter2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"CompressedBinDepositAmount\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"decompress_multiplier\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BaseFeeParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\"Base factor for base fee rate\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\"Base fee power factor\"],\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Bin\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\n              \"Amount of token X in the bin. This already excluded protocol fees.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\n              \"Amount of token Y in the bin. This already excluded protocol fees.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"price\",\n            \"docs\": [\"Bin price\"],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"liquidity_supply\",\n            \"docs\": [\n              \"Liquidities of the bin. This is the same as LP mint supply. q-number\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"reward_per_token_stored\",\n            \"docs\": [\"reward_a_per_token_stored\"],\n            \"type\": {\n              \"array\": [\"u128\", 2]\n            }\n          },\n          {\n            \"name\": \"fee_amount_x_per_token_stored\",\n            \"docs\": [\"Swap fee amount of token X per liquidity deposited.\"],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_amount_y_per_token_stored\",\n            \"docs\": [\"Swap fee amount of token Y per liquidity deposited.\"],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"amount_x_in\",\n            \"docs\": [\n              \"Total token X swap into the bin. Only used for tracking purpose.\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"amount_y_in\",\n            \"docs\": [\n              \"Total token Y swap into he bin. Only used for tracking purpose.\"\n            ],\n            \"type\": \"u128\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinArray\",\n      \"docs\": [\n        \"An account to contain a range of bin. For example: Bin 100 <-> 200.\",\n        \"For example:\",\n        \"BinArray index: 0 contains bin 0 <-> 599\",\n        \"index: 2 contains bin 600 <-> 1199, ...\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"index\",\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"version\",\n            \"docs\": [\"Version of binArray\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"type\": {\n              \"array\": [\"u8\", 7]\n            }\n          },\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"Bin\"\n                  }\n                },\n                70\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinArrayBitmapExtension\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"positive_bin_array_bitmap\",\n            \"docs\": [\n              \"Packed initialized bin array state for start_bin_index is positive\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"array\": [\"u64\", 8]\n                },\n                12\n              ]\n            }\n          },\n          {\n            \"name\": \"negative_bin_array_bitmap\",\n            \"docs\": [\n              \"Packed initialized bin array state for start_bin_index is negative\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"array\": [\"u64\", 8]\n                },\n                12\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityDistribution\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"docs\": [\"Define the bin ID wish to deposit to.\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"distribution_x\",\n            \"docs\": [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"distribution_y\",\n            \"docs\": [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityDistributionByWeight\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"docs\": [\"Define the bin ID wish to deposit to.\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"weight\",\n            \"docs\": [\"weight of liquidity distributed for this bin id\"],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityReduction\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bps_to_remove\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFee\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"fee_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFee2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"fee_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFeeOperator\",\n      \"docs\": [\"Parameter that set by the protocol\"],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"operator\",\n            \"docs\": [\"operator\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\"Reserve\"],\n            \"type\": {\n              \"array\": [\"u8\", 128]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_reward\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimReward2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_reward\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CompositionFee\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i16\"\n          },\n          {\n            \"name\": \"token_x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"token_y_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_token_x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_token_y_fee_amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CompressedBinDepositAmount\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CustomizableParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Pool price\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\"Base factor\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"activation_type\",\n            \"docs\": [\n              \"Activation type. 0 = Slot, 1 = Time. Check ActivationType enum\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"has_alpha_vault\",\n            \"docs\": [\"Whether the pool has an alpha vault\"],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"activation_point\",\n            \"docs\": [\"Decide when does the pool start trade. None = Now\"],\n            \"type\": {\n              \"option\": \"u64\"\n            }\n          },\n          {\n            \"name\": \"creator_pool_on_off_control\",\n            \"docs\": [\n              \"Pool creator have permission to enable/disable pool with restricted program validation. Only applicable for customizable permissionless pool.\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\"Base fee power factor\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\"Padding, for future use\"],\n            \"type\": {\n              \"array\": [\"u8\", 62]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DecreasePositionLength\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"length_to_remove\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"side\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DummyIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"_pair_status\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PairStatus\"\n              }\n            }\n          },\n          {\n            \"name\": \"_pair_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PairType\"\n              }\n            }\n          },\n          {\n            \"name\": \"_activation_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ActivationType\"\n              }\n            }\n          },\n          {\n            \"name\": \"_token_program_flag\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"TokenProgramFlags\"\n              }\n            }\n          },\n          {\n            \"name\": \"_resize_side\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ResizeSide\"\n              }\n            }\n          },\n          {\n            \"name\": \"_rounding\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"Rounding\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DummyZcAccount\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position_bin_data\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PositionBinData\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DynamicFeeParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DynamicFeeParameterUpdate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FeeInfo\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"fee_x_per_token_complete\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_y_per_token_complete\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_x_pending\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y_pending\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FeeParameterUpdate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FundReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"GoToABin\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"to_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"IncreaseObservation\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"oracle\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_observation_length\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"IncreasePositionLength\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"length_to_add\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"side\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitPermissionPairIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"activation_type\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitPresetParameters2Ix\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"index\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step. Represent the price increment / decrement.\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\"Base fee power factor\"],\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitPresetParametersIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step. Represent the price increment / decrement.\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitializeLbPair2Params\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Pool price\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\"Padding, for future use\"],\n            \"type\": {\n              \"array\": [\"u8\", 96]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitializeReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_mint\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_duration\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LbPair\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"parameters\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StaticParameters\"\n              }\n            }\n          },\n          {\n            \"name\": \"v_parameters\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"VariableParameters\"\n              }\n            }\n          },\n          {\n            \"name\": \"bump_seed\",\n            \"type\": {\n              \"array\": [\"u8\", 1]\n            }\n          },\n          {\n            \"name\": \"bin_step_seed\",\n            \"docs\": [\"Bin step signer seed\"],\n            \"type\": {\n              \"array\": [\"u8\", 2]\n            }\n          },\n          {\n            \"name\": \"pair_type\",\n            \"docs\": [\"Type of the pair\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Active bin id\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step. Represent the price increment / decrement.\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"status\",\n            \"docs\": [\"Status of the pair. Check PairStatus enum.\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"require_base_factor_seed\",\n            \"docs\": [\"Require base factor seed\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"base_factor_seed\",\n            \"docs\": [\"Base factor seed\"],\n            \"type\": {\n              \"array\": [\"u8\", 2]\n            }\n          },\n          {\n            \"name\": \"activation_type\",\n            \"docs\": [\"Activation type\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"creator_pool_on_off_control\",\n            \"docs\": [\n              \"Allow pool creator to enable/disable pool with restricted validation. Only applicable for customizable permissionless pair type.\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"token_x_mint\",\n            \"docs\": [\"Token X mint\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_y_mint\",\n            \"docs\": [\"Token Y mint\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reserve_x\",\n            \"docs\": [\"LB token X vault\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reserve_y\",\n            \"docs\": [\"LB token Y vault\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"protocol_fee\",\n            \"docs\": [\"Uncollected protocol fee\"],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ProtocolFee\"\n              }\n            }\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"docs\": [\n              \"_padding_1, previous Fee owner, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\"u8\", 32]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\"Farming reward information\"],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"RewardInfo\"\n                  }\n                },\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"oracle\",\n            \"docs\": [\"Oracle pubkey\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_array_bitmap\",\n            \"docs\": [\"Packed initialized bin array state\"],\n            \"type\": {\n              \"array\": [\"u64\", 16]\n            }\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\"Last time the pool fee parameter was updated\"],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"_padding_2\",\n            \"docs\": [\n              \"_padding_2, previous whitelisted_wallet, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\"u8\", 32]\n            }\n          },\n          {\n            \"name\": \"pre_activation_swap_address\",\n            \"docs\": [\n              \"Address allowed to swap when the current point is greater than or equal to the pre-activation point. The pre-activation point is calculated as `activation_point - pre_activation_duration`.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"base_key\",\n            \"docs\": [\"Base keypair. Only required for permission pair\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"activation_point\",\n            \"docs\": [\n              \"Time point to enable the pair. Only applicable for permission pair.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"pre_activation_duration\",\n            \"docs\": [\n              \"Duration before activation activation_point. Used to calculate pre-activation time point for pre_activation_swap_address\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"_padding_3\",\n            \"docs\": [\n              \"_padding 3 is reclaimed free space from swap_cap_deactivate_point and swap_cap_amount before, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\"u8\", 8]\n            }\n          },\n          {\n            \"name\": \"_padding_4\",\n            \"docs\": [\n              \"_padding_4, previous lock_duration, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"creator\",\n            \"docs\": [\"Pool creator\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_mint_x_program_flag\",\n            \"docs\": [\"token_mint_x_program_flag\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"token_mint_y_program_flag\",\n            \"docs\": [\"token_mint_y_program_flag\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\"Reserved space for future use\"],\n            \"type\": {\n              \"array\": [\"u8\", 22]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LbPairCreate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"token_x\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_y\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityOneSideParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount\",\n            \"docs\": [\"Amount of X token or Y token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Active bin that integrator observe off-chain\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\"max active bin slippage allowed\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\"Liquidity distribution to each bins\"],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistributionByWeight\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\"Amount of X token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\"Amount of Y token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\"Liquidity distribution to each bins\"],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistribution\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByStrategy\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\"Amount of X token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\"Amount of Y token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Active bin that integrator observe off-chain\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\"max active bin slippage allowed\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_parameters\",\n            \"docs\": [\"strategy parameters\"],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyParameters\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByStrategyOneSide\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount\",\n            \"docs\": [\"Amount of X token or Y token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Active bin that integrator observe off-chain\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\"max active bin slippage allowed\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_parameters\",\n            \"docs\": [\"strategy parameters\"],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyParameters\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByWeight\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\"Amount of X token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\"Amount of Y token to deposit\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"Active bin that integrator observe off-chain\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\"max active bin slippage allowed\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\"Liquidity distribution to each bins\"],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistributionByWeight\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Oracle\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"idx\",\n            \"docs\": [\"Index of latest observation\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_size\",\n            \"docs\": [\n              \"Size of active sample. Active sample is initialized observation.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"length\",\n            \"docs\": [\"Number of observations\"],\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PairStatus\",\n      \"docs\": [\n        \"Pair status. 0 = Enabled, 1 = Disabled. Putting 0 as enabled for backward compatibility.\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Enabled\"\n          },\n          {\n            \"name\": \"Disabled\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PairType\",\n      \"docs\": [\n        \"Type of the Pair. 0 = Permissionless, 1 = Permission, 2 = CustomizablePermissionless. Putting 0 as permissionless for backward compatibility.\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Permissionless\"\n          },\n          {\n            \"name\": \"Permission\"\n          },\n          {\n            \"name\": \"CustomizablePermissionless\"\n          },\n          {\n            \"name\": \"PermissionlessV2\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Position\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"docs\": [\"The LB pair of this position\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"docs\": [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"liquidity_shares\",\n            \"docs\": [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ],\n            \"type\": {\n              \"array\": [\"u64\", 70]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\"Farming reward information\"],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"UserRewardInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"fee_infos\",\n            \"docs\": [\"Swap fee to claim information\"],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"FeeInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"lower_bin_id\",\n            \"docs\": [\"Lower bin ID\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"upper_bin_id\",\n            \"docs\": [\"Upper bin ID\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\"Last updated timestamp\"],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_x_amount\",\n            \"docs\": [\"Total claimed token fee X\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_y_amount\",\n            \"docs\": [\"Total claimed token fee Y\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_rewards\",\n            \"docs\": [\"Total claimed rewards\"],\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\"Reserved space for future use\"],\n            \"type\": {\n              \"array\": [\"u8\", 160]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionBinData\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"liquidity_share\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"reward_info\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"UserRewardInfo\"\n              }\n            }\n          },\n          {\n            \"name\": \"fee_info\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"FeeInfo\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionClose\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionCreate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionV2\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"docs\": [\"The LB pair of this position\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"docs\": [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"liquidity_shares\",\n            \"docs\": [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ],\n            \"type\": {\n              \"array\": [\"u128\", 70]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\"Farming reward information\"],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"UserRewardInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"fee_infos\",\n            \"docs\": [\"Swap fee to claim information\"],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"FeeInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"lower_bin_id\",\n            \"docs\": [\"Lower bin ID\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"upper_bin_id\",\n            \"docs\": [\"Upper bin ID\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\"Last updated timestamp\"],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_x_amount\",\n            \"docs\": [\"Total claimed token fee X\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_y_amount\",\n            \"docs\": [\"Total claimed token fee Y\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_rewards\",\n            \"docs\": [\"Total claimed rewards\"],\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          },\n          {\n            \"name\": \"operator\",\n            \"docs\": [\"Operator of position\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"lock_release_point\",\n            \"docs\": [\"Time point which the locked liquidity can be withdraw\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"_padding_0\",\n            \"docs\": [\n              \"_padding_0, previous subjected_to_bootstrap_liquidity_locking, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"fee_owner\",\n            \"docs\": [\n              \"Address is able to claim fee in this position, only valid for bootstrap_liquidity_position\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\"Reserved space for future use\"],\n            \"type\": {\n              \"array\": [\"u8\", 87]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PresetParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step. Represent the price increment / decrement.\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PresetParameter2\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\"Bin step. Represent the price increment / decrement.\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"index\",\n            \"docs\": [\"index\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\"Base fee power factor\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding_0\",\n            \"docs\": [\"Padding 0 for future use\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding_1\",\n            \"docs\": [\"Padding 1 for future use\"],\n            \"type\": {\n              \"array\": [\"u64\", 20]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ProtocolFee\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RebalanceLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\"active id\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\"max active bin slippage allowed\"],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"should_claim_fee\",\n            \"docs\": [\"a flag to indicate that whether fee should be harvested\"],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"should_claim_reward\",\n            \"docs\": [\n              \"a flag to indicate that whether rewards should be harvested\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"min_withdraw_x_amount\",\n            \"docs\": [\"threshold for withdraw token x\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_deposit_x_amount\",\n            \"docs\": [\"threshold for deposit token x\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"min_withdraw_y_amount\",\n            \"docs\": [\"threshold for withdraw token y\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_deposit_y_amount\",\n            \"docs\": [\"threshold for deposit token y\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"shrink_mode\",\n            \"docs\": [\"shrink mode\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\"padding 32 bytes for future usage\"],\n            \"type\": {\n              \"array\": [\"u8\", 31]\n            }\n          },\n          {\n            \"name\": \"removes\",\n            \"docs\": [\"removes\"],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"RemoveLiquidityParams\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"adds\",\n            \"docs\": [\"adds\"],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"AddLiquidityParams\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Rebalancing\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"x_withdrawn_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"x_added_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_withdrawn_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_added_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_min_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"old_max_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"new_min_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"new_max_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"rewards\",\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemainingAccountsInfo\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"slices\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"RemainingAccountsSlice\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemainingAccountsSlice\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"accounts_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"AccountsType\"\n              }\n            }\n          },\n          {\n            \"name\": \"length\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemoveLiquidity\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amounts\",\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemoveLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_bin_id\",\n            \"type\": {\n              \"option\": \"i32\"\n            }\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"type\": {\n              \"option\": \"i32\"\n            }\n          },\n          {\n            \"name\": \"bps\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"padding\",\n            \"type\": {\n              \"array\": [\"u8\", 16]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ResizeSide\",\n      \"docs\": [\"Side of resize, 0 for lower and 1 for upper\"],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Lower\"\n          },\n          {\n            \"name\": \"Upper\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RewardInfo\",\n      \"docs\": [\n        \"Stores the state relevant for tracking liquidity mining rewards\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"mint\",\n            \"docs\": [\"Reward token mint.\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"vault\",\n            \"docs\": [\"Reward vault token account.\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"docs\": [\"Authority account that allows to fund rewards\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_duration\",\n            \"docs\": [\"LM reward duration in seconds.\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_duration_end\",\n            \"docs\": [\"LM reward duration end time.\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_rate\",\n            \"docs\": [\"LM reward rate\"],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"last_update_time\",\n            \"docs\": [\"The last time reward states were updated.\"],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"cumulative_seconds_with_empty_liquidity_reward\",\n            \"docs\": [\n              \"Accumulated seconds where when farm distribute rewards, but the bin is empty. The reward will be accumulated for next reward time window.\"\n            ],\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Rounding\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Up\"\n          },\n          {\n            \"name\": \"Down\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StaticParameters\",\n      \"docs\": [\"Parameter that set by the protocol\"],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\"Base fee power factor\"],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\"Padding for bytemuck safe alignment\"],\n            \"type\": {\n              \"array\": [\"u8\", 5]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StrategyParameters\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\"min bin id\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\"max bin id\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_type\",\n            \"docs\": [\"strategy type\"],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyType\"\n              }\n            }\n          },\n          {\n            \"name\": \"parameteres\",\n            \"docs\": [\"parameters\"],\n            \"type\": {\n              \"array\": [\"u8\", 64]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StrategyType\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"SpotOneSide\"\n          },\n          {\n            \"name\": \"CurveOneSide\"\n          },\n          {\n            \"name\": \"BidAskOneSide\"\n          },\n          {\n            \"name\": \"SpotBalanced\"\n          },\n          {\n            \"name\": \"CurveBalanced\"\n          },\n          {\n            \"name\": \"BidAskBalanced\"\n          },\n          {\n            \"name\": \"SpotImBalanced\"\n          },\n          {\n            \"name\": \"CurveImBalanced\"\n          },\n          {\n            \"name\": \"BidAskImBalanced\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Swap\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"start_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"end_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"amount_in\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_out\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"swap_for_y\",\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"fee\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_fee\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_bps\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"host_fee\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"TokenBadge\",\n      \"docs\": [\"Parameter that set by the protocol\"],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"token_mint\",\n            \"docs\": [\"token mint\"],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\"Reserve\"],\n            \"type\": {\n              \"array\": [\"u8\", 128]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"TokenProgramFlags\",\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"TokenProgram\"\n          },\n          {\n            \"name\": \"TokenProgram2022\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdatePositionLockReleasePoint\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"current_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"new_lock_release_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_lock_release_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"sender\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdatePositionOperator\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"old_operator\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_operator\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdateRewardDuration\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_reward_duration\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"new_reward_duration\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdateRewardFunder\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_funder\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UserRewardInfo\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"reward_per_token_completes\",\n            \"type\": {\n              \"array\": [\"u128\", 2]\n            }\n          },\n          {\n            \"name\": \"reward_pendings\",\n            \"type\": {\n              \"array\": [\"u64\", 2]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"VariableParameters\",\n      \"docs\": [\"Parameters that changes based on dynamic of the market\"],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"volatility_accumulator\",\n            \"docs\": [\n              \"Volatility accumulator measure the number of bin crossed since reference bin ID. Normally (without filter period taken into consideration), reference bin ID is the active bin of last swap.\",\n              \"It affects the variable fee rate\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"volatility_reference\",\n            \"docs\": [\n              \"Volatility reference is decayed volatility accumulator. It is always <= volatility_accumulator\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"index_reference\",\n            \"docs\": [\"Active bin id of last swap.\"],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\"Padding for bytemuck safe alignment\"],\n            \"type\": {\n              \"array\": [\"u8\", 4]\n            }\n          },\n          {\n            \"name\": \"last_update_timestamp\",\n            \"docs\": [\"Last timestamp the variable parameters was updated\"],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"docs\": [\"Padding for bytemuck safe alignment\"],\n            \"type\": {\n              \"array\": [\"u8\", 8]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"WithdrawIneligibleReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_mint\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    }\n  ],\n  \"constants\": [\n    {\n      \"name\": \"BASIS_POINT_MAX\",\n      \"type\": \"i32\",\n      \"value\": \"10000\"\n    },\n    {\n      \"name\": \"BIN_ARRAY\",\n      \"type\": \"bytes\",\n      \"value\": \"[98, 105, 110, 95, 97, 114, 114, 97, 121]\"\n    },\n    {\n      \"name\": \"BIN_ARRAY_BITMAP_SEED\",\n      \"type\": \"bytes\",\n      \"value\": \"[98, 105, 116, 109, 97, 112]\"\n    },\n    {\n      \"name\": \"BIN_ARRAY_BITMAP_SIZE\",\n      \"type\": \"i32\",\n      \"value\": \"512\"\n    },\n    {\n      \"name\": \"CLAIM_PROTOCOL_FEE_OPERATOR\",\n      \"type\": \"bytes\",\n      \"value\": \"[99, 102, 95, 111, 112, 101, 114, 97, 116, 111, 114]\"\n    },\n    {\n      \"name\": \"DEFAULT_BIN_PER_POSITION\",\n      \"type\": \"u64\",\n      \"value\": \"70\"\n    },\n    {\n      \"name\": \"EXTENSION_BINARRAY_BITMAP_SIZE\",\n      \"type\": \"u64\",\n      \"value\": \"12\"\n    },\n    {\n      \"name\": \"FEE_PRECISION\",\n      \"type\": \"u64\",\n      \"value\": \"1000000000\"\n    },\n    {\n      \"name\": \"HOST_FEE_BPS\",\n      \"docs\": [\"Host fee. 20%\"],\n      \"type\": \"u16\",\n      \"value\": \"2000\"\n    },\n    {\n      \"name\": \"ILM_PROTOCOL_SHARE\",\n      \"type\": \"u16\",\n      \"value\": \"2000\"\n    },\n    {\n      \"name\": \"MAX_BASE_FEE\",\n      \"docs\": [\"Maximum base fee, base_fee / 10^9 = fee_in_percentage\"],\n      \"type\": \"u128\",\n      \"value\": \"100000000\"\n    },\n    {\n      \"name\": \"MAX_BIN_ID\",\n      \"docs\": [\"Maximum bin ID supported. Computed based on 1 bps.\"],\n      \"type\": \"i32\",\n      \"value\": \"443636\"\n    },\n    {\n      \"name\": \"MAX_BIN_PER_ARRAY\",\n      \"type\": \"u64\",\n      \"value\": \"70\"\n    },\n    {\n      \"name\": \"MAX_BIN_STEP\",\n      \"docs\": [\"Maximum bin step\"],\n      \"type\": \"u16\",\n      \"value\": \"400\"\n    },\n    {\n      \"name\": \"MAX_FEE_RATE\",\n      \"docs\": [\"Maximum fee rate. 10%\"],\n      \"type\": \"u64\",\n      \"value\": \"100000000\"\n    },\n    {\n      \"name\": \"MAX_PROTOCOL_SHARE\",\n      \"docs\": [\"Maximum protocol share of the fee. 25%\"],\n      \"type\": \"u16\",\n      \"value\": \"2500\"\n    },\n    {\n      \"name\": \"MAX_RESIZE_LENGTH\",\n      \"type\": \"u64\",\n      \"value\": \"91\"\n    },\n    {\n      \"name\": \"MAX_REWARD_BIN_SPLIT\",\n      \"type\": \"u64\",\n      \"value\": \"15\"\n    },\n    {\n      \"name\": \"MAX_REWARD_DURATION\",\n      \"type\": \"u64\",\n      \"value\": \"31536000\"\n    },\n    {\n      \"name\": \"MINIMUM_LIQUIDITY\",\n      \"type\": \"u128\",\n      \"value\": \"1000000\"\n    },\n    {\n      \"name\": \"MIN_BASE_FEE\",\n      \"docs\": [\"Minimum base fee\"],\n      \"type\": \"u128\",\n      \"value\": \"100000\"\n    },\n    {\n      \"name\": \"MIN_BIN_ID\",\n      \"docs\": [\"Minimum bin ID supported. Computed based on 1 bps.\"],\n      \"type\": \"i32\",\n      \"value\": \"-443636\"\n    },\n    {\n      \"name\": \"MIN_REWARD_DURATION\",\n      \"type\": \"u64\",\n      \"value\": \"1\"\n    },\n    {\n      \"name\": \"NUM_REWARDS\",\n      \"type\": \"u64\",\n      \"value\": \"2\"\n    },\n    {\n      \"name\": \"ORACLE\",\n      \"type\": \"bytes\",\n      \"value\": \"[111, 114, 97, 99, 108, 101]\"\n    },\n    {\n      \"name\": \"POSITION\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 111, 115, 105, 116, 105, 111, 110]\"\n    },\n    {\n      \"name\": \"POSITION_MAX_LENGTH\",\n      \"type\": \"u64\",\n      \"value\": \"1400\"\n    },\n    {\n      \"name\": \"PRESET_PARAMETER\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114]\"\n    },\n    {\n      \"name\": \"PRESET_PARAMETER2\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114, 50]\"\n    },\n    {\n      \"name\": \"PROTOCOL_SHARE\",\n      \"type\": \"u16\",\n      \"value\": \"500\"\n    }\n  ]\n}\n"
  },
  {
    "path": "keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json",
    "content": "[230,207,238,109,95,154,47,93,183,250,147,189,87,15,117,184,44,91,94,231,126,140,238,134,29,58,8,182,88,22,113,234,8,234,192,109,87,125,190,55,129,173,227,8,104,201,104,13,31,178,74,80,54,14,77,78,226,57,47,122,166,165,57,144]"
  },
  {
    "path": "keys/localnet/program-LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ.json",
    "content": "[237,14,0,252,204,70,136,161,168,214,209,214,165,86,118,17,167,67,226,89,141,50,93,57,21,217,228,215,232,31,23,19,5,5,8,150,192,245,85,119,65,35,231,38,247,167,119,108,169,108,10,152,101,233,92,168,216,177,25,12,113,154,69,75]"
  },
  {
    "path": "market_making/Cargo.toml",
    "content": "[package]\nname = \"market_making\"\nversion = \"0.0.1\"\ndescription = \"Market making bot\"\nedition = \"2021\"\nauthors = [\"andrew <andrew@racoons.dev>\"]\n\n[dependencies]\ntokio = { workspace = true, features = [\"full\"] }\nhyper = { workspace = true, features = [\"full\"] }\nrouterify = { workspace = true }\nureq = { workspace = true, features = [\"json\"] }\nanchor-client = { workspace = true, features = [\"async\"] }\nanchor-spl = { workspace = true }\nanchor-lang = { workspace = true }\nenv_logger = { workspace = true }\nlog = { workspace = true }\nclap = { workspace = true, features = [\"derive\"] }\nshellexpand = { workspace = true }\nanyhow = { workspace = true }\nserde_json = { workspace = true }\nserde = { workspace = true, features = [\"derive\"] }\nspl-associated-token-account = { workspace = true }\nsolana-transaction-status = { workspace = true }\nbs58 = { workspace = true }\nchrono = { workspace = true }\ncommons = { workspace = true }\nsolana-account-decoder = { workspace = true }\nitertools = { workspace = true }\nrust_decimal = { workspace = true, features = [\"maths\"] }\nspl-memo = { workspace = true, features = [\"no-entrypoint\"] }\nbytemuck = { workspace = true }\n"
  },
  {
    "path": "market_making/README.MD",
    "content": "An example for market making with DLMM\n\n### Toolchain\n\n```\nchannel = 1.76.0\n```\n\nIf you're using M1 chip\n\n```\nchannel = 1.76.0\ntarget triple = x86_64-apple-darwin\n# Eg: 1.76.0-x86_64-apple-darwin\n```\n\n### Build\n\n```\ncargo build\n```\n\n### Run\n\ntarget/debug/market_making --help\n\n### Check positions:\n\n`http://localhost:8080/check_positions`\n"
  },
  {
    "path": "market_making/src/bin_array_manager.rs",
    "content": "use crate::*;\n\npub struct BinArrayManager<'a> {\n    pub bin_arrays: &'a [BinArray],\n}\n\nimpl<'a> BinArrayManager<'a> {\n    pub fn get_bin(&self, bin_id: i32) -> Result<&Bin> {\n        let bin_array_idx = BinArray::bin_id_to_bin_array_index(bin_id)?;\n        match self\n            .bin_arrays\n            .iter()\n            .find(|ba| ba.index == bin_array_idx as i64)\n        {\n            Some(bin_array) => Ok(bin_array.get_bin(bin_id)?),\n            None => Err(anyhow::Error::msg(\"Cannot get bin\")),\n        }\n    }\n\n    pub fn get_lower_upper_bin_id(&self) -> Result<(i32, i32)> {\n        let lower_bin_array_idx = self.bin_arrays[0].index as i32;\n        let upper_bin_array_idx = self.bin_arrays[self.bin_arrays.len() - 1].index as i32;\n\n        let lower_bin_id = lower_bin_array_idx\n            .checked_mul(MAX_BIN_PER_ARRAY as i32)\n            .context(\"math is overflow\")?;\n\n        let upper_bin_id = upper_bin_array_idx\n            .checked_mul(MAX_BIN_PER_ARRAY as i32)\n            .context(\"math is overflow\")?\n            .checked_add(MAX_BIN_PER_ARRAY as i32)\n            .context(\"math is overflow\")?\n            .checked_sub(1)\n            .context(\"math is overflow\")?;\n\n        Ok((lower_bin_id, upper_bin_id))\n    }\n\n    /// Update reward + fee earning\n    pub fn get_total_fee_pending(&self, position: &PositionV2) -> Result<(u64, u64)> {\n        let (bin_arrays_lower_bin_id, bin_arrays_upper_bin_id) = self.get_lower_upper_bin_id()?;\n\n        if position.lower_bin_id < bin_arrays_lower_bin_id\n            && position.upper_bin_id > bin_arrays_upper_bin_id\n        {\n            return Err(anyhow::Error::msg(\"Bin array is not correct\"));\n        }\n\n        let mut total_fee_x = 0u64;\n        let mut total_fee_y = 0u64;\n        for bin_id in position.lower_bin_id..=position.upper_bin_id {\n            let bin = self.get_bin(bin_id)?;\n            let (fee_x_pending, fee_y_pending) =\n                BinArrayManager::get_fee_pending_for_a_bin(position, bin_id, &bin)?;\n            total_fee_x = fee_x_pending\n                .checked_add(total_fee_x)\n                .context(\"math is overflow\")?;\n            total_fee_y = fee_y_pending\n                .checked_add(total_fee_y)\n                .context(\"math is overflow\")?;\n        }\n\n        Ok((total_fee_x, total_fee_y))\n    }\n\n    fn get_fee_pending_for_a_bin(\n        position: &PositionV2,\n        bin_id: i32,\n        bin: &Bin,\n    ) -> Result<(u64, u64)> {\n        ensure!(\n            bin_id >= position.lower_bin_id && bin_id <= position.upper_bin_id,\n            \"Bin is not within the position\"\n        );\n\n        let idx = bin_id - position.lower_bin_id;\n\n        let fee_infos = position.fee_infos[idx as usize];\n        let liquidity_share_in_bin = position.liquidity_shares[idx as usize];\n\n        let fee_x_per_token_stored = bin.fee_amount_x_per_token_stored;\n\n        let liquidity_share_in_bin_downscaled = liquidity_share_in_bin\n            .checked_shr(SCALE_OFFSET.into())\n            .context(\"math is overflow\")?;\n\n        let new_fee_x: u64 = safe_mul_shr_cast(\n            liquidity_share_in_bin_downscaled,\n            fee_x_per_token_stored\n                .checked_sub(fee_infos.fee_x_per_token_complete)\n                .context(\"math is overflow\")?,\n            SCALE_OFFSET,\n            Rounding::Down,\n        )?;\n\n        let fee_x_pending = new_fee_x\n            .checked_add(fee_infos.fee_x_pending)\n            .context(\"math is overflow\")?;\n\n        let fee_y_per_token_stored = bin.fee_amount_y_per_token_stored;\n\n        let new_fee_y: u64 = safe_mul_shr_cast(\n            liquidity_share_in_bin_downscaled,\n            fee_y_per_token_stored\n                .checked_sub(fee_infos.fee_y_per_token_complete)\n                .context(\"math is overflow\")?,\n            SCALE_OFFSET,\n            Rounding::Down,\n        )?;\n\n        let fee_y_pending = new_fee_y\n            .checked_add(fee_infos.fee_y_pending)\n            .context(\"math is overflow\")?;\n\n        Ok((fee_x_pending, fee_y_pending))\n    }\n}\n"
  },
  {
    "path": "market_making/src/config.json",
    "content": "[\n    {\n        \"pair_address\": \"jKzkEPEnoGkrR7QQqzsTDQ1MuGDSyHM3yCgYpNKwREm\",\n        \"x_amount\": 15000000000,\n        \"y_amount\": 2000000,\n        \"mode\": \"ModeBoth\"\n    },\n    {\n        \"pair_address\": \"FoSDw2L5DmTuQTFe55gWPDXf88euaxAEKFre74CnvQbX\",\n        \"x_amount\": 17000000,\n        \"y_amount\": 2000000,\n        \"mode\": \"ModeBoth\"\n    }\n]"
  },
  {
    "path": "market_making/src/core.rs",
    "content": "use crate::MarketMakingMode;\nuse crate::*;\nuse anchor_spl::associated_token::get_associated_token_address_with_program_id;\nuse anchor_spl::token_interface::Mint;\nuse anchor_spl::token_interface::TokenAccount;\nuse compute_budget::ComputeBudgetInstruction;\nuse dlmm::events::Swap as SwapEvent;\nuse instruction::AccountMeta;\nuse instruction::Instruction;\nuse itertools::Itertools;\nuse std::collections::HashMap;\nuse std::str::FromStr;\nuse std::sync::Arc;\nuse std::sync::Mutex;\n\npub struct Core {\n    pub provider: Cluster,\n    pub wallet: Option<Arc<Keypair>>,\n    pub owner: Pubkey,\n    pub config: Vec<PairConfig>,\n    pub state: Arc<Mutex<AllPosition>>,\n}\n\nimpl Core {\n    fn rpc_client(&self) -> RpcClient {\n        RpcClient::new(self.provider.url().to_owned())\n    }\n\n    pub async fn refresh_state(&self) -> Result<()> {\n        let rpc_client = self.rpc_client();\n\n        for pair in self.config.iter() {\n            let pair_address =\n                Pubkey::from_str(&pair.pair_address).context(\"Invalid pair address\")?;\n\n            let lb_pair_state = rpc_client\n                .get_account_and_deserialize(&pair_address, |account| {\n                    Ok(bytemuck::pod_read_unaligned(&account.data[8..]))\n                })\n                .await?;\n\n            // get all position with an user\n            let position_accounts = rpc_client\n                .get_program_accounts_with_config(\n                    &dlmm_ID,\n                    RpcProgramAccountsConfig {\n                        filters: Some(position_filter_by_wallet_and_pair(self.owner, pair_address)),\n                        account_config: RpcAccountInfoConfig {\n                            encoding: Some(UiAccountEncoding::Base64),\n                            ..Default::default()\n                        },\n                        ..Default::default()\n                    },\n                )\n                .await?;\n\n            let mut position_key_with_state = position_accounts\n                .into_iter()\n                .map(|(key, account)| {\n                    let position: PositionV2 = bytemuck::pod_read_unaligned(&account.data[8..]);\n                    (key, position)\n                })\n                .collect::<Vec<_>>();\n\n            let mut position_pks = vec![];\n            let mut positions = vec![];\n            let mut min_bin_id = 0;\n            let mut max_bin_id = 0;\n            let mut bin_arrays = HashMap::new();\n\n            if position_key_with_state.len() > 0 {\n                // sort position by bin id\n                position_key_with_state\n                    .sort_by(|(_, a), (_, b)| a.lower_bin_id.cmp(&b.lower_bin_id));\n\n                min_bin_id = position_key_with_state\n                    .first()\n                    .map(|(_key, state)| state.lower_bin_id)\n                    .context(\"Missing min bin id\")?;\n\n                max_bin_id = position_key_with_state\n                    .last()\n                    .map(|(_key, state)| state.upper_bin_id)\n                    .context(\"Missing max bin id\")?;\n\n                for (key, state) in position_key_with_state.iter() {\n                    position_pks.push(*key);\n                    positions.push(state.to_owned());\n                }\n\n                let bin_array_keys = position_key_with_state\n                    .iter()\n                    .filter_map(|(_key, state)| state.get_bin_array_keys_coverage().ok())\n                    .flatten()\n                    .unique()\n                    .collect::<Vec<_>>();\n\n                let bin_array_accounts = rpc_client.get_multiple_accounts(&bin_array_keys).await?;\n\n                for (key, account) in bin_array_keys.iter().zip(bin_array_accounts) {\n                    if let Some(account) = account {\n                        let bin_array_state = bytemuck::pod_read_unaligned(&account.data[8..]);\n                        bin_arrays.insert(*key, bin_array_state);\n                    }\n                }\n            }\n\n            let mut all_state = self.state.lock().unwrap();\n            let state = all_state.all_positions.get_mut(&pair_address).unwrap();\n\n            state.lb_pair_state = Some(lb_pair_state);\n            state.bin_arrays = bin_arrays;\n            state.position_pks = position_pks;\n            state.positions = positions;\n            state.min_bin_id = min_bin_id;\n            state.max_bin_id = max_bin_id;\n            state.last_update_timestamp = get_epoch_sec();\n        }\n\n        Ok(())\n    }\n\n    pub async fn fetch_token_info(&self) -> Result<()> {\n        let token_mints_with_program = self.get_all_token_mints_with_program_id()?;\n\n        let token_mint_keys = token_mints_with_program\n            .iter()\n            .map(|(key, _program_id)| *key)\n            .collect::<Vec<_>>();\n\n        let rpc_client = self.rpc_client();\n\n        let accounts = rpc_client.get_multiple_accounts(&token_mint_keys).await?;\n        let mut tokens = HashMap::new();\n\n        for ((key, program_id), account) in token_mints_with_program.iter().zip(accounts) {\n            if let Some(account) = account {\n                let mint = Mint::try_deserialize(&mut account.data.as_ref())?;\n                tokens.insert(*key, (mint, *program_id));\n            }\n        }\n        let mut state = self.state.lock().unwrap();\n        state.tokens = tokens;\n\n        Ok(())\n    }\n\n    fn get_all_token_mints_with_program_id(&self) -> Result<Vec<(Pubkey, Pubkey)>> {\n        let state = self.state.lock().unwrap();\n        let mut token_mints_with_program = vec![];\n\n        for (_, position) in state.all_positions.iter() {\n            let lb_pair = &position.lb_pair_state.context(\"Missing lb pair state\")?;\n            let [token_x_program, token_y_program] = lb_pair.get_token_programs()?;\n            token_mints_with_program.push((lb_pair.token_x_mint, token_x_program));\n            token_mints_with_program.push((lb_pair.token_y_mint, token_y_program));\n        }\n\n        token_mints_with_program.sort_unstable();\n        token_mints_with_program.dedup();\n        Ok(token_mints_with_program)\n    }\n\n    pub fn get_position_state(&self, lp_pair: Pubkey) -> SinglePosition {\n        let state = self.state.lock().unwrap();\n        let position = state.all_positions.get(&lp_pair).unwrap();\n        position.clone()\n    }\n\n    pub async fn init_user_ata(&self) -> Result<()> {\n        if let Some(wallet) = self.wallet.as_ref() {\n            let rpc_client = self.rpc_client();\n            for (token_mint, program_id) in self.get_all_token_mints_with_program_id()?.iter() {\n                get_or_create_ata(\n                    &rpc_client,\n                    *token_mint,\n                    *program_id,\n                    wallet.pubkey(),\n                    wallet,\n                )\n                .await?;\n            }\n        }\n\n        Ok(())\n    }\n\n    // withdraw all positions\n    pub async fn withdraw(&self, state: &SinglePosition, is_simulation: bool) -> Result<()> {\n        if state.position_pks.len() == 0 {\n            return Ok(());\n        }\n\n        let rpc_client = self.rpc_client();\n\n        let payer = self.wallet.clone().context(\"Requires keypair\")?;\n\n        let (event_authority, _bump) = derive_event_authority_pda();\n\n        let lb_pair = state.lb_pair;\n        let lb_pair_state = state.lb_pair_state.context(\"Missing lb pair state\")?;\n\n        let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n        let mut remaining_account_info = RemainingAccountsInfo { slices: vec![] };\n        let mut transfer_hook_remaining_accounts = vec![];\n\n        if let Some((slices, remaining_accounts)) =\n            get_potential_token_2022_related_ix_data_and_accounts(\n                &lb_pair_state,\n                RpcClient::new(self.provider.url().to_owned()),\n                ActionType::Liquidity,\n            )\n            .await?\n        {\n            remaining_account_info.slices = slices;\n            transfer_hook_remaining_accounts = remaining_accounts;\n        }\n\n        for (i, &position) in state.position_pks.iter().enumerate() {\n            let position_state = &state.positions[i];\n\n            let bin_arrays_account_meta = position_state.get_bin_array_accounts_meta_coverage()?;\n\n            let user_token_x = get_associated_token_address_with_program_id(\n                &payer.pubkey(),\n                &lb_pair_state.token_x_mint,\n                &token_x_program,\n            );\n\n            let user_token_y = get_associated_token_address_with_program_id(\n                &payer.pubkey(),\n                &lb_pair_state.token_y_mint,\n                &token_y_program,\n            );\n\n            let mut instructions =\n                vec![ComputeBudgetInstruction::set_compute_unit_limit(1_400_000)];\n\n            let main_accounts = dlmm::client::accounts::RemoveLiquidityByRange2 {\n                position,\n                lb_pair,\n                bin_array_bitmap_extension: Some(dlmm_ID),\n                user_token_x,\n                user_token_y,\n                reserve_x: lb_pair_state.reserve_x,\n                reserve_y: lb_pair_state.reserve_y,\n                token_x_mint: lb_pair_state.token_x_mint,\n                token_y_mint: lb_pair_state.token_y_mint,\n                sender: payer.pubkey(),\n                token_x_program,\n                token_y_program,\n                memo_program: spl_memo::ID,\n                event_authority,\n                program: dlmm_ID,\n            }\n            .to_account_metas(None);\n\n            let remaining_accounts = [\n                transfer_hook_remaining_accounts.clone(),\n                bin_arrays_account_meta.clone(),\n            ]\n            .concat();\n\n            let data = dlmm::client::args::RemoveLiquidityByRange2 {\n                from_bin_id: position_state.lower_bin_id,\n                to_bin_id: position_state.upper_bin_id,\n                bps_to_remove: BASIS_POINT_MAX as u16,\n                remaining_accounts_info: remaining_account_info.clone(),\n            }\n            .data();\n\n            let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n            let remove_all_ix = Instruction {\n                program_id: dlmm_ID,\n                accounts,\n                data,\n            };\n\n            instructions.push(remove_all_ix);\n\n            let main_accounts = dlmm::client::accounts::ClaimFee2 {\n                lb_pair,\n                position,\n                sender: payer.pubkey(),\n                event_authority,\n                program: dlmm_ID,\n                reserve_x: lb_pair_state.reserve_x,\n                reserve_y: lb_pair_state.reserve_y,\n                token_x_mint: lb_pair_state.token_x_mint,\n                token_y_mint: lb_pair_state.token_y_mint,\n                token_program_x: token_x_program,\n                token_program_y: token_y_program,\n                memo_program: spl_memo::ID,\n                user_token_x,\n                user_token_y,\n            }\n            .to_account_metas(None);\n\n            let remaining_accounts = [\n                transfer_hook_remaining_accounts.clone(),\n                bin_arrays_account_meta.clone(),\n            ]\n            .concat();\n\n            let data = dlmm::client::args::ClaimFee2 {\n                min_bin_id: position_state.lower_bin_id,\n                max_bin_id: position_state.upper_bin_id,\n                remaining_accounts_info: remaining_account_info.clone(),\n            }\n            .data();\n\n            let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n            let claim_fee_ix = Instruction {\n                program_id: dlmm_ID,\n                accounts,\n                data,\n            };\n\n            instructions.push(claim_fee_ix);\n\n            let accounts = dlmm::client::accounts::ClosePosition2 {\n                position,\n                sender: payer.pubkey(),\n                rent_receiver: payer.pubkey(),\n                event_authority,\n                program: dlmm_ID,\n            }\n            .to_account_metas(None);\n\n            let data = dlmm::client::args::ClosePosition2 {}.data();\n\n            let close_position_ix = Instruction {\n                program_id: dlmm_ID,\n                accounts: accounts.to_vec(),\n                data,\n            };\n\n            instructions.push(close_position_ix);\n\n            if is_simulation {\n                let response =\n                    simulate_transaction(&instructions, &rpc_client, &[], payer.pubkey()).await?;\n                println!(\"{:?}\", response);\n            } else {\n                let signature = send_tx(&instructions, &rpc_client, &[], &payer).await?;\n                info!(\"Close position {position} {signature}\");\n            }\n        }\n\n        Ok(())\n    }\n\n    // TODO implement jupiter swap swap\n    async fn swap(\n        &self,\n        state: &SinglePosition,\n        amount_in: u64,\n        swap_for_y: bool,\n        is_simulation: bool,\n    ) -> Result<Option<SwapEvent>> {\n        let rpc_client = self.rpc_client();\n\n        let lb_pair_state = state.lb_pair_state.context(\"Missing lb pair state\")?;\n        let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n        let lb_pair = state.lb_pair;\n\n        let payer = self.wallet.clone().context(\"Requires keypair\")?;\n\n        let (event_authority, _bump) = derive_event_authority_pda();\n        let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n\n        let account = rpc_client.get_account(&bin_array_bitmap_extension).await;\n\n        let (bin_array_bitmap_extension, bin_array_bitmap_extension_state) =\n            if let std::result::Result::Ok(account) = account {\n                let bin_array_bitmap_extension_state =\n                    bytemuck::pod_read_unaligned(&account.data[8..]);\n                (\n                    bin_array_bitmap_extension,\n                    Some(bin_array_bitmap_extension_state),\n                )\n            } else {\n                (dlmm_ID, None)\n            };\n\n        let bin_arrays_account_meta = get_bin_array_pubkeys_for_swap(\n            lb_pair,\n            &lb_pair_state,\n            bin_array_bitmap_extension_state.as_ref(),\n            swap_for_y,\n            3,\n        )?\n        .into_iter()\n        .map(|key| AccountMeta::new(key, false))\n        .collect::<Vec<_>>();\n\n        let (user_token_in, user_token_out) = if swap_for_y {\n            (\n                get_associated_token_address_with_program_id(\n                    &payer.pubkey(),\n                    &lb_pair_state.token_x_mint,\n                    &token_x_program,\n                ),\n                get_associated_token_address_with_program_id(\n                    &payer.pubkey(),\n                    &lb_pair_state.token_y_mint,\n                    &token_y_program,\n                ),\n            )\n        } else {\n            (\n                get_associated_token_address_with_program_id(\n                    &payer.pubkey(),\n                    &lb_pair_state.token_y_mint,\n                    &token_y_program,\n                ),\n                get_associated_token_address_with_program_id(\n                    &payer.pubkey(),\n                    &lb_pair_state.token_x_mint,\n                    &token_x_program,\n                ),\n            )\n        };\n\n        let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n        let mut remaining_accounts = vec![];\n\n        if let Some((slices, transfer_hook_remaining_accounts)) =\n            get_potential_token_2022_related_ix_data_and_accounts(\n                &lb_pair_state,\n                RpcClient::new(self.provider.url().to_owned()),\n                ActionType::Liquidity,\n            )\n            .await?\n        {\n            remaining_accounts_info.slices = slices;\n            remaining_accounts.extend(transfer_hook_remaining_accounts);\n        }\n\n        remaining_accounts.extend(bin_arrays_account_meta);\n\n        let main_accounts = dlmm::client::accounts::Swap2 {\n            lb_pair,\n            bin_array_bitmap_extension: Some(bin_array_bitmap_extension),\n            reserve_x: lb_pair_state.reserve_x,\n            reserve_y: lb_pair_state.reserve_y,\n            token_x_mint: lb_pair_state.token_x_mint,\n            token_y_mint: lb_pair_state.token_y_mint,\n            token_x_program,\n            token_y_program,\n            user: payer.pubkey(),\n            user_token_in,\n            user_token_out,\n            oracle: lb_pair_state.oracle,\n            host_fee_in: Some(dlmm_ID),\n            event_authority,\n            program: dlmm_ID,\n            memo_program: spl_memo::ID,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::Swap2 {\n            amount_in,\n            min_amount_out: state.get_min_out_amount_with_slippage_rate(amount_in, swap_for_y)?,\n            remaining_accounts_info,\n        }\n        .data();\n\n        let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n        let swap_ix = Instruction {\n            program_id: dlmm_ID,\n            accounts,\n            data,\n        };\n\n        let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000);\n\n        let instructions = [compute_budget_ix, swap_ix];\n\n        if is_simulation {\n            let response =\n                simulate_transaction(&instructions, &rpc_client, &[], payer.pubkey()).await?;\n            println!(\"{:?}\", response);\n            return Ok(None);\n        }\n\n        let signature = send_tx(&instructions, &rpc_client, &[], &payer).await?;\n        info!(\"Swap {amount_in} {swap_for_y} {signature}\");\n\n        // TODO should handle if cannot get swap event\n        let swap_event = parse_swap_event(&rpc_client, signature).await?;\n\n        Ok(Some(swap_event))\n    }\n\n    pub async fn deposit(\n        &self,\n        state: &SinglePosition,\n        amount_x: u64,\n        amount_y: u64,\n        active_id: i32,\n        is_simulation: bool,\n    ) -> Result<()> {\n        let payer = self.wallet.clone().context(\"Require keypair\")?;\n\n        let rpc_client = self.rpc_client();\n        let lower_bin_id = active_id - (MAX_BIN_PER_ARRAY as i32).checked_div(2).unwrap();\n\n        let upper_bin_id = lower_bin_id\n            .checked_add(MAX_BIN_PER_ARRAY as i32)\n            .context(\"math is overflow\")?\n            .checked_sub(1)\n            .context(\"math is overflow\")?;\n\n        let lower_bin_array_idx = BinArray::bin_id_to_bin_array_index(lower_bin_id)?;\n        let upper_bin_array_idx = lower_bin_array_idx\n            .checked_add(1)\n            .context(\"math is overflow\")?;\n\n        let lb_pair = state.lb_pair;\n\n        let (event_authority, _bump) = derive_event_authority_pda();\n\n        let mut instructions = vec![ComputeBudgetInstruction::set_compute_unit_limit(1_400_000)];\n\n        for idx in lower_bin_array_idx..=upper_bin_array_idx {\n            // Initialize bin array if not exists\n            let (bin_array, _bump) = derive_bin_array_pda(lb_pair, idx.into());\n\n            if rpc_client.get_account_data(&bin_array).await.is_err() {\n                let accounts = dlmm::client::accounts::InitializeBinArray {\n                    bin_array,\n                    funder: payer.pubkey(),\n                    lb_pair,\n                    system_program: system_program::ID,\n                }\n                .to_account_metas(None);\n\n                let data = dlmm::client::args::InitializeBinArray { index: idx.into() }.data();\n\n                let instruction = Instruction {\n                    program_id: dlmm_ID,\n                    accounts: accounts.to_vec(),\n                    data,\n                };\n\n                instructions.push(instruction)\n            }\n        }\n\n        let position_kp = Keypair::new();\n        let position = position_kp.pubkey();\n\n        let accounts = dlmm::client::accounts::InitializePosition {\n            lb_pair,\n            payer: payer.pubkey(),\n            position,\n            owner: payer.pubkey(),\n            rent: sysvar::rent::ID,\n            system_program: system_program::ID,\n            event_authority,\n            program: dlmm_ID,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::InitializePosition {\n            lower_bin_id,\n            width: DEFAULT_BIN_PER_POSITION as i32,\n        }\n        .data();\n\n        let instruction = Instruction {\n            program_id: dlmm_ID,\n            accounts: accounts.to_vec(),\n            data,\n        };\n\n        instructions.push(instruction);\n\n        // TODO implement add liquidity by strategy imbalance\n        let (bin_array_bitmap_extension, _bump) = derive_bin_array_bitmap_extension(lb_pair);\n        let bin_array_bitmap_extension = rpc_client\n            .get_account(&bin_array_bitmap_extension)\n            .await\n            .map(|_| bin_array_bitmap_extension)\n            .unwrap_or(dlmm_ID);\n\n        let (bin_array_lower, _bump) = derive_bin_array_pda(lb_pair, lower_bin_array_idx.into());\n        let (bin_array_upper, _bump) = derive_bin_array_pda(lb_pair, upper_bin_array_idx.into());\n\n        let lb_pair_state = state.lb_pair_state.context(\"Missing lb pair state\")?;\n        let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n        let user_token_x = get_associated_token_address_with_program_id(\n            &payer.pubkey(),\n            &lb_pair_state.token_x_mint,\n            &token_x_program,\n        );\n\n        let user_token_y = get_associated_token_address_with_program_id(\n            &payer.pubkey(),\n            &lb_pair_state.token_y_mint,\n            &token_y_program,\n        );\n\n        let mut remaining_accounts_info = RemainingAccountsInfo { slices: vec![] };\n        let mut remaining_accounts = vec![];\n\n        if let Some((slices, transfer_hook_remaining_accounts)) =\n            get_potential_token_2022_related_ix_data_and_accounts(\n                &lb_pair_state,\n                RpcClient::new(self.provider.url().to_owned()),\n                ActionType::Liquidity,\n            )\n            .await?\n        {\n            remaining_accounts_info.slices = slices;\n            remaining_accounts.extend(transfer_hook_remaining_accounts);\n        }\n\n        remaining_accounts.extend(\n            [bin_array_lower, bin_array_upper]\n                .into_iter()\n                .map(|k| AccountMeta::new(k, false)),\n        );\n\n        let main_accounts = dlmm::client::accounts::AddLiquidityByStrategy2 {\n            lb_pair,\n            position,\n            bin_array_bitmap_extension: Some(bin_array_bitmap_extension),\n            sender: payer.pubkey(),\n            event_authority,\n            program: dlmm_ID,\n            reserve_x: lb_pair_state.reserve_x,\n            reserve_y: lb_pair_state.reserve_y,\n            token_x_mint: lb_pair_state.token_x_mint,\n            token_y_mint: lb_pair_state.token_y_mint,\n            user_token_x,\n            user_token_y,\n            token_x_program,\n            token_y_program,\n        }\n        .to_account_metas(None);\n\n        let data = dlmm::client::args::AddLiquidityByStrategy2 {\n            liquidity_parameter: LiquidityParameterByStrategy {\n                amount_x,\n                amount_y,\n                active_id: lb_pair_state.active_id,\n                max_active_bin_slippage: 3,\n                strategy_parameters: StrategyParameters {\n                    min_bin_id: lower_bin_id,\n                    max_bin_id: upper_bin_id,\n                    strategy_type: StrategyType::SpotBalanced,\n                    parameteres: [0u8; 64],\n                },\n            },\n            remaining_accounts_info,\n        }\n        .data();\n\n        let accounts = [main_accounts.to_vec(), remaining_accounts].concat();\n\n        let instruction = Instruction {\n            program_id: dlmm_ID,\n            accounts,\n            data,\n        };\n\n        instructions.push(instruction);\n\n        if is_simulation {\n            let simulate_tx = simulate_transaction(\n                &instructions,\n                &rpc_client,\n                &[&position_kp, &payer],\n                payer.pubkey(),\n            )\n            .await?;\n\n            info!(\"Deposit {amount_x} {amount_y} {position} {:?}\", simulate_tx);\n        } else {\n            let signature = send_tx(&instructions, &rpc_client, &[&position_kp], &payer).await?;\n            info!(\"deposit {amount_x} {amount_y} {position} {signature}\");\n        }\n\n        Ok(())\n    }\n\n    pub async fn get_deposit_amount(\n        &self,\n        position: &SinglePosition,\n        amount_x: u64,\n        amount_y: u64,\n    ) -> Result<(u64, u64)> {\n        let lb_pair_state = position.lb_pair_state.context(\"Missing lb pair state\")?;\n\n        let rpc_client = self.rpc_client();\n        let payer = self.wallet.clone().context(\"Require keypair\")?;\n\n        let [token_x_program, token_y_program] = lb_pair_state.get_token_programs()?;\n\n        let user_token_x = get_associated_token_address_with_program_id(\n            &payer.pubkey(),\n            &lb_pair_state.token_x_mint,\n            &token_x_program,\n        );\n\n        let user_token_y = get_associated_token_address_with_program_id(\n            &payer.pubkey(),\n            &lb_pair_state.token_y_mint,\n            &token_y_program,\n        );\n\n        let mut accounts = rpc_client\n            .get_multiple_accounts(&[user_token_x, user_token_y])\n            .await?;\n\n        let user_token_x_account = accounts[0].take().context(\"user_token_x not found\")?;\n        let user_token_y_account = accounts[1].take().context(\"user_token_y not found\")?;\n\n        let user_token_x_state =\n            TokenAccount::try_deserialize(&mut user_token_x_account.data.as_ref())?;\n        let user_token_y_state =\n            TokenAccount::try_deserialize(&mut user_token_y_account.data.as_ref())?;\n\n        // compare with current balance\n        let amount_x = if amount_x > user_token_x_state.amount {\n            user_token_x_state.amount\n        } else {\n            amount_x\n        };\n\n        let amount_y = if amount_y > user_token_y_state.amount {\n            user_token_y_state.amount\n        } else {\n            amount_y\n        };\n\n        Ok((amount_x, amount_y))\n    }\n\n    pub fn get_all_positions(&self) -> Vec<SinglePosition> {\n        let state = self.state.lock().unwrap();\n        let mut positions = vec![];\n        for (_, position) in &state.all_positions {\n            positions.push(position.clone());\n        }\n        positions\n    }\n\n    pub fn get_all_tokens(&self) -> HashMap<Pubkey, MintWithProgramId> {\n        let state = self.state.lock().unwrap();\n        state.tokens.clone()\n    }\n\n    pub async fn check_shift_price_range(&self) -> Result<()> {\n        let all_positions = self.get_all_positions();\n        for position in all_positions.iter() {\n            let pair_config = get_pair_config(&self.config, position.lb_pair);\n            // check whether out of price range\n            let lb_pair_state = &position.lb_pair_state.context(\"Missing lb pair state\")?;\n            if pair_config.mode == MarketMakingMode::ModeRight\n                && lb_pair_state.active_id > position.max_bin_id\n            {\n                self.shift_right(&position).await?;\n                self.inc_rebalance_time(position.lb_pair);\n            }\n\n            if pair_config.mode == MarketMakingMode::ModeLeft\n                && lb_pair_state.active_id < position.min_bin_id\n            {\n                self.shift_left(&position).await?;\n                self.inc_rebalance_time(position.lb_pair);\n            }\n\n            if pair_config.mode == MarketMakingMode::ModeBoth {\n                if lb_pair_state.active_id < position.min_bin_id {\n                    self.shift_left(&position).await?;\n                    self.inc_rebalance_time(position.lb_pair);\n                } else if lb_pair_state.active_id > position.max_bin_id {\n                    self.shift_right(&position).await?;\n                    self.inc_rebalance_time(position.lb_pair);\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    async fn shift_right(&self, state: &SinglePosition) -> Result<()> {\n        let pair_config = get_pair_config(&self.config, state.lb_pair);\n        // validate that y amount is zero\n        info!(\"shift right {}\", state.lb_pair);\n        let position = state.get_positions()?;\n        if position.amount_x != 0 {\n            return Err(Error::msg(\"Amount x is not zero\"));\n        }\n\n        info!(\"withdraw {}\", state.lb_pair);\n        // withdraw\n        self.withdraw(state, false).await?;\n\n        // buy base\n        let amount_y_for_buy = position\n            .amount_y\n            .checked_div(2)\n            .context(\"math is overflow\")?;\n\n        let lb_pair_state = &state.lb_pair_state.context(\"Missing lb pair state\")?;\n\n        let (amount_x, amount_y) = if amount_y_for_buy != 0 {\n            info!(\"swap {}\", state.lb_pair);\n            let swap_event = self.swap(state, amount_y_for_buy, false, false).await?;\n            (\n                swap_event.map(|e| e.amount_out).unwrap_or_default(),\n                position.amount_y - amount_y_for_buy,\n            )\n        } else {\n            (pair_config.x_amount, pair_config.y_amount)\n        };\n\n        // deposit again, just test with 1 position only\n        info!(\"deposit {}\", state.lb_pair);\n        match self\n            .deposit(state, amount_x, amount_y, lb_pair_state.active_id, false)\n            .await\n        {\n            Err(_) => {\n                self.deposit(state, amount_x, amount_y, lb_pair_state.active_id, true)\n                    .await?;\n            }\n            _ => {}\n        }\n        info!(\"refresh state {}\", state.lb_pair);\n        // fetch positions again\n        self.refresh_state().await?;\n        Ok(())\n    }\n\n    async fn shift_left(&self, state: &SinglePosition) -> Result<()> {\n        let pair_config = get_pair_config(&self.config, state.lb_pair);\n        info!(\"shift left {}\", state.lb_pair);\n        // validate that y amount is zero\n        let position = state.get_positions()?;\n        if position.amount_y != 0 {\n            return Err(Error::msg(\"Amount y is not zero\"));\n        }\n        info!(\"withdraw {}\", state.lb_pair);\n        // withdraw\n        self.withdraw(state, false).await?;\n\n        // sell base\n        let amount_x_for_sell = position\n            .amount_x\n            .checked_div(2)\n            .context(\"math is overflow\")?;\n\n        let lb_pair_state = &state.lb_pair_state.context(\"Missing lb pair state\")?;\n\n        let (amount_x, amount_y) = if amount_x_for_sell != 0 {\n            info!(\"swap {}\", state.lb_pair);\n            let swap_event = self.swap(state, amount_x_for_sell, true, false).await?;\n            (\n                position.amount_x - amount_x_for_sell,\n                swap_event.map(|e| e.amount_out).unwrap_or_default(),\n            )\n        } else {\n            (pair_config.x_amount, pair_config.y_amount)\n        };\n\n        // sanity check with real balances\n        let (amount_x, amount_y) = self.get_deposit_amount(state, amount_x, amount_y).await?;\n        info!(\"deposit {}\", state.lb_pair);\n        match self\n            .deposit(state, amount_x, amount_y, lb_pair_state.active_id, false)\n            .await\n        {\n            Err(_) => {\n                self.deposit(state, amount_x, amount_y, lb_pair_state.active_id, true)\n                    .await?;\n            }\n            _ => {}\n        }\n\n        info!(\"refresh state {}\", state.lb_pair);\n        // fetch positions again\n        self.refresh_state().await?;\n        Ok(())\n    }\n\n    pub fn inc_rebalance_time(&self, lb_pair: Pubkey) {\n        let mut state = self.state.lock().unwrap();\n        let state = state.all_positions.get_mut(&lb_pair).unwrap();\n        state.inc_rebalance_time();\n    }\n\n    pub fn get_positions(&self) -> Result<Vec<PositionInfo>> {\n        let all_positions = self.get_all_positions();\n        let tokens = self.get_all_tokens();\n\n        let mut position_infos = vec![];\n        for position in all_positions.iter() {\n            let lb_pair_state = &position.lb_pair_state.context(\"Missing lb pair state\")?;\n            let x_decimals = get_decimals(lb_pair_state.token_x_mint, &tokens);\n            let y_decimals = get_decimals(lb_pair_state.token_y_mint, &tokens);\n            let position_raw = position.get_positions()?;\n            position_infos.push(position_raw.to_position_info(x_decimals, y_decimals)?);\n        }\n        return Ok(position_infos);\n    }\n}\n\n#[cfg(test)]\nmod core_test {\n    use super::*;\n    use std::env;\n\n    #[tokio::test]\n    async fn test_withdraw() {\n        let wallet = env::var(\"MM_WALLET\").unwrap();\n        let cluster = env::var(\"MM_CLUSTER\").unwrap();\n        let payer = read_keypair_file(wallet.clone()).unwrap();\n\n        let lp_pair = Pubkey::from_str(\"FoSDw2L5DmTuQTFe55gWPDXf88euaxAEKFre74CnvQbX\").unwrap();\n\n        let config = vec![PairConfig {\n            pair_address: lp_pair.to_string(),\n            x_amount: 17000000,\n            y_amount: 2000000,\n            mode: MarketMakingMode::ModeBoth,\n        }];\n\n        let core = &Core {\n            provider: Cluster::from_str(&cluster).unwrap(),\n            owner: payer.pubkey(),\n            wallet: Some(Arc::new(payer)),\n            config: config.clone(),\n            state: Arc::new(Mutex::new(AllPosition::new(&config))),\n        };\n\n        core.refresh_state().await.unwrap();\n\n        let state = core.get_position_state(lp_pair);\n\n        // withdraw\n        core.withdraw(&state, true).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_swap() {\n        let wallet = env::var(\"MM_WALLET\").unwrap();\n        let cluster = env::var(\"MM_CLUSTER\").unwrap();\n        let payer = read_keypair_file(wallet.clone()).unwrap();\n\n        let lp_pair = Pubkey::from_str(\"FoSDw2L5DmTuQTFe55gWPDXf88euaxAEKFre74CnvQbX\").unwrap();\n\n        let config = vec![PairConfig {\n            pair_address: lp_pair.to_string(),\n            x_amount: 17000000,\n            y_amount: 2000000,\n            mode: MarketMakingMode::ModeBoth,\n        }];\n\n        let core = &Core {\n            provider: Cluster::from_str(&cluster).unwrap(),\n            owner: payer.pubkey(),\n            wallet: Some(Arc::new(payer)),\n            config: config.clone(),\n            state: Arc::new(Mutex::new(AllPosition::new(&config))),\n        };\n\n        core.refresh_state().await.unwrap();\n\n        let state = core.get_position_state(lp_pair);\n\n        core.swap(&state, 1000000, true, true).await.unwrap();\n    }\n}\n"
  },
  {
    "path": "market_making/src/main.rs",
    "content": "pub mod bin_array_manager;\npub mod core;\npub mod pair_config;\npub mod router;\npub mod state;\npub mod utils;\n\nuse crate::pair_config::*;\nuse crate::state::*;\nuse crate::utils::*;\n\nuse anchor_client::solana_client::nonblocking::rpc_client::*;\nuse anchor_client::solana_sdk::pubkey::*;\nuse anchor_client::solana_sdk::signature::*;\nuse anchor_client::solana_sdk::*;\nuse anchor_client::*;\nuse solana_account_decoder::*;\n\nuse anyhow::*;\nuse commons::dlmm::accounts::*;\nuse commons::dlmm::types::*;\nuse commons::dlmm::ID as dlmm_ID;\nuse commons::extensions::*;\nuse commons::pda::*;\nuse commons::rpc_client_extension::*;\nuse commons::*;\n\nuse serde::*;\nuse solana_client::rpc_config::*;\n\nuse clap::Parser;\nuse core::Core;\nuse hyper::Server;\nuse router::router;\nuse routerify::RouterService;\nuse std::convert::Into;\nuse std::fmt::Debug;\nuse std::str::FromStr;\nuse std::sync::Arc;\nuse std::sync::Mutex;\nuse std::time::Duration;\n\nuse anchor_lang::AccountDeserialize;\nuse anchor_lang::AnchorDeserialize;\nuse anchor_lang::InstructionData;\nuse anchor_lang::ToAccountMetas;\n\n#[macro_use]\nextern crate log;\n\nuse tokio::time::interval;\n\n#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]\npub enum MarketMakingMode {\n    ModeRight,\n    ModeLeft,\n    ModeBoth,\n    ModeView,\n}\n\nimpl Default for MarketMakingMode {\n    fn default() -> Self {\n        MarketMakingMode::ModeView\n    }\n}\n\nimpl FromStr for MarketMakingMode {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_ascii_lowercase().as_str() {\n            \"moderight\" => Ok(MarketMakingMode::ModeRight),\n            \"modeleft\" => Ok(MarketMakingMode::ModeLeft),\n            \"modeboth\" => Ok(MarketMakingMode::ModeBoth),\n            \"modeview\" => Ok(MarketMakingMode::ModeView),\n            _ => Err(anyhow::Error::msg(\"cannot get mode\")),\n        }\n    }\n}\n\n#[derive(Parser, Debug)]\npub struct Args {\n    /// Solana RPC provider. For example: https://api.mainnet-beta.solana.com\n    #[clap(long, default_value_t = Cluster::Localnet)]\n    provider: Cluster,\n    /// Wallet of owner\n    #[clap(long)]\n    wallet: Option<String>,\n    /// Address of owner, only user_public_key or wallet is set, other wise it is panic immediately\n    #[clap(long)]\n    user_public_key: Option<Pubkey>,\n    /// config path\n    #[clap(long)]\n    config_file: String,\n}\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n    env_logger::init();\n\n    let Args {\n        provider,\n        wallet,\n        user_public_key,\n        config_file,\n    } = Args::parse();\n\n    let config = get_config_from_file(&config_file)?;\n    let wallet = wallet.and_then(|path| read_keypair_file(path).ok());\n\n    let user_wallet = if should_market_making(&config) {\n        wallet.as_ref().context(\"Require keypair\")?.pubkey()\n    } else {\n        user_public_key.unwrap()\n    };\n\n    let core = Core {\n        provider,\n        wallet: wallet.map(Arc::new),\n        owner: user_wallet,\n        config: config.clone(),\n        state: Arc::new(Mutex::new(AllPosition::new(&config))),\n    };\n\n    // init some state\n    core.refresh_state().await.unwrap();\n    core.fetch_token_info().await.unwrap();\n\n    let core = Arc::new(core);\n\n    let mut handles = vec![];\n    {\n        // crawl epoch down\n        let core = core.clone();\n        let handle = tokio::spawn(async move {\n            let duration = 60; // 1 min\n            let mut interval = interval(Duration::from_secs(duration));\n            loop {\n                interval.tick().await;\n                info!(\"refresh state\");\n                if let Err(err) = core.refresh_state().await {\n                    error!(\"refresh_state err {}\", err)\n                };\n            }\n        });\n        handles.push(handle);\n    }\n\n    if should_market_making(&config) {\n        {\n            // crawl epoch down\n            let core = core.clone();\n\n            // init user ata\n            core.init_user_ata().await.unwrap();\n\n            let handle = tokio::spawn(async move {\n                let duration = 60; // 1 min\n                let mut interval = interval(Duration::from_secs(duration));\n                loop {\n                    interval.tick().await;\n                    info!(\"check shift price range\");\n                    if let Err(err) = core.check_shift_price_range().await {\n                        error!(\"check shift price err {}\", err)\n                    }\n                }\n            });\n            handles.push(handle);\n        }\n    }\n\n    let router = router(core);\n\n    let service = RouterService::new(router).unwrap();\n\n    let addr = ([0, 0, 0, 0], 8080).into();\n\n    let server = Server::bind(&addr).serve(service);\n\n    server.await.unwrap();\n\n    for handle in handles {\n        handle.await.unwrap();\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "market_making/src/pair_config.rs",
    "content": "use crate::MarketMakingMode;\nuse anchor_lang::prelude::Pubkey;\nuse anyhow::*;\nuse serde::Deserialize;\nuse std::fs::File;\nuse std::io::Read;\n\n#[derive(Debug, Deserialize, Clone, Default)]\n#[serde(rename_all = \"snake_case\")]\npub struct PairConfig {\n    pub pair_address: String,\n    pub x_amount: u64,\n    pub y_amount: u64,\n    pub mode: MarketMakingMode,\n}\n\npub fn should_market_making(config: &Vec<PairConfig>) -> bool {\n    for pair in config.iter() {\n        if pair.mode != MarketMakingMode::ModeView {\n            return true;\n        }\n    }\n    return false;\n}\n\npub fn get_pair_config(config: &Vec<PairConfig>, pair_addr: Pubkey) -> PairConfig {\n    for pair_config in config.iter() {\n        if pair_config.pair_address == pair_addr.to_string() {\n            return pair_config.clone();\n        }\n    }\n    return PairConfig::default();\n}\n\npub fn get_config_from_file(path: &str) -> Result<Vec<PairConfig>> {\n    // println!(\"config file {}\", env::var(\"KEEPER_CONFIG_FILE\").unwrap());\n    let mut file = File::open(path)?;\n    let mut data = String::new();\n    file.read_to_string(&mut data)?;\n\n    let config: Vec<PairConfig> = serde_json::from_str(&data)?;\n    Ok(config)\n}\n\n#[cfg(test)]\nmod config_test {\n    use super::*;\n    use std::env;\n    #[test]\n    fn test_get_get_config_from_file() {\n        let mut owned_string: String = env::current_dir()\n            .unwrap()\n            .into_os_string()\n            .into_string()\n            .unwrap();\n        let borrowed_string: &str = \"/src/pair_config.json\";\n        owned_string.push_str(borrowed_string);\n\n        let config = get_config_from_file(&owned_string).unwrap();\n        println!(\"{:?}\", config);\n    }\n}\n"
  },
  {
    "path": "market_making/src/router.rs",
    "content": "use std::sync::Arc;\n\nuse crate::Core;\nuse hyper::{Body, Request, Response, StatusCode};\nuse log::debug;\nuse routerify::prelude::*;\nuse routerify::{Middleware, RequestInfo, Router};\nuse std::convert::Infallible;\n\npub fn router(core: Arc<Core>) -> Router<Body, Infallible> {\n    Router::builder()\n        .data(core)\n        .middleware(Middleware::pre(logger))\n        .get(\"/check_positions\", check_positions)\n        .err_handler_with_info(error_handler)\n        .build()\n        .unwrap()\n}\n\nasync fn check_positions(req: Request<Body>) -> Result<Response<Body>, Infallible> {\n    // Access the app state.\n    let core = req.data::<Arc<Core>>().unwrap();\n    match core.get_positions() {\n        Ok(positions) => match serde_json::to_string(&positions) {\n            Ok(res) => Ok(Response::new(Body::from(res))),\n            Err(_) => Ok(Response::new(Body::from(\"Cannot encode positions\"))),\n        },\n        Err(err) => {\n            println!(\"{err}\");\n            Ok(Response::new(Body::from(\"Cannot get positions\")))\n        }\n    }\n}\n\nasync fn error_handler(err: routerify::RouteError, _: RequestInfo) -> Response<Body> {\n    debug!(\"{}\", err);\n    Response::builder()\n        .status(StatusCode::INTERNAL_SERVER_ERROR)\n        .body(Body::from(format!(\"Something went wrong: {}\", err)))\n        .unwrap()\n}\n\nasync fn logger(req: Request<Body>) -> Result<Request<Body>, Infallible> {\n    debug!(\n        \"{} {} {}\",\n        req.remote_addr(),\n        req.method(),\n        req.uri().path()\n    );\n    Ok(req)\n}\n"
  },
  {
    "path": "market_making/src/state.rs",
    "content": "use crate::*;\nuse anchor_spl::token_interface::Mint;\nuse bin_array_manager::BinArrayManager;\nuse rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, MathematicalOps};\nuse std::collections::HashMap;\npub type MintWithProgramId = (Mint, Pubkey);\n\npub struct AllPosition {\n    pub all_positions: HashMap<Pubkey, SinglePosition>, // hashmap of pool pubkey and a position\n    pub tokens: HashMap<Pubkey, MintWithProgramId>,     // cached token info\n}\n\nimpl AllPosition {\n    pub fn new(config: &Vec<PairConfig>) -> Self {\n        let mut all_positions = HashMap::new();\n        for pair in config.iter() {\n            let pool_pk = Pubkey::from_str(&pair.pair_address).unwrap();\n            all_positions.insert(pool_pk, SinglePosition::new(pool_pk));\n        }\n        AllPosition {\n            all_positions,\n            tokens: HashMap::new(),\n        }\n    }\n}\n\n#[derive(Default, Debug, Clone)]\npub struct SinglePosition {\n    pub lb_pair: Pubkey,\n    pub lb_pair_state: Option<LbPair>,\n    pub bin_arrays: HashMap<Pubkey, BinArray>, // only store relevant bin arrays\n    pub positions: Vec<PositionV2>,\n    pub position_pks: Vec<Pubkey>,\n    pub rebalance_time: u64,\n    pub min_bin_id: i32,\n    pub max_bin_id: i32,\n    pub last_update_timestamp: u64,\n}\n\nconst SLIPPAGE_RATE: u64 = 300; // 3%\nconst BASIC_POINT_MAX: u64 = 10_000;\n\nimpl SinglePosition {\n    pub fn inc_rebalance_time(&mut self) {\n        self.rebalance_time += 1;\n    }\n\n    pub fn get_min_out_amount_with_slippage_rate(\n        &self,\n        amount_in: u64,\n        swap_for_y: bool,\n    ) -> Result<u64> {\n        let lb_pair_state = self.lb_pair_state.context(\"Missing lb pair state\")?;\n        let price = get_price_from_id(lb_pair_state.active_id, lb_pair_state.bin_step)?;\n        let out_amount = Bin::get_amount_out(amount_in, price, swap_for_y)?;\n\n        let min_out_amount = out_amount\n            .checked_mul(BASIC_POINT_MAX - SLIPPAGE_RATE)\n            .unwrap()\n            .checked_div(BASIC_POINT_MAX)\n            .unwrap();\n        Ok(min_out_amount)\n    }\n\n    pub fn get_positions(&self) -> Result<PositionRaw> {\n        if self.positions.len() == 0 {\n            return Ok(PositionRaw::default());\n        }\n\n        let mut amount_x = 0u64;\n        let mut amount_y = 0u64;\n\n        let mut fee_x = 0u64;\n        let mut fee_y = 0u64;\n\n        for position in self.positions.iter() {\n            let bin_array_keys = position.get_bin_array_keys_coverage()?;\n            let mut bin_arrays = vec![];\n\n            for key in bin_array_keys {\n                let bin_array_state = self\n                    .bin_arrays\n                    .get(&key)\n                    .ok_or(Error::msg(\"Cannot get binarray\"))?;\n                bin_arrays.push(*bin_array_state);\n            }\n\n            let bin_array_manager = BinArrayManager {\n                bin_arrays: &bin_arrays,\n            };\n\n            for (i, liquidity_share) in position.liquidity_shares.iter().enumerate() {\n                let bin_id = position\n                    .lower_bin_id\n                    .checked_add(i as i32)\n                    .context(\"math is overflow\")?;\n\n                let bin = bin_array_manager.get_bin(bin_id)?;\n                let (bin_amount_x, bin_amount_y) = bin.calculate_out_amount(*liquidity_share)?;\n\n                amount_x = amount_x\n                    .checked_add(bin_amount_x)\n                    .context(\"math is overflow\")?;\n\n                amount_y = amount_y\n                    .checked_add(bin_amount_y)\n                    .context(\"math is overflow\")?;\n            }\n\n            let (fee_x_pending, fee_y_pending) =\n                bin_array_manager.get_total_fee_pending(position)?;\n\n            fee_x = fee_x\n                .checked_add(fee_x_pending)\n                .context(\"math is overflow\")?;\n            fee_y = fee_y\n                .checked_add(fee_y_pending)\n                .context(\"math is overflow\")?;\n        }\n\n        let lb_pair_state = self.lb_pair_state.context(\"Missing lb pair state\")?;\n\n        Ok(PositionRaw {\n            position_len: self.positions.len(),\n            bin_step: lb_pair_state.bin_step,\n            rebalance_time: self.rebalance_time,\n            min_bin_id: self.min_bin_id,\n            active_id: lb_pair_state.active_id,\n            max_bin_id: self.max_bin_id,\n            amount_x,\n            amount_y,\n            fee_x,\n            fee_y,\n            last_update_timestamp: self.last_update_timestamp,\n        })\n    }\n}\n\n#[derive(Default, PartialEq, Debug, Clone, Serialize, Deserialize)]\npub struct PositionRaw {\n    pub position_len: usize,\n    pub rebalance_time: u64,\n    pub max_bin_id: i32,\n    pub active_id: i32,\n    pub min_bin_id: i32,\n    pub bin_step: u16,\n    pub amount_x: u64,\n    pub amount_y: u64,\n    pub fee_x: u64,\n    pub fee_y: u64,\n    pub last_update_timestamp: u64,\n}\n\nimpl PositionRaw {\n    pub fn to_position_info(\n        &self,\n        token_x_decimals: u8,\n        token_y_decimals: u8,\n    ) -> Result<PositionInfo> {\n        let bin_step = self.bin_step;\n\n        let ui_price_adjustment_factor =\n            Decimal::TEN.powi(token_x_decimals as i64 - token_y_decimals as i64);\n\n        let token_x_ui_adjustment_factor = 10f64.powi(token_x_decimals.into());\n        let token_y_ui_adjustment_factor = 10f64.powi(token_y_decimals.into());\n\n        let min_price_fp = get_price_from_id(self.min_bin_id, bin_step)?;\n        let min_price =\n            Decimal::from_u128(min_price_fp).context(\"Math is overflow\")? / Decimal::from(ONE);\n        let adjusted_min_price = min_price\n            .checked_mul(ui_price_adjustment_factor.into())\n            .context(\"Math is overflow\")?\n            .to_f64()\n            .context(\"Math is overflow\")?;\n\n        let max_price_fp = get_price_from_id(self.max_bin_id, bin_step)?;\n        let max_price =\n            Decimal::from_u128(max_price_fp).context(\"Math is overflow\")? / Decimal::from(ONE);\n        let adjusted_max_price = max_price\n            .checked_mul(ui_price_adjustment_factor.into())\n            .context(\"Math is overflow\")?\n            .to_f64()\n            .context(\"Math is overflow\")?;\n\n        let current_price_fp = get_price_from_id(self.active_id, bin_step)?;\n        let current_price =\n            Decimal::from_u128(current_price_fp).context(\"Math is overflow\")? / Decimal::from(ONE);\n        let adjusted_current_price = current_price\n            .checked_mul(ui_price_adjustment_factor.into())\n            .context(\"Math is overflow\")?\n            .to_f64()\n            .context(\"Math is overflow\")?;\n\n        let amount_x = self.amount_x as f64 / token_x_ui_adjustment_factor;\n        let amount_y = self.amount_y as f64 / token_y_ui_adjustment_factor;\n\n        let fee_x = self.fee_x as f64 / token_x_ui_adjustment_factor;\n        let fee_y = self.fee_y as f64 / token_y_ui_adjustment_factor;\n\n        return Ok(PositionInfo {\n            position_len: self.position_len,\n            rebalance_time: self.rebalance_time,\n            max_price: adjusted_max_price,\n            current_price: adjusted_current_price,\n            min_price: adjusted_min_price,\n            amount_x,\n            amount_y,\n            fee_x,\n            fee_y,\n            last_update_timestamp: self.last_update_timestamp,\n        });\n    }\n}\n\n#[derive(Default, PartialEq, Debug, Clone, Serialize, Deserialize)]\npub struct PositionInfo {\n    pub position_len: usize,\n    pub rebalance_time: u64,\n    pub max_price: f64,\n    pub current_price: f64,\n    pub min_price: f64,\n    pub amount_x: f64,\n    pub amount_y: f64,\n    pub fee_x: f64,\n    pub fee_y: f64,\n    pub last_update_timestamp: u64,\n}\n\nimpl SinglePosition {\n    pub fn new(lb_pair: Pubkey) -> Self {\n        SinglePosition {\n            lb_pair,\n            rebalance_time: 0,\n            lb_pair_state: None,\n            bin_arrays: HashMap::new(),\n            positions: vec![],\n            position_pks: vec![],\n            min_bin_id: 0,\n            max_bin_id: 0,\n            last_update_timestamp: 0,\n        }\n    }\n}\n\npub fn get_decimals(token_mint_pk: Pubkey, all_tokens: &HashMap<Pubkey, MintWithProgramId>) -> u8 {\n    let token = all_tokens.get(&token_mint_pk).unwrap();\n    return token.0.decimals;\n}\n"
  },
  {
    "path": "market_making/src/utils.rs",
    "content": "use crate::*;\nuse anchor_spl::associated_token::get_associated_token_address_with_program_id;\nuse commitment_config::CommitmentConfig;\nuse dlmm::events::Swap as SwapEvent;\nuse solana_client::rpc_response::{Response, RpcSimulateTransactionResult};\nuse solana_sdk::instruction::Instruction;\nuse solana_transaction_status::option_serializer::OptionSerializer;\nuse solana_transaction_status::{UiInstruction, UiTransactionEncoding};\nuse spl_associated_token_account::instruction::create_associated_token_account;\nuse std::time::*;\nuse transaction::Transaction;\n\npub fn get_epoch_sec() -> u64 {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs()\n}\n\npub async fn get_or_create_ata(\n    rpc_client: &RpcClient,\n    token_mint: Pubkey,\n    program_id: Pubkey,\n    wallet_address: Pubkey,\n    payer: &Keypair,\n) -> Result<Pubkey> {\n    let user_ata =\n        get_associated_token_address_with_program_id(&wallet_address, &token_mint, &program_id);\n\n    let user_ata_exists = rpc_client.get_account(&user_ata).await.is_ok();\n\n    if !user_ata_exists {\n        let create_ata_ix = create_associated_token_account(\n            &payer.pubkey(),\n            &wallet_address,\n            &token_mint,\n            &program_id,\n        );\n\n        let signature = send_tx(&[create_ata_ix], rpc_client, &[], payer).await?;\n        println!(\"Create ata {token_mint} {wallet_address} {signature}\");\n    }\n\n    Ok(user_ata)\n}\n\npub fn get_transaction_config() -> RpcSendTransactionConfig {\n    let commitment_config = CommitmentConfig::confirmed();\n\n    RpcSendTransactionConfig {\n        skip_preflight: false,\n        preflight_commitment: Some(commitment_config.commitment),\n        encoding: None,\n        max_retries: None,\n        min_context_slot: None,\n    }\n}\n\npub async fn send_tx(\n    instructions: &[Instruction],\n    rpc_client: &RpcClient,\n    keypairs: &[&Keypair],\n    payer: &Keypair,\n) -> Result<Signature> {\n    let latest_blockhash = rpc_client.get_latest_blockhash().await?;\n\n    let mut tx = Transaction::new_signed_with_payer(\n        instructions,\n        Some(&payer.pubkey()),\n        keypairs,\n        latest_blockhash,\n    );\n    tx.sign(&[payer], latest_blockhash);\n\n    let signature = rpc_client.send_and_confirm_transaction(&tx).await?;\n\n    Ok(signature)\n}\n\npub async fn simulate_transaction(\n    instructions: &[Instruction],\n    rpc_client: &RpcClient,\n    keypairs: &[&Keypair],\n    payer: Pubkey,\n) -> Result<Response<RpcSimulateTransactionResult>> {\n    let latest_blockhash = rpc_client.get_latest_blockhash().await?;\n\n    let tx =\n        Transaction::new_signed_with_payer(&instructions, Some(&payer), keypairs, latest_blockhash);\n    let simulation = rpc_client.simulate_transaction(&tx).await?;\n\n    Ok(simulation)\n}\n\npub async fn parse_swap_event(rpc_client: &RpcClient, signature: Signature) -> Result<SwapEvent> {\n    let tx = rpc_client\n        .get_transaction_with_config(\n            &signature,\n            RpcTransactionConfig {\n                encoding: Some(UiTransactionEncoding::Base64),\n                commitment: Some(CommitmentConfig::finalized()),\n                max_supported_transaction_version: Some(0),\n            },\n        )\n        .await?;\n\n    if let Some(meta) = &tx.transaction.meta {\n        if let OptionSerializer::Some(inner_instructions) = meta.inner_instructions.as_ref() {\n            let inner_ixs = inner_instructions\n                .iter()\n                .flat_map(|ix| ix.instructions.as_slice());\n\n            for ix in inner_ixs {\n                match ix {\n                    UiInstruction::Compiled(compiled_ix) => {\n                        if let std::result::Result::Ok(ix_data) =\n                            bs58::decode(compiled_ix.data.as_str()).into_vec()\n                        {\n                            return Ok(SwapEvent::deserialize(&mut ix_data.as_ref())?);\n                        };\n                    }\n                    _ => {}\n                }\n            }\n        }\n    }\n    Err(Error::msg(\"Cannot find swap event\"))\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"dependencies\": {\n    \"pako\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "python-client/dlmm/.gitignore",
    "content": "*/__pycache__"
  },
  {
    "path": "python-client/dlmm/README.md",
    "content": "# DLMM Python SDK\n\n## Using the SDK\n1. Install the SDK and other necessary libraries\n```bash\npip install dlmm solders\n```\n2. Initialize DLMM instance\n```python\nfrom dlmm import DLMM_CLIENT\nfrom solders.pubkey import Pubkey\n\nRPC = \"https://api.devnet.solana.com\"\npool_address = Pubkey.from_string(\"3W2HKgUa96Z69zzG3LK1g8KdcRAWzAttiLiHfYnKuPw5\") # You can get your desired pool address from the API https://dlmm-api.meteora.ag/pair/all\ndlmm = DLMM_CLIENT.create(pool_address, RPC) # Returns DLMM object instance\n```\nNow you can use the `dlmm` object to interact with different methods of the [DLMM](https://docs.meteora.ag/dlmm/dlmm-integration/dlmm-sdk).\n\n## Setup and Run (Development)\n1. Install [poetry](https://python-poetry.org/docs/#installing-with-the-official-installer/).\n2. CD to `python-client/dlmm` and Run `poetry install` to install the dependencies.\n3. Open another terminal, CD to `ts-client`.\n4. Install the dependencies using `npm install` and run the server using `npm start-server`.\n5. In the `dlmm.py`, if the API_URL is not already set to `localhost:3000`.\n6. Add new dependencies using `poetry add package_name`\n7. Now you can add and modify the python code and add tests as required under `dlmm/tests` directory and test them using `poetry run pytest`.\n\n"
  },
  {
    "path": "python-client/dlmm/dlmm/__init__.py",
    "content": "__version__ = \"0.1.0\"\n\nfrom .dlmm import DLMM_CLIENT"
  },
  {
    "path": "python-client/dlmm/dlmm/dlmm.py",
    "content": "import json\nimport requests\nfrom typing import Dict, List, Optional\nfrom solana.transaction import Transaction\nfrom solders.pubkey import Pubkey\nfrom .utils import convert_to_transaction\nfrom .types import ActivationType, ActiveBin, FeeInfo, GetBins, BinArray, Position, GetPositionByUser, Position, PositionInfo, StrategyParameters, SwapQuote, LBPair, TokenReserve, DlmmHttpError as HTTPError\n\nAPI_URL = \"http://localhost:3000\"\n\nclass DLMM:\n    '''\n    DLMM is a class that provides utility methods for interacting with the DLMM API.\n    '''\n    __session: requests.Session\n    pool_address: Pubkey\n    rpc: str\n    lb_pair: LBPair\n    token_X: TokenReserve\n    token_Y: TokenReserve\n\n    def __init__(self, public_key: Pubkey, rpc: str) -> None:\n        if type(public_key) != Pubkey:\n            raise TypeError(\"public_key must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(rpc) != str:\n            raise TypeError(\"rpc must be of type `str`\")\n        \n        self.pool_address = public_key\n        self.rpc = rpc\n        session = requests.Session()\n        session.headers.update({\n            'Content-type': 'application/json', \n            'Accept': 'text/plain',\n            'pool': str(public_key),\n            'rpc': rpc\n        })\n        self.__session = session\n\n        try:\n            result = session.get(f\"{API_URL}/dlmm/create\").json()\n            self.lb_pair = LBPair(result[\"lbPair\"])\n            self.token_X = TokenReserve(result[\"tokenX\"])\n            self.token_Y = TokenReserve(result[\"tokenY\"])\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error creating DLMM: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_active_bin(self) -> ActiveBin:\n        '''\n        The function retrieves the active bin ID and its corresponding price.\n        '''\n        try:\n            result = self.__session.get(f\"{API_URL}/dlmm/get-active-bin\").json()\n            active_bin = ActiveBin(result)\n            return active_bin\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting active bins: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def from_price_per_lamport(self, price: float) -> float:\n        '''\n        The function converts a price per lamport value to a real price of bin.\n\n        Args:\n            price (float): The price per lamport.\n        \n        '''\n        if type(price) != float:\n            raise TypeError(\"price must be of type `float`\")\n        \n        try:\n            data = json.dumps({\n                \"price\": price\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/from-price-per-lamport\", data=data).json()\n            return float(result[\"price\"])\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error converting price per lamports: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def to_price_per_lamport(self, price: float) -> float:\n        '''\n        The function converts a real price of bin to a lamport value.\n\n        Args:\n            price (float): The price per lamport.\n        \n        '''\n        if type(price) != float:\n            raise TypeError(\"price must be of type `float`\")\n        \n        try:\n            data = json.dumps({\n                \"price\": price\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/to-price-per-lamport\", data=data).json()\n            return float(result[\"price\"])\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error converting price per lamports: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def initialize_position_and_add_liquidity_by_strategy(self, position_pub_key: Pubkey, user: Pubkey, x_amount: int, y_amount: int, strategy: StrategyParameters) -> Transaction:\n        '''\n        Initialize position and add liquidity by strategy.\n\n        Args:\n            position_pub_key (Pubkey): The public key of the position.\n            user (Pubkey): The public key of the user.\n            x_amount (int): The total amount of token X to be added to the liquidity pool.\n            y_amount (int): The total amount of token Y to be added to the liquidity pool.\n            strategy (StrategyParameters): The strategy parameters.\n\n        '''\n        if type(position_pub_key) != Pubkey:\n            raise TypeError(\"position_pub_key must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(x_amount) != int:\n            raise TypeError(\"x_amount must be of type `int`\")\n        \n        if type(y_amount) != int:\n            raise TypeError(\"y_amount must be of type `int`\")\n        \n        if isinstance(strategy, dict) == False:\n            raise TypeError(\"strategy must be of type `dict`\")\n        else:\n            if strategy.get(\"max_bin_id\") is None:\n                raise ValueError(\"max_bin_id is required in strategy\")\n            \n            if strategy.get(\"min_bin_id\") is None:\n                raise ValueError(\"min_bin_id is required in strategy\")\n            \n            if strategy.get(\"strategy_type\") is None:\n                raise ValueError(\"strategy_type is required in strategy\")\n        \n        try:\n            data = json.dumps({\n                \"positionPubKey\": str(position_pub_key),\n                \"userPublicKey\": str(user),\n                \"totalXAmount\": x_amount,\n                \"totalYAmount\": y_amount,\n                \"maxBinId\": strategy[\"max_bin_id\"],\n                \"minBinId\": strategy[\"min_bin_id\"],\n                \"strategyType\": str(strategy[\"strategy_type\"])\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/initialize-position-and-add-liquidity-by-strategy\", data=data).json()\n            transaction = convert_to_transaction(result)\n            return transaction\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error initializing position and adding liquidity by strategy: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def add_liquidity_by_strategy(self, position_pub_key: Pubkey, user: Pubkey, x_amount: int, y_amount: int, strategy: StrategyParameters) -> Transaction:\n        '''\n        Add liquidity by strategy to existing position.\n\n        Args:\n            position_pub_key (Pubkey): The public key of the position.\n            user (Pubkey): The public key of the user.\n            x_amount (int): The total amount of token X to be added to the liquidity pool.\n            y_amount (int): The total amount of token Y to be added to the liquidity pool.\n            strategy (StrategyParameters): The strategy parameters.\n\n        '''\n        if type(position_pub_key) != Pubkey:\n            raise TypeError(\"position_pub_key must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(x_amount) != int:\n            raise TypeError(\"x_amount must be of type `int`\")\n        \n        if type(y_amount) != int:\n            raise TypeError(\"y_amount must be of type `int`\")\n        \n        if isinstance(strategy, dict) == False:\n            raise TypeError(\"strategy must be of type `dict`\")\n        else:\n            if strategy.get(\"max_bin_id\") is None:\n                raise ValueError(\"max_bin_id is required in strategy\")\n            \n            if strategy.get(\"min_bin_id\") is None:\n                raise ValueError(\"min_bin_id is required in strategy\")\n            \n            if strategy.get(\"strategy_type\") is None:\n                raise ValueError(\"strategy_type is required in strategy\")\n        \n        try:\n            data = json.dumps({\n                \"positionPubKey\": str(position_pub_key),\n                \"userPublicKey\": str(user),\n                \"totalXAmount\": x_amount,\n                \"totalYAmount\": y_amount,\n                \"maxBinId\": strategy[\"max_bin_id\"],\n                \"minBinId\": strategy[\"min_bin_id\"],\n                \"strategyType\": str(strategy[\"strategy_type\"])\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/add-liquidity-by-strategy\", data=data).json()\n            transaction = convert_to_transaction(result)\n            return transaction\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error adding liquidity by strategy: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def get_positions_by_user_and_lb_pair(self, user: Pubkey) -> GetPositionByUser:\n        '''\n        This function retrieves positions by user and LB pair, including active bin and user positions.\n\n        Args:\n            user (Pubkey): The public key of the user.\n        \n        '''\n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        try:\n            data = json.dumps({\n                \"userPublicKey\": str(user)\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-positions-by-user-and-lb-pair\", data=data).json()\n            return GetPositionByUser(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting positions by user and lb pair: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def remove_liqidity(self, position_pub_key: Pubkey, user: Pubkey, bin_ids: List[int], bps: int, should_claim_and_close: bool) -> List[Transaction]:\n        '''\n        Remove liquidity from the position.\n\n        Args:\n            position_pub_key (Pubkey): The public key of the position account.\n            user (Pubkey): The public key of the user.\n            bin_ids (List[int]): The list bin IDs to remove liquidity from.\n            bps (int): The percentage of liquidity to remove.\n            should_claim_and_close (bool): A boolean flag that indicates whether to claim rewards and close the position.\n        \n        '''\n        if type(position_pub_key) != Pubkey:\n            raise TypeError(\"position_pub_key must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(bin_ids) != list:\n            raise TypeError(\"bin_ids must be of type `list`\")\n        \n        if type(bps) != int:\n            raise TypeError(\"bps must be of type `int`\")\n        \n        if isinstance(should_claim_and_close, bool) == False:\n            raise TypeError(\"should_claim_and_close must be of type `bool`\")\n\n        try:\n            data = json.dumps({\n                \"positionPubKey\": str(position_pub_key),\n                \"userPublicKey\": str(user),\n                \"binIds\": bin_ids,\n                \"bps\": bps,\n                \"shouldClaimAndClose\": should_claim_and_close\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/remove-liquidity\", data=data).json()\n            return [convert_to_transaction(tx_data) for tx_data in result] if type(result) == list else [convert_to_transaction(result)]\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error removing liquidity: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def close_position(self, owner: Pubkey, position: Position) -> Transaction:\n        '''\n        Close the position.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the position.\n            position (Position): The position to close.\n        \n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(position) != Position:\n            raise TypeError(\"position must be of type `dlmm.types.Position`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"position\": position.to_json()\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/close-position\", data=data).json()\n            return convert_to_transaction(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error closing position: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    \n    def get_bin_array_for_swap(self, swap_Y_to_X: bool, count: Optional[int]=4) -> List[dict]:\n        '''\n        This function retrieves a specified number of `BinArrayAccount` objects from the blockchain for swap.\n\n        Args:\n            swap_Y_to_X (bool): A boolean value that indicates whether the swap is using quote token as input.\n            count (Optional[int]): The number of `BinArrayAccount` objects to retrieve.\n        \n        '''\n        if isinstance(swap_Y_to_X, bool) == False:\n            raise TypeError(\"swap_Y_to_X must be of type `bool`\")\n        \n        if count is not None and type(count) != int:\n            raise TypeError(\"count must be of type `int`\")\n\n        try:\n            data = json.dumps({\n                \"swapYToX\": swap_Y_to_X,\n                \"count\": count\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-bin-array-for-swap\", data=data).json()\n            return result\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bin array for swap: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def swap_quote(self, amount: int, swap_Y_to_X: bool, allowed_slippage: int, binArrays: List[dict], is_partial_filled: Optional[bool]=False) -> SwapQuote:\n        '''\n        Get a quote for the swap.\n\n        Args:\n            amount (int): Amount of lamport to swap in.\n            swap_Y_to_X (bool): Swap token X to Y when it is true, else reversed.\n            allowed_slippage (int): Allowed slippage for the swap. Expressed in BPS. To convert from slippage percentage to BPS unit: SLIPPAGE_PERCENTAGE * 100\n            binArrays (List[dict]): The list of bin arrays to use for the swap.\n            is_partial_filled (Optional[bool]): Flag to check whether the the swapQuote is partial fill.\n        \n        '''\n        if type(amount) != int:\n            raise TypeError(\"amount must be of type `int`\")\n        \n        if isinstance(swap_Y_to_X, bool) == False:\n            raise TypeError(\"swap_Y_to_X must be of type `bool`\")\n        \n        if type(allowed_slippage) != int:\n            raise TypeError(\"allowed_slippage must be of type `int`\")\n        \n        if type(binArrays) != list:\n            raise TypeError(\"binArrays must be of type `dict`\")\n        \n        if is_partial_filled is not None and isinstance(is_partial_filled, bool) == False:\n            raise TypeError(\"is_partial_filled must be of type `bool`\")\n        \n        try:\n            data = json.dumps({\n                \"swapYToX\": swap_Y_to_X,\n                \"amount\": amount,\n                \"allowedSlippage\": allowed_slippage,\n                \"binArrays\": binArrays,\n                \"isPartialFilled\": is_partial_filled\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/swap-quote\", data=data).json()\n            return SwapQuote(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error swapping quote: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def swap(self, in_token: Pubkey, out_token: Pubkey, in_amount: int, min_out_amount: int, lb_pair: Pubkey,  user: Pubkey, binArrays: List[Pubkey]) -> Transaction:\n        '''\n        Swap tokens.\n\n        Args:\n            in_token (Pubkey): The public key of the token to swap in.\n            out_token (Pubkey): The public key of the token to swap out.\n            in_amount (int): The amount of token to swap in.\n            min_out_amount (int): The minimum amount of token to swap out.\n            lb_pair (Pubkey): The public key of the liquidity pool pair.\n            user (Pubkey): The public key of the user.\n            binArrays (List[Pubkey]): The list of public keys of the bin arrays to use for the swap.\n        \n        '''\n        if type(in_token) != Pubkey:\n            raise TypeError(\"in_token must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(out_token) != Pubkey:\n            raise TypeError(\"out_token must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(in_amount) != int:\n            raise TypeError(\"in_amount must be of type `int`\")\n        \n        if type(min_out_amount) != int:\n            raise TypeError(\"min_out_amount must be of type `int`\")\n        \n        if type(lb_pair) != Pubkey:\n            raise TypeError(\"lb_pair must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(binArrays) != list:\n            raise TypeError(\"binArrays must be of type `list`\")\n        \n        try:\n            data = json.dumps({\n                \"inToken\": str(in_token),\n                \"outToken\": str(out_token),\n                \"inAmount\": in_amount,\n                \"minOutAmount\": min_out_amount,\n                \"lbPair\": str(lb_pair),\n                \"userPublicKey\": str(user),\n                \"binArrays\": list(map(lambda x: str(x), binArrays))\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/swap\", data=data).json()\n            return convert_to_transaction(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error swapping: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\n    def refetch_states(self) -> None:\n        '''\n        This function retrieves and updates various states and data related to bin arrays and lb pairs\n        '''\n        try:\n            result = self.__session.get(f\"{API_URL}/dlmm/refetch-states\")\n            return None\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error refetching states: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_bin_arrays(self) -> list[BinArray]:\n        '''\n        This function retrieves all bin arrays from the blockchain.\n        '''\n        try:\n            result = self.__session.get(f\"{API_URL}/dlmm/get-bin-arrays\").json()\n            return [BinArray(bin_data) for bin_data in result]\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bin arrays: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_fee_info(self) -> FeeInfo:\n        '''\n        This function calculates and returns the base fee rate percentage, maximum fee rate percentage, and protocol fee percentage.\n        '''\n        try:\n            result = self.__session.get(f\"{API_URL}/dlmm/get-fee-info\").json()\n            return FeeInfo(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting fee info: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_dynamic_fee(self) -> float:\n        '''\n        This function calculates and returns the dynamic fee.\n        '''\n        try:\n            result = self.__session.get(f\"{API_URL}/dlmm/get-dynamic-fee\").json()\n            return float(result['fee'])\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting dynamic fee: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_bin_id_from_price(self, price: float, min: bool) -> int | None:\n        '''\n        The function get bin ID based on a given price and a boolean flag indicating whether to round down or up.\n\n        Args:\n            price (float): The price of the bin.\n            min (bool): A boolean value that determines whether to round down or round up the calculated binId. If \"min\" is true, the bin_id will be rounded down (floor), otherwise it will be rounded up (ceil).\n        \n        '''\n        if type(price) != float:\n            raise TypeError(\"price must be of type `float`\")\n\n        if isinstance(min, bool) == False:\n            raise TypeError(\"min must be of type `bool`\")\n        \n        try:\n            data = json.dumps({\n                \"price\": price,\n                \"min\": min\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-bin-id-from-price\", data=data).json()\n            return int(result['binId']) if result.get('binId') is not None else None\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bin id from price: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_bins_around_active_bin(self, number_of_bins_to_left: int, number_of_bins_to_right: int) -> GetBins:\n        '''\n        The function retrieves a specified number of bins to the left and right of the active bin and returns them along with the active bin ID.\n\n        Args:\n            number_of_bins_to_left (int): The number of bins to the left of the active bin.  It determines how many bins you want to include in the result that are positioned to the left of the active bin.\n            number_of_bins_to_right (int): The number of bins to the right of the active bin. It determines how many bins you want to include in the result that are positioned to the right of the active bin.\n        \n        '''\n        \n        if type(number_of_bins_to_left) != int:\n            raise TypeError(\"number_of_bins_to_left must be of type `int`\")\n        \n        if type(number_of_bins_to_right) != int:\n            raise TypeError(\"number_of_bins_to_right must be of type `int`\")\n        \n        try:\n            data = json.dumps({\n                \"numberOfBinsToTheLeft\": number_of_bins_to_left,\n                \"numberOfBinsToTheRight\": number_of_bins_to_right\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-bins-around-active-bin\", data=data).json()\n            return GetBins(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bins around active bin: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_bins_between_min_and_max_price(self, min_price: float, max_price: float) -> GetBins:\n        '''\n        The function retrieves a list of bins within a specified price range.\n\n        Args:\n            min_price (float): The minimum price.\n            max_price (float): The maximum price.\n        \n        '''\n        if type(min_price) != float:\n            raise TypeError(\"min_price must be of type `float`\")\n        \n        if type(max_price) != float:\n            raise TypeError(\"max_price must be of type `float`\")\n        \n        try:\n            data = json.dumps({\n                \"minPrice\": min_price,\n                \"maxPrice\": max_price\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-bins-between-min-and-max-price\", data=data).json()\n            return GetBins(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bins between min and max price: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def get_bins_between_lower_and_upper_bound(self, lower_bound: int, upper_bound: int) -> GetBins:\n        '''\n        The function retrieves a list of bins within a specified range of bin IDs.\n\n        Args:\n            lower_bound (int): A number that represents the ID of the lowest bin.\n            upper_bound (int): A number that represents the ID of the highest bin.\n\n        '''\n        if type(lower_bound) != int:\n            raise TypeError(\"lower_bound must be of type `int`\")\n        \n        if type(upper_bound) != int:\n            raise TypeError(\"upper_bound must be of type `int`\")\n        \n        try:\n            data = json.dumps({\n                \"lowerBound\": lower_bound,\n                \"upperBound\": upper_bound\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/get-bins-between-lower-and-upper-bound\", data=data).json()\n            return GetBins(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting bins between lower and upper bound: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def claim_LM_reward(self, owner: Pubkey, position: Position) -> Transaction:\n        '''\n        The function is used to claim rewards for a specific position owned by a specific owner.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the position.\n            position (Position): The position to claim rewards from.\n            \n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"position\": position.to_json()\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/claim-lm-reward\", data=data).json()\n            return convert_to_transaction(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error claiming LM rewards: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def claim_all_LM_reards(self, owner: Pubkey, positions: List[Position]) -> List[Transaction]:\n        '''\n        The function is used to claim all liquidity mining rewards for a given owner and their positions.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the positions.\n            positions (List[Position]): The list of positions to claim rewards from.\n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(positions) != list:\n            raise TypeError(\"positions must be of type `list`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"positions\": [position.to_json() for position in positions]\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/claim-all-lm-rewards\", data=data).json()\n            return [convert_to_transaction(tx) for tx in result]\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error claiming all LM rewards: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def claim_swap_fee(self, owner: Pubkey, position: Position) -> Transaction:\n        '''\n        The function is used to claim swap fee for a specific position owned by a specific owner.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the position.\n            position (Position): The position to claim swap fee from.\n        \n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(position) != Position:\n            raise TypeError(\"position must be of type `dlmm.types.Position`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"position\": position.to_json()\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/claim-swap-fee\", data=data).json()\n            return convert_to_transaction(result)\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error claiming swap fee: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def claim_all_swap_fees(self, owner: Pubkey, positions: List[Position]) -> List[Transaction]:\n        '''\n        The function is used to claim all swap fees for a given owner and their positions.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the positions.\n            positions (List[Position]): The list of positions to claim swap fees from.\n        \n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(positions) != list:\n            raise TypeError(\"positions must be of type `list`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"positions\": [position.to_json() for position in positions]\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/claim-all-swap-fee\", data=data).json()\n            return [convert_to_transaction(tx) for tx in result]\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error claiming all swap fees: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n    \n    def claim_all_rewards(self, owner: Pubkey, positions: List[Position]) -> List[Transaction]:\n        '''\n        The function to claim swap fees and LM rewards for multiple positions owned by a specific owner.\n\n        Args:\n            owner (Pubkey): The public key of the owner of the positions.\n            positions (List[Position]): The list of positions to claim rewards from.\n        \n        '''\n        if type(owner) != Pubkey:\n            raise TypeError(\"owner must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(positions) != list:\n            raise TypeError(\"positions must be of type `list`\")\n        \n        try:\n            data = json.dumps({\n                \"owner\": str(owner),\n                \"positions\": [position.to_json() for position in positions]\n            })\n            result = self.__session.post(f\"{API_URL}/dlmm/claim-all-rewards\", data=data).json()\n            return [convert_to_transaction(tx) for tx in result]\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error claiming all rewards: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n\nclass DLMM_CLIENT:\n    '''\n    DLMM_CLIENT is a class that provides utility methods for interacting with the DLMM API using DLMM class object.\n    '''\n\n    @staticmethod\n    def create(public_key: Pubkey, rpc: str) -> DLMM:\n        '''\n        Create a DLMM object using the public key of the pool and the RPC URL.\n\n        Args:\n            public_key (Pubkey): The public key of the pool.\n            rpc (str): The RPC URL.\n        \n        '''\n        if isinstance(public_key, Pubkey) == False:\n            raise TypeError(\"public_key must be of type `solders.pubkey.Pubkey`\")\n        \n        return DLMM(public_key, rpc)\n    \n    @staticmethod\n    def create_multiple(public_keys: List[Pubkey], rpc: str) -> List[DLMM]:\n        '''\n        Create multiple DLMM objects using the public keys of the pools and the RPC URL.\n\n        Args:\n            public_keys (List[Pubkey]): The public keys of the pools.\n            rpc (str): The RPC URL\n        \n        '''\n        if type(public_keys) != list:\n            raise TypeError(\"public_keys must be of type `list`\")\n        \n        return [DLMM(public_keys, rpc) for public_keys in public_keys]\n    \n    @staticmethod\n    def get_all_lb_pair_positions_by_user(user: Pubkey, rpc: str) -> Dict[str, PositionInfo]:\n        '''\n        Get all lb pair positions by user.\n\n        Args:\n            user (Pubkey): The public key of the user.\n            rpc (str): The RPC URL.\n        \n        '''\n        if type(user) != Pubkey:\n            raise TypeError(\"user must be of type `solders.pubkey.Pubkey`\")\n        \n        if type(rpc) != str:\n            raise TypeError(\"rpc must be of type `str`\")\n        \n        try:\n            session = requests.Session()\n            session.headers.update({\n                'Content-type': 'application/json', \n                'Accept': 'text/plain',\n                'rpc': rpc,\n                'pool': \"2EszZfwee7myuECGizcprwsC5jymGTVVEqPG5uVRRbmb\"\n                # There needs to be some pool passed or else it errors\n                # Could fix the error in TS but would have to rewrite the handler\n\n            })\n            data = json.dumps({\n                \"user\": str(user)\n            })\n            result = session.post(f\"{API_URL}/dlmm/get-all-lb-pair-positions-by-user\", data=data).json()\n            return {key: PositionInfo(value) for key, value in result.items()}\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error getting all lb pair positions by user: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")\n        \n    @staticmethod\n    def create_customizable_permissionless_lb_pair(\n        bin_step: int,\n        token_x: Pubkey,\n        token_y: Pubkey,\n        active_id: int,\n        fee_bps: int,\n        activation_type: int,\n        has_alpha_vault: bool,\n        creator_key: Pubkey,\n        activation_point: Optional[int] = None\n    ) -> Transaction:\n        \n        if(type(bin_step) != int):\n            raise TypeError(\"bin_step must be of type `int`\")\n        \n        if(type(token_x) != Pubkey):\n            raise TypeError(\"token_x must be of type `solders.pubkey.Pubkey`\")\n        \n        if(type(token_y) != Pubkey):\n            raise TypeError(\"token_y must be of type `solders.pubkey.Pubkey`\")\n        \n        if(type(active_id) != int):\n            raise TypeError(\"active_id must be of type `int`\")\n        \n        if(type(fee_bps) != int):\n            raise TypeError(\"fee_bps must be of type `int`\")\n        \n        if(type(activation_type) != int):\n            raise TypeError(\"activation_type must be of type `int`\")\n        \n        if(type(has_alpha_vault) != bool):\n            raise TypeError(\"has_alpha_vault must be of type `bool`\")\n        \n        if(type(creator_key) != Pubkey):\n            raise TypeError(\"creator_key must be of type `solders.pubkey.Pubkey`\")\n        \n        if(activation_point is not None and type(activation_point) != int):\n            raise TypeError(\"activation_point must be of type `int`\")\n        \n        try:\n            data = json.dumps({\n                \"binStep\": bin_step,\n                \"tokenX\": str(token_x),\n                \"tokenY\": str(token_y),\n                \"activeId\": active_id,\n                \"feeBps\": fee_bps,\n                \"activationType\": activation_type,\n                \"hasAlphaVault\": has_alpha_vault,\n                \"creatorKey\": str(creator_key),\n                \"activationPoint\": activation_point\n            })\n            result = requests.post(f\"{API_URL}/dlmm/create-customizable-permissionless-lb-pair\", data=data).json()\n            return convert_to_transaction(result)\n\n        except requests.exceptions.HTTPError as e:\n            raise HTTPError(f\"Error creating customizable permissionless lb pair: {e}\")\n        except requests.exceptions.ConnectionError as e:\n            raise HTTPError(f\"Error connecting to DLMM: {e}\")"
  },
  {
    "path": "python-client/dlmm/dlmm/types.py",
    "content": "from dataclasses import dataclass\nfrom enum import Enum\nfrom solders.pubkey import Pubkey\nfrom typing import Any, List, TypedDict, Union\n\nclass DlmmHttpError(Exception):\n    def __init__(self, message):\n        super().__init__(message)\n\nclass StrategyType(Enum):\n    SpotOneSide=0,\n    CurveOneSide=1,\n    BidAskOneSide=2,\n    SpotImBalanced=3,\n    CurveImBalanced=4,\n    BidAskImBalanced=5,\n    SpotBalanced=6,\n    CurveBalanced=7,\n    BidAskBalanced=8\n\n    def __str__(self) -> str:\n        return f\"{self.value[0]}\"\n    \n    def __repr__(self) -> str:\n        return self.name\n\nclass ActivationType(Enum):  \n    Slot=0,\n    Timestamp=1,\n\n    def __str__(self) -> str:\n        return self.value[1]\n    \n    def __repr__(self) -> str:\n        return self.name\n\n\nclass PositionVersion(Enum):\n    V1=\"V1\",\n    V2=\"V2\"\n\n    def __str__(self) -> str:\n        return self.name\n    \n    def __repr__(self) -> str:\n        return self.name\n\nclass StrategyParameters(TypedDict):\n    max_bin_id: int\n    min_bin_id: int\n    strategy_type: StrategyType\n\n@dataclass\nclass ActiveBin():\n    bin_id: int\n    x_amount: str\n    y_amount: str\n    supply: str\n    price: float\n    version: int\n    price_per_token: str\n\n    def __init__(self, data: dict):\n        self.bin_id = data[\"binId\"]\n        self.x_amount = data[\"xAmount\"]\n        self.y_amount = data[\"yAmount\"]\n        self.supply = data[\"supply\"]\n        self.price = float(data[\"price\"])\n        self.version = data[\"version\"]\n        self.price_per_token = data[\"pricePerToken\"]\n\n@dataclass\nclass PositionBinData():\n    bin_id: int\n    price: str\n    price_per_token: str\n    bin_x_Amount: str\n    bin_y_Amount: str\n    bin_liquidity: str\n    position_liquidity: str\n    position_x_amount: str\n    position_y_amount: str\n\n    def __init__(self, data: dict):\n        if data.get(\"binId\") is None:\n            raise AttributeError(\"binId is required\")\n        if data.get(\"price\") is None:\n            raise AttributeError(\"price is required\")\n        if data.get(\"pricePerToken\") is None:\n            raise AttributeError(\"pricePerToken is required\")\n        if data.get(\"binXAmount\") is None:\n            raise AttributeError(\"binXAmount is required\")\n        if data.get(\"binYAmount\") is None:\n            raise AttributeError(\"binYAmount is required\")\n        if data.get(\"binLiquidity\") is None:\n            raise AttributeError(\"binLiquidity is required\")\n        if data.get(\"positionLiquidity\") is None:\n            raise AttributeError(\"positionLiquidity is required\")\n        if data.get(\"positionXAmount\") is None:\n            raise AttributeError(\"positionXAmount is required\")\n        if data.get(\"positionYAmount\") is None:\n            raise AttributeError(\"positionYAmount is required\")\n\n        self.bin_id = data[\"binId\"]\n        self.price = data[\"price\"]\n        self.price_per_token = data[\"pricePerToken\"]\n        self.bin_x_Amount = data[\"binXAmount\"]\n        self.bin_y_Amount = data[\"binYAmount\"]\n        self.bin_liquidity = data[\"binLiquidity\"]\n        self.position_liquidity = data[\"positionLiquidity\"]\n        self.position_x_amount = data[\"positionXAmount\"]\n        self.position_y_amount = data[\"positionYAmount\"]\n\n    def to_json(self) -> dict:\n        return {\n            \"binId\": self.bin_id,\n            \"price\": self.price,\n            \"pricePerToken\": self.price_per_token,\n            \"binXAmount\": self.bin_x_Amount,\n            \"binYAmount\": self.bin_y_Amount,\n            \"binLiquidity\": self.bin_liquidity,\n            \"positionLiquidity\": self.position_liquidity,\n            \"positionXAmount\": self.position_x_amount,\n            \"positionYAmount\": self.position_y_amount\n        }\n\n@dataclass\nclass PositionData():\n    total_x_amount: str\n    total_y_amount: str\n    position_bin_data: List[PositionBinData]\n    last_updated_at: int\n    upper_bin_id: int\n    lower_bin_id: int\n    fee_X: int\n    fee_Y: int\n    reward_one: int\n    reward_two: int\n    fee_owner: str\n    total_claimed_fee_X_amount: int\n    total_claimed_fee_Y_amount: int\n\n    def __init__(self, data: dict):\n        if data.get(\"totalXAmount\") is None:\n            raise AttributeError(\"totalXAmount is required\")\n        if data.get(\"totalYAmount\") is None:\n            raise AttributeError(\"totalYAmount is required\")\n        if data.get(\"positionBinData\") is None:\n            raise AttributeError(\"positionBinData is required\")\n        if data.get(\"lastUpdatedAt\") is None:\n            raise AttributeError(\"lastUpdatedAt is required\")\n        if data.get(\"upperBinId\") is None:\n            raise AttributeError(\"upperBinId is required\")\n        if data.get(\"lowerBinId\") is None:\n            raise AttributeError(\"lowerBinId is required\")\n        if data.get(\"feeX\") is None:\n            raise AttributeError(\"feeX is required\")\n        if data.get(\"feeY\") is None:\n            raise AttributeError(\"feeY is required\")\n        if data.get(\"rewardOne\") is None:\n            raise AttributeError(\"rewardOne is required\")\n        if data.get(\"rewardTwo\") is None:\n            raise AttributeError(\"rewardTwo is required\")\n        if data.get(\"feeOwner\") is None:\n            raise AttributeError(\"feeOwner is required\")\n        if data.get(\"totalClaimedFeeXAmount\") is None:\n            raise AttributeError(\"totalClaimedFeeXAmount is required\")\n        if data.get(\"totalClaimedFeeYAmount\") is None:\n            raise AttributeError(\"totalClaimedFeeYAmount is required\")\n\n        self.total_x_amount = data[\"totalXAmount\"]\n        self.total_y_amount = data[\"totalYAmount\"]\n        self.position_bin_data = [PositionBinData(bin_data) for bin_data in data[\"positionBinData\"]]\n        self.last_updated_at = int(data[\"lastUpdatedAt\"], 16)\n        self.upper_bin_id = data[\"upperBinId\"]\n        self.lower_bin_id = data[\"lowerBinId\"]\n        self.fee_X = int(data[\"feeX\"], 16)\n        self.fee_Y = int(data[\"feeY\"], 16)\n        self.reward_one = data[\"rewardOne\"]\n        self.reward_two = data[\"rewardTwo\"]\n        self.fee_owner = data[\"feeOwner\"]\n        self.total_claimed_fee_X_amount = int(data[\"totalClaimedFeeXAmount\"], 16)\n        self.total_claimed_fee_Y_amount = int(data[\"totalClaimedFeeYAmount\"], 16)\n    \n    def to_json(self) -> dict:\n        return {\n            \"totalXAmount\": self.total_x_amount,\n            \"totalYAmount\": self.total_y_amount,\n            \"positionBinData\": [bin_data.to_json() for bin_data in self.position_bin_data],\n            \"lastUpdatedAt\": self.last_updated_at,\n            \"upperBinId\": self.upper_bin_id,\n            \"lowerBinId\": self.lower_bin_id,\n            \"feeX\": self.fee_X,\n            \"feeY\": self.fee_Y,\n            \"rewardOne\": self.reward_one,\n            \"rewardTwo\": self.reward_two,\n            \"feeOwner\": self.fee_owner,\n            \"totalClaimedFeeXAmount\": self.total_claimed_fee_X_amount,\n            \"totalClaimedFeeYAmount\": self.total_claimed_fee_Y_amount\n        }\n\n@dataclass\nclass  Position():\n    public_key: Pubkey\n    position_data: PositionData\n    position_version: PositionVersion\n\n    def __init__(self, data: dict):\n        if data.get(\"publicKey\") is None:\n            raise AttributeError(\"publicKey is required\")\n        if data.get(\"positionData\") is None:\n            raise AttributeError(\"positionData is required\")\n        if data.get(\"version\") is None:\n            raise AttributeError(\"version is required\")\n\n        self.public_key = Pubkey.from_string(data[\"publicKey\"])\n        self.position_data = PositionData(data[\"positionData\"])\n        self.position_version = data[\"version\"]\n    \n    def to_json(self):\n        return {\n            \"publicKey\": str(self.public_key),\n            \"positionData\": self.position_data.to_json(),\n            \"version\": str(self.position_version)\n        }\n\n@dataclass\nclass GetPositionByUser():\n    active_bin: ActiveBin\n    user_positions: List[Position]\n\n    def __init__(self, data: dict):\n        self.active_bin = ActiveBin(data[\"activeBin\"])\n        self.user_positions = [Position(position) for position in data[\"userPositions\"]]\n\n@dataclass\nclass SwapQuote():\n    consumed_in_amount: int\n    out_amount: int\n    fee: int\n    protocol_fee: int\n    min_out_amount: int\n    price_impact: float\n    bin_arrays_pubkey: List[Pubkey]\n\n    def __init__(self, data: dict):\n        self.consumed_in_amount = int(data[\"consumedInAmount\"])\n        self.out_amount = int(data[\"outAmount\"])\n        self.fee = int(data[\"fee\"])\n        self.protocol_fee = int(data[\"protocolFee\"])\n        self.min_out_amount = int(data[\"minOutAmount\"])\n        self.price_impact = float(data[\"priceImpact\"])\n        self.bin_arrays_pubkey = list(map(lambda x: Pubkey.from_string(x), data[\"binArraysPubkey\"]))\n\nclass LBPair:\n    bump_seed: List[int]\n    bin_step_seed: List[int]\n    pair_type: int\n    active_id: int\n    bin_step: int\n    status: int\n    require_base_factor_seed: int\n    base_factor_seed: List[int]\n    token_x_mint: str\n    token_y_mint: str\n    padding1: List[int]\n    padding2: List[int]\n    fee_owner: Union[Pubkey, None]\n    base_key: str\n\n    def __init__(self, data: dict) -> None:\n        self.bump_seed = data[\"bumpSeed\"]\n        self.bin_step_seed = data[\"binStepSeed\"]\n        self.pair_type = data[\"pairType\"]\n        self.active_id = data[\"activeId\"]\n        self.bin_step = data[\"binStep\"]\n        self.status = data[\"status\"]\n        self.require_base_factor_seed = data[\"requireBaseFactorSeed\"]\n        self.base_factor_seed = data[\"baseFactorSeed\"]\n        self.token_x_mint = data[\"tokenXMint\"]\n        self.token_y_mint = data[\"tokenYMint\"]\n        self.padding1 = data[\"padding1\"]\n        self.padding2 = data[\"padding2\"]\n        fee_owner = data.get(\"feeOwner\", None)\n        self.fee_owner = Pubkey.from_string(fee_owner) if fee_owner else fee_owner\n        self.base_key = data[\"baseKey\"]\n        \n@dataclass\nclass TokenReserve():\n    public_key: Pubkey\n    reserve: Pubkey\n    amount: str\n    decimal: Union[int, None]\n\n    def __init__(self, data: dict) -> None:\n        self.public_key = Pubkey.from_string(data[\"publicKey\"])\n        self.reserve = Pubkey.from_string(data[\"reserve\"])\n        self.amount = data[\"amount\"]\n        decimal = data.get(\"decimal\", None)\n        self.decimal = decimal\n\n@dataclass\nclass PositionInfo():\n    public_key: Pubkey\n    lb_pair: Any\n    token_x: TokenReserve\n    token_y: TokenReserve\n    lb_pair_positions_data: List[Position]\n\n    def __init__(self, data: dict) -> None:\n        self.public_key = Pubkey.from_string(data[\"publicKey\"])\n        self.lb_pair = data[\"lbPair\"]\n        self.token_x = TokenReserve(data[\"tokenX\"])\n        self.token_y = TokenReserve(data[\"tokenY\"])\n        self.lb_pair_positions_data = [Position(position) for position in data[\"lbPairPositionsData\"]]\n\n@dataclass\nclass FeeInfo():\n    base_fee_rate_percentage: float\n    max_fee_rate_percentage: float\n    protocol_fee_percentage: float\n\n    def __init__(self, data: dict) -> None:\n        self.base_fee_rate_percentage = float(data[\"baseFeeRatePercentage\"])\n        self.max_fee_rate_percentage = float(data[\"maxFeeRatePercentage\"])\n        self.protocol_fee_percentage = float(data[\"protocolFeePercentage\"])\n\n@dataclass\nclass BinLiquidty():\n    bin_id: int\n    x_amount: str\n    y_amount: str\n    supply: str\n    version: int\n    price: str\n    price_per_token: str\n\n    def __init__(self, data: dict) -> None:\n        if data.get(\"binId\") is None:\n            raise AttributeError(\"binId is required\")\n        if data.get(\"xAmount\") is None:\n            raise AttributeError(\"xAmount is required\")\n        if data.get(\"yAmount\") is None:\n            raise AttributeError(\"yAmount is required\")\n        if data.get(\"supply\") is None:\n            raise AttributeError(\"supply is required\")\n        if data.get(\"version\") is None:\n            raise AttributeError(\"version is required\")\n        if data.get(\"price\") is None:\n            raise AttributeError(\"price is required\")\n        \n        self.bin_id = int(data[\"binId\"])\n        self.x_amount = data[\"xAmount\"]\n        self.y_amount = data[\"yAmount\"]\n        self.supply = data[\"supply\"]\n        self.version = int(data[\"version\"])\n        self.price = data[\"price\"]\n        self.price_per_token = data[\"pricePerToken\"]\n\n@dataclass\nclass GetBins():\n    active_bin: int\n    bin_liquidty: List[BinLiquidty]\n\n    def __init__(self, data: dict) -> None:\n        if data.get(\"activeBin\") is None:\n            raise AttributeError(\"activeBin is required\")\n        \n        if data.get(\"bins\") is None:\n            raise AttributeError(\"bins is required\")\n        \n        self.active_bin = int(data[\"activeBin\"])\n        self.bin_liquidty = [BinLiquidty(bin_data) for bin_data in data[\"bins\"]]\n\n@dataclass\nclass Bin:\n    amount_x: int\n    amount_x_in: int\n    amount_y: int\n    amount_y_in: int\n    fee_amount_x_per_token_stored: int\n    fee_amount_y_per_token_stored: int\n    liquidity_supply: int\n    price: int\n    reward_per_token_stored: List[int]\n\n    def __init__(self, data: dict) -> None:\n        self.amount_x = int(data[\"amountX\"], 16)\n        self.amount_x_in = int(data[\"amountXIn\"], 16)\n        self.amount_y = int(data[\"amountY\"], 16)\n        self.amount_y_in = int(data[\"amountYIn\"], 16)\n        self.fee_amount_x_per_token_stored = int(data[\"feeAmountXPerTokenStored\"], 16)\n        self.fee_amount_y_per_token_stored = int(data[\"feeAmountYPerTokenStored\"], 16)\n        self.liquidity_supply = int(data[\"liquiditySupply\"], 16)\n        self.price = int(data[\"price\"], 16)\n        self.reward_per_token_stored = [int(r, 16) for r in data[\"rewardPerTokenStored\"]]\n\n\n@dataclass\nclass BinAccount:\n    index: int\n    bins: List[Bin]\n\n    def __init__(self, data: dict) -> None:\n        self.index = int(data[\"index\"], 16)\n        self.bins = [Bin(b) for b in data[\"bins\"]]\n\n\n@dataclass\nclass BinArray:\n    public_key: str\n    account: BinAccount\n\n    def __init__(self, data: dict) -> None:\n        self.public_key = data[\"publicKey\"]\n        self.account = BinAccount(data[\"account\"])\n"
  },
  {
    "path": "python-client/dlmm/dlmm/utils.py",
    "content": "from typing import List\nfrom solders.hash import Hash\nfrom solders.pubkey import Pubkey\nfrom solders.keypair import Keypair\nfrom solana.transaction import Transaction\nfrom solders.instruction import Instruction, AccountMeta\n\ndef convert_to_transaction(response: dict) -> Transaction:\n    recent_blockhash = Hash.from_string(response[\"recentBlockhash\"])\n    fee_payer = Pubkey.from_string(response[\"feePayer\"])\n\n    instructions: List[Instruction] = []\n    for instruction in response[\"instructions\"]:\n        keys = [AccountMeta(Pubkey.from_string(key[\"pubkey\"]), key[\"isSigner\"], key[\"isWritable\"]) for key in instruction[\"keys\"]]\n        data = bytes(instruction['data'])\n        program_id = Pubkey.from_string(instruction['programId'])\n        compiled_instruction = Instruction(\n            program_id=program_id,\n            data=data,\n            accounts=keys\n        )\n        instructions.append(compiled_instruction)\n\n    transaction = Transaction(\n        recent_blockhash=recent_blockhash, \n        instructions=instructions,\n        fee_payer=fee_payer,\n    )\n\n    return transaction\n\n"
  },
  {
    "path": "python-client/dlmm/pyproject.toml",
    "content": "[tool.poetry]\nname = \"dlmm\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Tanishq Parkar <tanishqparkar@gmail.com>\"]\nreadme = \"README.md\"\n\n[tool.poetry.dependencies]\npython = \"^3.12\"\nsolders = \"^0.21.0\"\nsolana = \"^0.34.3\"\nrequests = \"^2.32.3\"\n\n\n[tool.poetry.group.dev.dependencies]\npytest = \"^8.3.2\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\n"
  },
  {
    "path": "python-client/dlmm/tests/__init__.py",
    "content": ""
  },
  {
    "path": "python-client/dlmm/tests/test_lp_flow.py",
    "content": "import pytest\nfrom dlmm import DLMM_CLIENT\nfrom dlmm.dlmm import DLMM\nfrom dlmm.types import GetPositionByUser, StrategyType, SwapQuote\nfrom solders.keypair import Keypair\nfrom solders.pubkey import Pubkey\nfrom solana.rpc.api import Client\nfrom solana.transaction import Transaction\n\ndef test_flow():\n    RPC = \"https://api.devnet.solana.com\"\n    pool_address = Pubkey.from_string(\"3W2HKgUa96Z69zzG3LK1g8KdcRAWzAttiLiHfYnKuPw5\")\n    client = Client(RPC)\n    dlmm = DLMM_CLIENT.create(pool_address, RPC)\n    assert isinstance(dlmm, DLMM)\n\n    active_bin = dlmm.get_active_bin()\n    active_bin_price_per_token = dlmm.from_price_per_lamport(active_bin.price)\n    assert type(active_bin_price_per_token) == float\n\n    user = Keypair.from_bytes([3, 65, 174, 194, 140, 162, 138, 46, 167, 188, 153, 227, 110, 110, 82, 167, 238, 92, 174, 250, 66, 104, 188, 196, 164, 72, 222, 202, 150, 52, 38, 249, 205, 59, 43, 173, 101, 40, 208, 183, 241, 9, 237, 75, 52, 240, 165, 65, 91, 247, 233, 207, 170, 155, 162, 181, 215, 135, 103, 2, 132, 32, 196, 16])\n\n    new_balance_position = Keypair()\n\n    total_interval_range = 10\n    max_bin_id = active_bin.bin_id + total_interval_range\n    min_bin_id = active_bin.bin_id - total_interval_range\n    total_x_amount = 100\n    total_y_amount = total_x_amount * int(active_bin_price_per_token)\n\n    position_tx = dlmm.initialize_position_and_add_liquidity_by_strategy(\n        new_balance_position.pubkey(),\n        user.pubkey(), \n        total_x_amount, \n        total_y_amount, \n        {\n            \"max_bin_id\": max_bin_id, \n            \"min_bin_id\": min_bin_id, \n            \"strategy_type\": 0\n        })\n\n    assert isinstance(position_tx, Transaction)\n\n    client.send_transaction(position_tx, user, new_balance_position)\n    print(\"Transaction sent\")\n\n    positions = dlmm.get_positions_by_user_and_lb_pair(user.pubkey())\n    assert isinstance(positions, GetPositionByUser)\n\n    add_liquidity_tx = dlmm.add_liquidity_by_strategy(\n        new_balance_position.pubkey(), \n        user.pubkey(), \n        total_x_amount, \n        total_y_amount, \n        {\n            \"max_bin_id\": max_bin_id, \n            \"min_bin_id\": min_bin_id, \n            \"strategy_type\": StrategyType.SpotBalanced\n        })\n    assert isinstance(add_liquidity_tx, Transaction)\n\n    client.send_transaction(add_liquidity_tx, user)\n    print(\"Transaction sent\")\n\n    user_positions = next(filter(lambda x: x.public_key == new_balance_position.pubkey() ,positions.user_positions), None)\n\n    if user_positions:\n        bin_ids_to_remove = list(map(lambda x: x.bin_id, user_positions.position_data.position_bin_data))\n        remove_liquidity = dlmm.remove_liqidity(\n            new_balance_position.pubkey(),\n            user.pubkey(),\n            bin_ids_to_remove,\n            100*100,\n            True\n        )\n        assert isinstance(remove_liquidity, list)\n        client.send_transaction(remove_liquidity, user)\n\n    swap_amount = 100\n    swap_y_to_x = True\n    bin_arrays = dlmm.get_bin_array_for_swap(swap_y_to_x)\n    swap_quote = dlmm.swap_quote(swap_amount, swap_y_to_x, 10, bin_arrays)\n    assert isinstance(swap_quote, SwapQuote)\n\n    swap_tx = dlmm.swap(\n        dlmm.token_X.public_key,\n        dlmm.token_Y.public_key,\n        swap_amount,\n        swap_quote.min_out_amount,\n        dlmm.pool_address,\n        user.pubkey(),\n        swap_quote.bin_arrays_pubkey\n        )\n    assert isinstance(swap_tx, Transaction)\n\n    client.send_transaction(swap_tx, user)\n\n\n    "
  },
  {
    "path": "python-client/dlmm/tests/test_util_methods.py",
    "content": "from dlmm.dlmm import DLMM, DLMM_CLIENT\nfrom solana.rpc.api import Client\nfrom solders.pubkey import Pubkey\nfrom dlmm.types import FeeInfo, GetBins, Position\nfrom solders.keypair import Keypair\nfrom solana.transaction import Transaction\n\ndef test_util_methods():\n    RPC = \"https://api.devnet.solana.com\"\n    pool_address = Pubkey.from_string(\"3W2HKgUa96Z69zzG3LK1g8KdcRAWzAttiLiHfYnKuPw5\")\n    # client = Client(RPC)\n    dlmm = DLMM_CLIENT.create(pool_address, RPC)\n    assert isinstance(dlmm, DLMM)\n\n    user = Keypair.from_bytes([3, 65, 174, 194, 140, 162, 138, 46, 167, 188, 153, 227, 110, 110, 82, 167, 238, 92, 174, 250, 66, 104, 188, 196, 164, 72, 222, 202, 150, 52, 38, 249, 205, 59, 43, 173, 101, 40, 208, 183, 241, 9, 237, 75, 52, 240, 165, 65, 91, 247, 233, 207, 170, 155, 162, 181, 215, 135, 103, 2, 132, 32, 196, 16])\n\n    new_balance_position = Keypair()\n    #new_balance_position = Keypair.from_bytes([32, 144, 75, 246, 203, 27, 190, 52, 136, 171, 135, 250, 125, 246, 242, 26, 67, 40, 71, 23, 206, 192, 101, 86, 155, 59, 121, 96, 14, 59, 50, 215, 212, 236, 210, 249, 79, 133, 198, 35, 7, 150, 118, 47, 206, 4, 220, 255, 79, 208, 248, 233, 179, 231, 209, 204, 139, 232, 20, 116, 66, 48, 2, 49])\n\n    bin_arrays = dlmm.get_bin_arrays()\n    assert type(bin_arrays) == list\n\n    fee_info = dlmm.get_fee_info()\n    assert isinstance(fee_info, FeeInfo)\n\n    dynamic_fee = dlmm.get_dynamic_fee()\n    assert type(dynamic_fee) == float\n\n    check_bin = bin_arrays[0].account.bins[0]\n\n    bin_id = dlmm.get_bin_id_from_price(float(check_bin.price), True)\n    assert isinstance(bin_id, int) or bin_id is None\n\n    bins_around_active = dlmm.get_bins_around_active_bin(0, 0)\n    assert isinstance(bins_around_active, GetBins)\n\n    bins_between_upper_lower = dlmm.get_bins_between_lower_and_upper_bound(0, 2)\n    assert isinstance(bins_between_upper_lower, GetBins)\n\n    bins_between_min_max = dlmm.get_bins_between_min_and_max_price(0.1, 50.0)\n    assert isinstance(bins_between_min_max, GetBins)\n\n    positions = dlmm.get_positions_by_user_and_lb_pair(user.pubkey())\n    user_positions = next(filter(lambda x: x.public_key == new_balance_position.pubkey() ,positions.user_positions), None)\n    if user_positions:\n        claim_lm = dlmm.claim_LM_reward(new_balance_position.pubkey(), user_positions)\n        assert isinstance(claim_lm, Transaction)\n\n        claim_swap_fee = dlmm.claim_swap_fee(new_balance_position.pubkey(), user_positions)\n        assert isinstance(claim_swap_fee, Transaction)\n\n    all_positions = DLMM_CLIENT.get_all_lb_pair_positions_by_user(user.pubkey(), RPC)\n\n    assert isinstance(all_positions, dict) and len(all_positions) > 0\n\n\n\n\n"
  },
  {
    "path": "rust-toolchain.toml",
    "content": "[toolchain]\nchannel = \"1.85.0\"\n"
  },
  {
    "path": "ts-client/README.md",
    "content": "# DLMM SDK\n\n<p align=\"center\">\n<img align=\"center\" src=\"https://app.meteora.ag/icons/logo.svg\" width=\"180\" height=\"180\" />\n</p>\n<br>\n\n## Getting started\n\nNPM: https://www.npmjs.com/package/@meteora-ag/dlmm\n\nSDK: https://github.com/MeteoraAg/dlmm-sdk\n\n<!-- Docs: https://docs.mercurial.finance/mercurial-dynamic-yield-infra/ -->\n\nDiscord: https://discord.com/channels/841152225564950528/864859354335412224\n\n## Install\n\n1. Install deps\n\n```\nnpm i @meteora-ag/dlmm @coral-xyz/anchor @solana/web3.js\n```\n\n2. Initialize DLMM instance\n\n```ts\nimport DLMM from '@meteora-ag/dlmm'\n\nconst USDC_USDT_POOL = new PublicKey('ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq') // You can get your desired pool address from the API https://dlmm-api.meteora.ag/pair/all\nconst dlmmPool = await DLMM.create(connection, USDC_USDT_POOL);\n\n// If you need to create multiple, can consider using `createMultiple`\nconst dlmmPool = await DLMM.createMultiple(connection, [USDC_USDT_POOL, ...]);\n\n```\n\n3. To interact with the AmmImpl\n\n- Get Active Bin\n\n```ts\nconst activeBin = await dlmmPool.getActiveBin();\nconst activeBinPriceLamport = activeBin.price;\nconst activeBinPricePerToken = dlmmPool.fromPricePerLamport(\n  Number(activeBin.price)\n);\n```\n\n- Create Balance Position\n\n```ts\nconst TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\nconst minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\nconst maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\nconst totalXAmount = new BN(100 * 10 ** baseMint.decimals);\nconst totalYAmount = autoFillYByStrategy(\n  activeBin.binId,\n  dlmmPool.lbPair.binStep,\n  totalXAmount,\n  activeBin.xAmount,\n  activeBin.yAmount,\n  minBinId,\n  maxBinId,\n  StrategyType.Spot // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n);\nconst newBalancePosition = new Keypair();\n\n// Create Position\nconst createPositionTx =\n  await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n    positionPubKey: newBalancePosition.publicKey,\n    user: user.publicKey,\n    totalXAmount,\n    totalYAmount,\n    strategy: {\n      maxBinId,\n      minBinId,\n      strategyType: StrategyType.Spot, // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n    },\n  });\n\ntry {\n  const createBalancePositionTxHash = await sendAndConfirmTransaction(\n    connection,\n    createPositionTx,\n    [user, newBalancePosition]\n  );\n} catch (error) {}\n```\n\n- Create Imbalance Position\n\n```ts\nconst TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\nconst minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\nconst maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\nconst totalXAmount = new BN(100 * 10 ** baseMint.decimals);\nconst totalYAmount = new BN(0.5 * 10 ** 9); // SOL\nconst newImbalancePosition = new Keypair();\n\n// Create Position\nconst createPositionTx =\n  await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n    positionPubKey: newImbalancePosition.publicKey,\n    user: user.publicKey,\n    totalXAmount,\n    totalYAmount,\n    strategy: {\n      maxBinId,\n      minBinId,\n      strategyType: StrategyType.Spot, // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n    },\n  });\n\ntry {\n  const createBalancePositionTxHash = await sendAndConfirmTransaction(\n    connection,\n    createPositionTx,\n    [user, newImbalancePosition]\n  );\n} catch (error) {}\n```\n\n- Create One Side Position\n\n```ts\nconst TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\nconst minBinId = activeBin.binId;\nconst maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL * 2;\n\nconst totalXAmount = new BN(100 * 10 ** baseMint.decimals);\nconst totalYAmount = new BN(0);\nconst newOneSidePosition = new Keypair();\n\n// Create Position\nconst createPositionTx =\n  await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n    positionPubKey: newOneSidePosition.publicKey,\n    user: user.publicKey,\n    totalXAmount,\n    totalYAmount,\n    strategy: {\n      maxBinId,\n      minBinId,\n      strategyType: StrategyType.Spot, // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n    },\n  });\n\ntry {\n  const createOneSidePositionTxHash = await sendAndConfirmTransaction(\n    connection,\n    createPositionTx,\n    [user, newOneSidePosition]\n  );\n} catch (error) {}\n```\n\n- Get list of positions\n\n```ts\nconst { userPositions } = await dlmmPool.getPositionsByUserAndLbPair(\n  user.publicKey\n);\nconst binData = userPositions[0].positionData.positionBinData;\n```\n\n- Add liquidity to existing position\n\n```ts\nconst TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\nconst minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\nconst maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\nconst totalXAmount = new BN(100 * 10 ** baseMint.decimals);\nconst totalYAmount = autoFillYByStrategy(\n  activeBin.binId,\n  dlmmPool.lbPair.binStep,\n  totalXAmount,\n  activeBin.xAmount,\n  activeBin.yAmount,\n  minBinId,\n  maxBinId,\n  StrategyType.Spot // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n);\n\n// Add Liquidity to existing position\nconst addLiquidityTx = await dlmmPool.addLiquidityByStrategy({\n  positionPubKey: newBalancePosition.publicKey,\n  user: user.publicKey,\n  totalXAmount,\n  totalYAmount,\n  strategy: {\n    maxBinId,\n    minBinId,\n    strategyType: StrategyType.Spot, // can be StrategyType.Spot, StrategyType.BidAsk, StrategyType.Curve\n  },\n});\n\ntry {\n  const addLiquidityTxHash = await sendAndConfirmTransaction(\n    connection,\n    addLiquidityTx,\n    [user]\n  );\n} catch (error) {}\n```\n\n- Remove Liquidity\n\n```ts\nconst userPosition = userPositions.find(({ publicKey }) =>\n  publicKey.equals(newBalancePosition.publicKey)\n);\n// Remove Liquidity\nconst binIdsToRemove = userPosition.positionData.positionBinData.map(\n  (bin) => bin.binId\n);\nconst removeLiquidityTx = await dlmmPool.removeLiquidity({\n  position: userPosition.publicKey,\n  user: user.publicKey,\n  fromBinId: binIdsToRemove[0],\n  toBinId: binIdsToRemove[binIdsToRemove.length - 1],\n  liquiditiesBpsToRemove: new Array(binIdsToRemove.length).fill(\n    new BN(100 * 100)\n  ), // 100% (range from 0 to 100)\n  shouldClaimAndClose: true, // should claim swap fee and close position together\n});\n\ntry {\n  for (let tx of Array.isArray(removeLiquidityTx)\n    ? removeLiquidityTx\n    : [removeLiquidityTx]) {\n    const removeBalanceLiquidityTxHash = await sendAndConfirmTransaction(\n      connection,\n      tx,\n      [user],\n      { skipPreflight: false, preflightCommitment: \"singleGossip\" }\n    );\n  }\n} catch (error) {}\n```\n\n- Claim Fee\n\n```ts\nasync function claimFee(dlmmPool: DLMM) {\n  const claimFeeTxs = await dlmmPool.claimAllSwapFee({\n    owner: user.publicKey,\n    positions: userPositions,\n  });\n\n  try {\n    for (const claimFeeTx of claimFeeTxs) {\n      const claimFeeTxHash = await sendAndConfirmTransaction(\n        connection,\n        claimFeeTx,\n        [user]\n      );\n    }\n  } catch (error) {}\n}\n```\n\n- Close Position\n\n```ts\nconst closePositionTx = await dlmmPool.closePosition({\n  owner: user.publicKey,\n  position: newBalancePosition.publicKey,\n});\n\ntry {\n  const closePositionTxHash = await sendAndConfirmTransaction(\n    connection,\n    closePositionTx,\n    [user],\n    { skipPreflight: false, preflightCommitment: \"singleGossip\" }\n  );\n} catch (error) {}\n```\n\n- Swap\n\n```ts\nconst swapAmount = new BN(0.1 * 10 ** 9);\n// Swap quote\nconst swapYtoX = true;\nconst binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX);\n\nconst swapQuote = await dlmmPool.swapQuote(\n  swapAmount,\n  swapYtoX,\n  new BN(1),\n  binArrays\n);\n\n// Swap\nconst swapTx = await dlmmPool.swap({\n  inToken: dlmmPool.tokenX.publicKey,\n  binArraysPubkey: swapQuote.binArraysPubkey,\n  inAmount: swapAmount,\n  lbPair: dlmmPool.pubkey,\n  user: user.publicKey,\n  minOutAmount: swapQuote.minOutAmount,\n  outToken: dlmmPool.tokenY.publicKey,\n});\n\ntry {\n  const swapTxHash = await sendAndConfirmTransaction(connection, swapTx, [\n    user,\n  ]);\n} catch (error) {}\n```\n\n## Static functions\n\n| Function                      | Description                                                                        | Return                               |\n| ----------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------ |\n| `create`                      | Given the DLMM address, create an instance to access the state and functions       | `Promise<DLMM>`                      |\n| `createMultiple`              | Given a list of DLMM addresses, create instances to access the state and functions | `Promise<Array<DLMM>>`               |\n| `getAllPresetParameters`      | Get all the preset params (use to create DLMM pool)                                | `Promise<PresetParams>`              |\n| `createPermissionLbPair`      | Create DLMM Pool                                                                   | `Promise<Transcation>`               |\n| `getClaimableLMReward`        | Get Claimable LM reward for a position                                             | `Promise<LMRewards>`                 |\n| `getClaimableSwapFee`         | Get Claimable Swap Fee for a position                                              | `Promise<SwapFee>`                   |\n| `getAllLbPairPositionsByUser` | Get user's all positions for all DLMM pools                                        | `Promise<Map<string, PositionInfo>>` |\n\n## DLMM instance functions\n\n| Function                                      | Description                                                                                                                   | Return                                                                                             |\n| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| `refetchStates`                               | Update onchain state of DLMM instance. It's recommend to call this before interact with the program (Deposit/ Withdraw/ Swap) | `Promise<void>`                                                                                    |\n| `getBinArrays`                                | Retrieves List of Bin Arrays                                                                                                  | `Promise<BinArrayAccount[]>`                                                                       |\n| `getBinArrayForSwap`                          | Retrieves List of Bin Arrays for swap purpose                                                                                 | `Promise<BinArrayAccount[]>`                                                                       |\n| `getFeeInfo`                                  | Retrieves LbPair's fee info including `base fee`, `protocol fee` & `max fee`                                                  | `FeeInfo`                                                                                          |\n| `getDynamicFee`                               | Retrieves LbPair's dynamic fee                                                                                                | `Decimal`                                                                                          |\n| `getBinsAroundActiveBin`                      | retrieves a specified number of bins to the left and right of the active bin and returns them along with the active bin ID.   | `Promise<{ activeBin: number; bins: BinLiquidity[] }>`                                             |\n| `getBinsBetweenMinAndMaxPrice`                | Retrieves a list of bins within a specified price                                                                             | `Promise<{ activeBin: number; bins: BinLiquidity[] }>`                                             |\n| `getBinsBetweenLowerAndUpperBound`            | retrieves a list of bins between a lower and upper bin ID and returns the active bin ID and the list of bins.                 | `Promise<{ activeBin: number; bins: BinLiquidity[] }>`                                             |\n| `toPricePerLamport`                           | Converts a real price of bin to lamport price                                                                                 | `string`                                                                                           |\n| `fromPricePerLamport`                         | converts a price per lamport value to a real price of bin                                                                     | `string`                                                                                           |\n| `getActiveBin`                                | Retrieves the active bin ID and its corresponding price                                                                       | `Promise<{ binId: number; price: string }>`                                                        |\n| `getPriceOfBinByBinId`                        | Get the price of a bin based on its bin ID                                                                                    | `string`                                                                                           |\n| `getBinIdFromPrice`                           | get bin ID based on a given price and a boolean flag indicating whether to round down or up.                                  | `number`                                                                                           |\n| `getPositionsByUserAndLbPair`                 | Retrieves positions by user and LB pair, including active bin and user positions.                                             | `Promise<{ activeBin: { binId: any; price: string; }; userPositions: Array<Position>;}>`           |\n| `initializePositionAndAddLiquidityByStrategy` | Initializes a position and adds liquidity                                                                                     | `Promise<Transaction\\|Transaction[]>`                                                              |\n| `addLiquidityByStrategy`                      | Add liquidity to existing position                                                                                            | `Promise<Transaction\\|Transaction[]>`                                                              |\n| `removeLiquidity`                             | function is used to remove liquidity from a position, with the option to claim rewards and close the position.                | `Promise<Transaction\\|Transaction[]>`                                                              |\n| `closePosition`                               | Closes a position                                                                                                             | `Promise<Transaction\\|Transaction[]>`                                                              |\n| `swapQuote`                                   | Quote for a swap                                                                                                              | `SwapQuote`                                                                                        |\n| `swap`                                        | Swap token within the LbPair                                                                                                  | `Promise<Transaction>`                                                                             |\n| `claimLMReward`                               | Claim rewards for a specific position owned by a specific owner                                                               | `Promise<Transaction>`                                                                             |\n| `claimAllLMRewards`                           | Claim all liquidity mining rewards for a given owner and their positions.                                                     | `Promise<Transaction[]>`                                                                           |\n| `claimSwapFee`                                | Claim swap fees for a specific position owned by a specific owner                                                             | `Promise<Transaction>`                                                                             |\n| `claimAllSwapFee`                             | Claim swap fees for multiple positions owned by a specific owner                                                              | `Promise<Transaction>`                                                                             |\n| `claimAllRewards`                             | Claim swap fees and LM rewards for multiple positions owned by a specific owner                                               | `Promise<Transaction[]>`                                                                           |\n| `syncWithMarketPrice`                         | Sync the pool current active bin to match nearest market price bin                                                            | `Promise<Transaction>`                                                                             |\n| `getPairPubkeyIfExists`                       | Get existing pool address given parameter, if not return null                                                                 | `Promise<PublicKey                                                                       \\| null>` |\n| `getMaxPriceInBinArrays`                      | Get max price of the last bin that has liquidity given bin arrays                                                             | `Promise<string                                                                       \\| null>`    |\n"
  },
  {
    "path": "ts-client/jest.config.js",
    "content": "const TIMEOUT_SEC = 1000;\n\nmodule.exports = {\n  preset: \"ts-jest\",\n  testEnvironment: \"node\",\n  transform: {\n    \"^.+\\\\.ts?$\": \"ts-jest\",\n  },\n  transformIgnorePatterns: [\"<rootDir>/node_modules/\"],\n  testTimeout: TIMEOUT_SEC * 60 * 5,\n};\n"
  },
  {
    "path": "ts-client/package.json",
    "content": "{\n  \"name\": \"@meteora-ag/dlmm\",\n  \"version\": \"1.9.7\",\n  \"description\": \"\",\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.mjs\",\n  \"source\": \"./src/index.ts\",\n  \"types\": \"./dist/index.d.ts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/MeteoraAg/dlmm-sdk.git\",\n    \"directory\": \"ts-client\"\n  },\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.js\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"files\": [\n    \"dist/**\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsup\",\n    \"start\": \"npm run build -- --watch\",\n    \"test\": \"jest 'src/test/sdk_token2022.test.ts'\",\n    \"unit-test\": \"jest src/test/calculate_distribution.test.ts\",\n    \"example\": \"dotenv -e .env npx ts-node src/examples/example.ts\",\n    \"start-server\": \"npx tsc && node dist/src/server/index.js\"\n  },\n  \"devDependencies\": {\n    \"@babel/preset-env\": \"^7.22.5\",\n    \"@types/babar\": \"^0.2.1\",\n    \"@types/bn.js\": \"^5.1.5\",\n    \"@types/express\": \"^4.17.21\",\n    \"@types/gaussian\": \"^1.2.0\",\n    \"@types/jest\": \"^29.5.2\",\n    \"babar\": \"^0.2.3\",\n    \"babel-jest\": \"^29.5.0\",\n    \"dotenv-cli\": \"^7.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"ts-jest\": \"^29.1.1\",\n    \"tsup\": \"^6.7.0\",\n    \"typescript\": \"^5.0.4\"\n  },\n  \"dependencies\": {\n    \"@coral-xyz/anchor\": \"0.31.0\",\n    \"@coral-xyz/borsh\": \"0.31.0\",\n    \"@solana/buffer-layout\": \"^4.0.1\",\n    \"@solana/spl-token\": \"^0.4.6\",\n    \"@solana/web3.js\": \"^1.91.6\",\n    \"bn.js\": \"^5.2.1\",\n    \"decimal.js\": \"^10.4.2\",\n    \"express\": \"^4.19.2\",\n    \"gaussian\": \"^1.3.0\"\n  },\n  \"keywords\": [],\n  \"author\": \"McSam\",\n  \"license\": \"ISC\"\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/constants/index.ts",
    "content": "import { LAMPORTS_PER_SOL, PublicKey } from \"@solana/web3.js\";\nimport { BN } from \"@coral-xyz/anchor\";\nimport IDL from \"../idl/idl.json\";\nimport Decimal from \"decimal.js\";\n\nexport const LBCLMM_PROGRAM_IDS = {\n  devnet: \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\n  localhost: \"LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ\",\n  \"mainnet-beta\": \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\n};\n\nexport const ALT_ADDRESS = {\n  \"mainnet-beta\": \"JA5F83HUK9L78Y12TRLCsJZbu3Tv8pCK1GfK8mVNp1sz\",\n  devnet: \"BD6E8oYV52P829MxDq3sEtqWKJrHh9pDSUHeaWR1jRBs\",\n};\n\nexport const ADMIN = {\n  devnet: \"6WaLrrRfReGKBYUSkmx2K6AuT21ida4j8at2SUiZdXu8\",\n  localhost: \"bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1\",\n};\n\nexport enum Network {\n  MAINNET = \"mainnet-beta\",\n  TESTNET = \"testnet\",\n  DEVNET = \"devnet\",\n  LOCAL = \"localhost\",\n}\n\nexport const BASIS_POINT_MAX = 10000;\nexport const SCALE_OFFSET = 64;\nexport const SCALE = new BN(1).shln(SCALE_OFFSET);\n\nexport const FEE_PRECISION = new BN(1_000_000_000);\nexport const MAX_FEE_RATE = new BN(100_000_000);\n\n// https://solscan.io/tx/5JgHgEiVoqV61p3SASYzP4gnedvYFLhewPchBdFgPQZjHEiitjZCqs8u4rXyDYnGJ9zqAscknv9NoBiodsfDE1qR\nexport const BIN_ARRAY_FEE = 0.07143744;\n// https://solscan.io/tx/37yEmHsTU6tKjUc6iGG8GPiEuPHxiyBezwexsnnsqXQQKuDgwsNciEzkQZFWJShcdLpfug5xqNBPJkzit7eWvkDD\nexport const POSITION_FEE = 0.05740608;\nexport const TOKEN_ACCOUNT_FEE = 0.00203928;\n// https://solscan.io/tx/4QkTyVZbZgS3Go7ksEWzmHef7SBVgoJ8Fjjxk3eL9LZBBmrXHJarVM4TPy5Nq3XcjwdhWALeCCbL7xonExBGpNry\nexport const POOL_FEE = 0.00718272;\nexport const BIN_ARRAY_BITMAP_FEE = 0.01180416;\n\nexport const BIN_ARRAY_FEE_BN = new BN(\n  new Decimal(BIN_ARRAY_FEE).mul(LAMPORTS_PER_SOL).toString()\n);\nexport const POSITION_FEE_BN = new BN(\n  new Decimal(POSITION_FEE).mul(LAMPORTS_PER_SOL).toString()\n);\nexport const TOKEN_ACCOUNT_FEE_BN = new BN(\n  new Decimal(TOKEN_ACCOUNT_FEE).mul(LAMPORTS_PER_SOL).toString()\n);\nexport const POOL_FEE_BN = new BN(\n  new Decimal(POOL_FEE).mul(LAMPORTS_PER_SOL).toString()\n);\nexport const BIN_ARRAY_BITMAP_FEE_BN = new BN(\n  new Decimal(BIN_ARRAY_BITMAP_FEE).mul(LAMPORTS_PER_SOL).toString()\n);\n\nconst CONSTANTS = Object.entries(IDL.constants);\n\nexport const MAX_BIN_ARRAY_SIZE = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"MAX_BIN_PER_ARRAY\")?.[1].value ?? 0\n);\nexport const DEFAULT_BIN_PER_POSITION = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"DEFAULT_BIN_PER_POSITION\")?.[1].value ??\n    0\n);\nexport const BIN_ARRAY_BITMAP_SIZE = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"BIN_ARRAY_BITMAP_SIZE\")?.[1].value ?? 0\n);\nexport const EXTENSION_BINARRAY_BITMAP_SIZE = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"EXTENSION_BINARRAY_BITMAP_SIZE\")?.[1]\n    .value ?? 0\n);\n\nexport const POSITION_MAX_LENGTH = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"POSITION_MAX_LENGTH\")?.[1].value ?? 0\n);\n\nexport const MAX_RESIZE_LENGTH = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"MAX_RESIZE_LENGTH\")?.[1].value ?? 0\n);\n\nexport const SIMULATION_USER = new PublicKey(\n  \"HrY9qR5TiB2xPzzvbBu5KrBorMfYGQXh9osXydz4jy9s\"\n);\n\nexport const PRECISION = 18446744073709551616;\n\nexport const MAX_CLAIM_ALL_ALLOWED = 2;\n\nexport const MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX = 26;\n\nexport const MAX_ACTIVE_BIN_SLIPPAGE = 3;\n\nexport const ILM_BASE = new PublicKey(\n  \"MFGQxwAmB91SwuYX36okv2Qmdc9aMuHTwWGUrp4AtB1\"\n);\n\nexport const MAX_EXTRA_BIN_ARRAYS = 3;\nexport const U64_MAX = new BN(\"18446744073709551615\");\n\nexport const MAX_BINS_PER_POSITION = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"POSITION_MAX_LENGTH\")?.[1].value ?? 0\n);\n\nexport enum FunctionType {\n  LiquidityMining = 0,\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/error.ts",
    "content": "import IDL from \"./idl/idl.json\";\nimport { AnchorError } from \"@coral-xyz/anchor\";\nimport { LBCLMM_PROGRAM_IDS } from \"./constants\";\n\ntype Codes = (typeof IDL.errors)[number][\"code\"];\n\n// ProgramError error parser\nexport class DLMMError extends Error {\n  public errorCode: number;\n  public errorName: string;\n  public errorMessage: string;\n\n  constructor(error: object | Codes) {\n    let _errorCode = 0;\n    let _errorName = \"Something went wrong\";\n    let _errorMessage = \"Something went wrong\";\n\n    if (error instanceof Error) {\n      const anchorError = AnchorError.parse(\n        JSON.parse(JSON.stringify(error)).logs as string[]\n      );\n\n      if (\n        anchorError?.program.toBase58() === LBCLMM_PROGRAM_IDS[\"mainnet-beta\"]\n      ) {\n        _errorCode = anchorError.error.errorCode.number;\n        _errorName = anchorError.error.errorCode.code;\n        _errorMessage = anchorError.error.errorMessage;\n      }\n    } else {\n      const idlError = IDL.errors.find((err) => err.code === error);\n\n      if (idlError) {\n        _errorCode = idlError.code;\n        _errorName = idlError.name;\n        _errorMessage = idlError.msg;\n      }\n    }\n\n    super(_errorMessage);\n\n    this.errorCode = _errorCode;\n    this.errorName = _errorName;\n    this.errorMessage = _errorMessage;\n  }\n}\n\n// SDK error\ntype ErrorName =\n  | \"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY\"\n  | \"INVALID_MAX_EXTRA_BIN_ARRAYS\";\n\nexport class DlmmSdkError extends Error {\n  name: ErrorName;\n  message: string;\n\n  constructor(name: ErrorName, message: string) {\n    super();\n    this.name = name;\n    this.message = message;\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/accountFilters.ts",
    "content": "import { GetProgramAccountsFilter, PublicKey } from \"@solana/web3.js\";\nimport { bs58 } from \"@coral-xyz/anchor/dist/cjs/utils/bytes\";\nimport BN from \"bn.js\";\nimport { getAccountDiscriminator } from \".\";\n\nexport const presetParameter2BinStepFilter = (\n  binStep: BN\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: bs58.encode(binStep.toArrayLike(Buffer, \"le\", 2)),\n      offset: 8,\n    },\n  };\n};\n\nexport const presetParameter2BaseFactorFilter = (\n  baseFactor: BN\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: bs58.encode(baseFactor.toArrayLike(Buffer, \"le\", 2)),\n      offset: 8 + 2,\n    },\n  };\n};\n\nexport const presetParameter2BaseFeePowerFactor = (\n  baseFeePowerFactor: BN\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: bs58.encode(baseFeePowerFactor.toArrayLike(Buffer, \"le\", 1)),\n      offset: 8 + 22,\n    },\n  };\n};\n\nexport const binArrayLbPairFilter = (\n  lbPair: PublicKey\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: lbPair.toBase58(),\n      offset: 8 + 16,\n    },\n  };\n};\n\nexport const positionOwnerFilter = (\n  owner: PublicKey\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: owner.toBase58(),\n      offset: 8 + 32,\n    },\n  };\n};\n\nexport const positionLbPairFilter = (\n  lbPair: PublicKey\n): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: bs58.encode(lbPair.toBuffer()),\n      offset: 8,\n    },\n  };\n};\n\nexport const positionV2Filter = (): GetProgramAccountsFilter => {\n  return {\n    memcmp: {\n      bytes: bs58.encode(Buffer.from(getAccountDiscriminator(\"positionV2\"))),\n      offset: 0,\n    },\n  };\n};\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/binArray.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport {\n  MAX_BIN_ARRAY_SIZE,\n  DEFAULT_BIN_PER_POSITION,\n  SCALE_OFFSET,\n} from \"../constants\";\nimport {\n  Bin,\n  BinArray,\n  BinArrayAccount,\n  BinArrayBitmapExtension,\n  BinLiquidity,\n  BitmapType,\n  Clock,\n  LbPair,\n  RewardInfo,\n  RewardInfos,\n} from \"../types\";\nimport {\n  EXTENSION_BINARRAY_BITMAP_SIZE,\n  BIN_ARRAY_BITMAP_SIZE,\n} from \"../constants\";\nimport { getPositionCount } from \"./math\";\nimport { deriveBinArray } from \"./derive\";\n\n/** private */\nfunction internalBitmapRange() {\n  const lowerBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();\n  const upperBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN(1));\n  return [lowerBinArrayIndex, upperBinArrayIndex];\n}\n\nfunction buildBitmapFromU64Arrays(u64Arrays: BN[], type: BitmapType) {\n  const buffer = Buffer.concat(\n    u64Arrays.map((b) => {\n      return b.toArrayLike(Buffer, \"le\", 8);\n    })\n  );\n\n  return new BN(buffer, \"le\");\n}\n\nfunction bitmapTypeDetail(type: BitmapType) {\n  if (type == BitmapType.U1024) {\n    return {\n      bits: 1024,\n      bytes: 1024 / 8,\n    };\n  } else {\n    return {\n      bits: 512,\n      bytes: 512 / 8,\n    };\n  }\n}\n\nfunction mostSignificantBit(number: BN, bitLength: number) {\n  const highestIndex = bitLength - 1;\n  if (number.isZero()) {\n    return null;\n  }\n\n  for (let i = highestIndex; i >= 0; i--) {\n    if (number.testn(i)) {\n      return highestIndex - i;\n    }\n  }\n  return null;\n}\n\nfunction leastSignificantBit(number: BN, bitLength: number) {\n  if (number.isZero()) {\n    return null;\n  }\n  for (let i = 0; i < bitLength; i++) {\n    if (number.testn(i)) {\n      return i;\n    }\n  }\n  return null;\n}\n\nfunction extensionBitmapRange() {\n  return [\n    BIN_ARRAY_BITMAP_SIZE.neg().mul(\n      EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN(1))\n    ),\n    BIN_ARRAY_BITMAP_SIZE.mul(\n      EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN(1))\n    ).sub(new BN(1)),\n  ];\n}\n\nfunction findSetBit(\n  startIndex: number,\n  endIndex: number,\n  binArrayBitmapExtension: BinArrayBitmapExtension\n): number | null {\n  const getBinArrayOffset = (binArrayIndex: BN) => {\n    return binArrayIndex.gt(new BN(0))\n      ? binArrayIndex.mod(BIN_ARRAY_BITMAP_SIZE)\n      : binArrayIndex.add(new BN(1)).neg().mod(BIN_ARRAY_BITMAP_SIZE);\n  };\n\n  const getBitmapOffset = (binArrayIndex: BN) => {\n    return binArrayIndex.gt(new BN(0))\n      ? binArrayIndex.div(BIN_ARRAY_BITMAP_SIZE).sub(new BN(1))\n      : binArrayIndex\n          .add(new BN(1))\n          .neg()\n          .div(BIN_ARRAY_BITMAP_SIZE)\n          .sub(new BN(1));\n  };\n\n  if (startIndex <= endIndex) {\n    for (let i = startIndex; i <= endIndex; i++) {\n      const binArrayOffset = getBinArrayOffset(new BN(i)).toNumber();\n      const bitmapOffset = getBitmapOffset(new BN(i)).toNumber();\n      const bitmapChunks =\n        i > 0\n          ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset]\n          : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];\n      const bitmap = buildBitmapFromU64Arrays(bitmapChunks, BitmapType.U512);\n      if (bitmap.testn(binArrayOffset)) {\n        return i;\n      }\n    }\n  } else {\n    for (let i = startIndex; i >= endIndex; i--) {\n      const binArrayOffset = getBinArrayOffset(new BN(i)).toNumber();\n      const bitmapOffset = getBitmapOffset(new BN(i)).toNumber();\n      const bitmapChunks =\n        i > 0\n          ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset]\n          : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];\n      const bitmap = buildBitmapFromU64Arrays(bitmapChunks, BitmapType.U512);\n      if (bitmap.testn(binArrayOffset)) {\n        return i;\n      }\n    }\n  }\n\n  return null;\n}\n/** private */\n\nexport function isOverflowDefaultBinArrayBitmap(binArrayIndex: BN) {\n  const [minBinArrayIndex, maxBinArrayIndex] = internalBitmapRange();\n  return (\n    binArrayIndex.gt(maxBinArrayIndex) || binArrayIndex.lt(minBinArrayIndex)\n  );\n}\n\nexport function deriveBinArrayBitmapExtension(\n  lbPair: PublicKey,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"bitmap\"), lbPair.toBytes()],\n    programId\n  );\n}\n\nexport function binIdToBinArrayIndex(binId: BN): BN {\n  const { div: idx, mod } = binId.divmod(MAX_BIN_ARRAY_SIZE);\n  return binId.isNeg() && !mod.isZero() ? idx.sub(new BN(1)) : idx;\n}\n\nexport function getBinArrayLowerUpperBinId(binArrayIndex: BN) {\n  const lowerBinId = binArrayIndex.mul(MAX_BIN_ARRAY_SIZE);\n  const upperBinId = lowerBinId.add(MAX_BIN_ARRAY_SIZE).sub(new BN(1));\n\n  return [lowerBinId, upperBinId];\n}\n\nexport function isBinIdWithinBinArray(activeId: BN, binArrayIndex: BN) {\n  const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);\n  return activeId.gte(lowerBinId) && activeId.lte(upperBinId);\n}\n\nexport function getBinFromBinArray(binId: number, binArray: BinArray): Bin {\n  const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArray.index);\n\n  let index = 0;\n  if (binId > 0) {\n    index = binId - lowerBinId.toNumber();\n  } else {\n    const delta = upperBinId.toNumber() - binId;\n    index = MAX_BIN_ARRAY_SIZE.toNumber() - delta - 1;\n  }\n\n  return binArray.bins[index];\n}\n\nexport function findNextBinArrayIndexWithLiquidity(\n  swapForY: boolean,\n  activeId: BN,\n  lbPairState: LbPair,\n  binArrayBitmapExtension: BinArrayBitmapExtension | null\n): BN | null {\n  const [lowerBinArrayIndex, upperBinArrayIndex] = internalBitmapRange();\n  let startBinArrayIndex = binIdToBinArrayIndex(activeId);\n\n  while (true) {\n    if (isOverflowDefaultBinArrayBitmap(startBinArrayIndex)) {\n      if (binArrayBitmapExtension === null) {\n        return null;\n      }\n      // When bin array index is negative, the MSB is smallest bin array index.\n\n      const [minBinArrayIndex, maxBinArrayIndex] = extensionBitmapRange();\n\n      if (startBinArrayIndex.isNeg()) {\n        if (swapForY) {\n          const binArrayIndex = findSetBit(\n            startBinArrayIndex.toNumber(),\n            minBinArrayIndex.toNumber(),\n            binArrayBitmapExtension\n          );\n\n          if (binArrayIndex !== null) {\n            return new BN(binArrayIndex);\n          } else {\n            return null;\n          }\n        } else {\n          const binArrayIndex = findSetBit(\n            startBinArrayIndex.toNumber(),\n            BIN_ARRAY_BITMAP_SIZE.neg().sub(new BN(1)).toNumber(),\n            binArrayBitmapExtension\n          );\n\n          if (binArrayIndex !== null) {\n            return new BN(binArrayIndex);\n          } else {\n            // Move to internal bitmap\n            startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();\n          }\n        }\n      } else {\n        if (swapForY) {\n          const binArrayIndex = findSetBit(\n            startBinArrayIndex.toNumber(),\n            BIN_ARRAY_BITMAP_SIZE.toNumber(),\n            binArrayBitmapExtension\n          );\n\n          if (binArrayIndex !== null) {\n            return new BN(binArrayIndex);\n          } else {\n            // Move to internal bitmap\n            startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN(1));\n          }\n        } else {\n          const binArrayIndex = findSetBit(\n            startBinArrayIndex.toNumber(),\n            maxBinArrayIndex.toNumber(),\n            binArrayBitmapExtension\n          );\n\n          if (binArrayIndex !== null) {\n            return new BN(binArrayIndex);\n          } else {\n            return null;\n          }\n        }\n      }\n    } else {\n      // Internal bitmap\n      const bitmapType = BitmapType.U1024;\n      const bitmapDetail = bitmapTypeDetail(bitmapType);\n      const offset = startBinArrayIndex.add(BIN_ARRAY_BITMAP_SIZE);\n\n      const bitmap = buildBitmapFromU64Arrays(\n        lbPairState.binArrayBitmap,\n        bitmapType\n      );\n\n      if (swapForY) {\n        const upperBitRange = new BN(bitmapDetail.bits - 1).sub(offset);\n        const croppedBitmap = bitmap.shln(upperBitRange.toNumber());\n\n        const msb = mostSignificantBit(croppedBitmap, bitmapDetail.bits);\n\n        if (msb !== null) {\n          return startBinArrayIndex.sub(new BN(msb));\n        } else {\n          // Move to extension\n          startBinArrayIndex = lowerBinArrayIndex.sub(new BN(1));\n        }\n      } else {\n        const lowerBitRange = offset;\n        const croppedBitmap = bitmap.shrn(lowerBitRange.toNumber());\n        const lsb = leastSignificantBit(croppedBitmap, bitmapDetail.bits);\n        if (lsb !== null) {\n          return startBinArrayIndex.add(new BN(lsb));\n        } else {\n          // Move to extension\n          startBinArrayIndex = upperBinArrayIndex.add(new BN(1));\n        }\n      }\n    }\n  }\n}\n\nexport function findNextBinArrayWithLiquidity(\n  swapForY: boolean,\n  activeBinId: BN,\n  lbPairState: LbPair,\n  binArrayBitmapExtension: BinArrayBitmapExtension | null,\n  binArrays: BinArrayAccount[]\n): BinArrayAccount | null {\n  const nearestBinArrayIndexWithLiquidity = findNextBinArrayIndexWithLiquidity(\n    swapForY,\n    activeBinId,\n    lbPairState,\n    binArrayBitmapExtension\n  );\n\n  if (nearestBinArrayIndexWithLiquidity == null) {\n    return null;\n  }\n\n  const binArrayAccount = binArrays.find((ba) =>\n    ba.account.index.eq(nearestBinArrayIndexWithLiquidity)\n  );\n  if (!binArrayAccount) {\n    // Cached bin array couldn't cover more bins, partial quoted.\n    return null;\n  }\n\n  return binArrayAccount;\n}\n\n/**\n * Retrieves the bin arrays required to initialize multiple positions in continuous range.\n *\n * @param {PublicKey} pair - The public key of the pair.\n * @param {BN} fromBinId - The starting bin ID.\n * @param {BN} toBinId - The ending bin ID.\n * @return {[{key: PublicKey, index: BN }]} An array of bin arrays required for the given position range.\n */\nexport function getBinArraysRequiredByPositionRange(\n  pair: PublicKey,\n  fromBinId: BN,\n  toBinId: BN,\n  programId: PublicKey\n): { key: PublicKey; index: BN }[] {\n  const [minBinId, maxBinId] = fromBinId.lt(toBinId)\n    ? [fromBinId, toBinId]\n    : [toBinId, fromBinId];\n\n  const positionCount = getPositionCount(minBinId, maxBinId);\n  const binArrays = new Map<String, BN>();\n\n  for (let i = 0; i < positionCount.toNumber(); i++) {\n    const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new BN(i)));\n\n    const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);\n    const upperBinArrayIndex = lowerBinArrayIndex.add(new BN(1));\n\n    const [lowerBinArray] = deriveBinArray(pair, lowerBinArrayIndex, programId);\n    const [upperBinArray] = deriveBinArray(pair, upperBinArrayIndex, programId);\n\n    binArrays.set(lowerBinArray.toBase58(), lowerBinArrayIndex);\n    binArrays.set(upperBinArray.toBase58(), upperBinArrayIndex);\n  }\n\n  return Array.from(binArrays, ([key, index]) => ({\n    key: new PublicKey(key),\n    index,\n  }));\n}\n\nexport function* enumerateBins(\n  binsById: Map<number, Bin>,\n  lowerBinId: number,\n  upperBinId: number,\n  binStep: number,\n  baseTokenDecimal: number,\n  quoteTokenDecimal: number,\n  version: number\n) {\n  for (\n    let currentBinId = lowerBinId;\n    currentBinId <= upperBinId;\n    currentBinId++\n  ) {\n    const bin = binsById.get(currentBinId);\n    if (bin != null) {\n      yield BinLiquidity.fromBin(\n        bin,\n        currentBinId,\n        binStep,\n        baseTokenDecimal,\n        quoteTokenDecimal,\n        version\n      );\n    } else {\n      yield BinLiquidity.empty(\n        currentBinId,\n        binStep,\n        baseTokenDecimal,\n        quoteTokenDecimal,\n        version\n      );\n    }\n  }\n}\n\nfunction isRewardInitialized(reward: RewardInfo) {\n  return !reward.mint.equals(PublicKey.default);\n}\n\nexport function getBinIdIndexInBinArray(\n  binId: BN,\n  lowerBinId: BN,\n  upperBinId: BN\n) {\n  if (binId.lt(lowerBinId) || binId.gt(upperBinId)) {\n    return null;\n  }\n  return binId.sub(lowerBinId);\n}\n\n/// Update bin array LM rewards\nexport function updateBinArray(\n  activeId: BN,\n  clock: Clock,\n  allRewardInfos: RewardInfos,\n  binArray: BinArray\n) {\n  const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArray.index);\n  const binIdx = getBinIdIndexInBinArray(activeId, lowerBinId, upperBinId);\n\n  if (binIdx == null) {\n    return binArray;\n  }\n\n  const binArrayClone = Object.assign({}, binArray);\n  const activeBin = binArrayClone.bins[binIdx.toNumber()];\n\n  if (activeBin.liquiditySupply.isZero()) {\n    return binArrayClone;\n  }\n\n  for (const [rewardIdx, reward] of allRewardInfos.entries()) {\n    if (!isRewardInitialized(reward)) {\n      continue;\n    }\n\n    const currentTime = new BN(\n      Math.min(\n        clock.unixTimestamp.toNumber(),\n        reward.rewardDurationEnd.toNumber()\n      )\n    );\n\n    const delta = currentTime.sub(reward.lastUpdateTime);\n    const liquiditySupply = activeBin.liquiditySupply.shrn(SCALE_OFFSET);\n\n    const rewardPerTokenStoredDelta = reward.rewardRate\n      .mul(delta)\n      .div(new BN(15))\n      .div(liquiditySupply);\n\n    activeBin.functionBytes[rewardIdx] = activeBin.functionBytes[rewardIdx].add(\n      rewardPerTokenStoredDelta\n    );\n  }\n\n  return binArrayClone;\n}\n\nexport function binDeltaToMinMaxBinId(binDelta: number, activeBinId: number) {\n  const minBinId = activeBinId - binDelta;\n  const maxBinId = minBinId + binDelta * 2;\n  return {\n    minBinId,\n    maxBinId,\n  };\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/computeUnit.ts",
    "content": "import {\n  AddressLookupTableAccount,\n  Commitment,\n  ComputeBudgetProgram,\n  Connection,\n  PublicKey,\n  TransactionInstruction,\n  TransactionMessage,\n  VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { ResizeSide } from \"../types\";\n\n// https://solscan.io/tx/4ryJKTB1vYmGU6YnUWwbLps18FaJjiTwgRozcgdP8RFcwp7zUZi85vgWE7rARNx2NvzDJiM9CUWArqzY7LHv38WL\nexport const DEFAULT_ADD_LIQUIDITY_CU = 1_000_000;\nexport const DEFAULT_EXTEND_POSITION_HIGH_CU = 1_000_000;\nexport const DEFAULT_EXTEND_POSITION_LOW_CU = 30_000;\nexport const DEFAULT_INIT_POSITION_CU = 30_000;\nexport const DEFAULT_INIT_BIN_ARRAY_CU = 350_000;\n\nexport const MIN_CU_BUFFER = 50_000;\nexport const MAX_CU_BUFFER = 200_000;\nexport const MAX_CU = 1_400_000;\n\n// CU estimate is difficult due to the CU estimated is based on current position state. We use hardcoded value ...\nexport const getDefaultExtendPositionCU = (side: ResizeSide) => {\n  switch (side) {\n    case ResizeSide.Lower:\n      return DEFAULT_EXTEND_POSITION_HIGH_CU;\n    case ResizeSide.Upper:\n      return DEFAULT_EXTEND_POSITION_LOW_CU;\n  }\n};\n\nexport const getSimulationComputeUnits = async (\n  connection: Connection,\n  instructions: Array<TransactionInstruction>,\n  payer: PublicKey,\n  lookupTables: Array<AddressLookupTableAccount> | [],\n  commitment: Commitment = \"confirmed\"\n): Promise<number | null> => {\n  const testInstructions = [\n    // Set an arbitrarily high number in simulation\n    // so we can be sure the transaction will succeed\n    // and get the real compute units used\n    ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),\n    ...instructions,\n  ];\n\n  const testTransaction = new VersionedTransaction(\n    new TransactionMessage({\n      instructions: testInstructions,\n      payerKey: payer,\n      // RecentBlockhash can by any public key during simulation\n      // since 'replaceRecentBlockhash' is set to 'true' below\n      recentBlockhash: PublicKey.default.toString(),\n    }).compileToV0Message(lookupTables)\n  );\n\n  const rpcResponse = await connection.simulateTransaction(testTransaction, {\n    replaceRecentBlockhash: true,\n    sigVerify: false,\n    commitment,\n  });\n\n  if (rpcResponse?.value?.err) {\n    const logs = rpcResponse.value.logs?.join(\"\\n  • \") || \"No logs available\";\n    throw new Error(\n      `Transaction simulation failed:\\n  •${logs}` +\n        JSON.stringify(rpcResponse?.value?.err)\n    );\n  }\n\n  return rpcResponse.value.unitsConsumed || null;\n};\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/derive.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport { AccountMeta, Connection, PublicKey } from \"@solana/web3.js\";\nimport { DLMM } from \"..\";\nimport { ILM_BASE } from \"../constants\";\n\n/** private */\nfunction sortTokenMints(tokenX: PublicKey, tokenY: PublicKey) {\n  const [minKey, maxKey] =\n    tokenX.toBuffer().compare(tokenY.toBuffer()) == 1\n      ? [tokenY, tokenX]\n      : [tokenX, tokenY];\n  return [minKey, maxKey];\n}\n/** private */\n\nexport function derivePresetParameterWithIndex(\n  index: BN,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [\n      Buffer.from(\"preset_parameter2\"),\n      new Uint8Array(index.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\nexport function deriveLbPairWithPresetParamWithIndexKey(\n  presetParameterKey: PublicKey,\n  tokenX: PublicKey,\n  tokenY: PublicKey,\n  programId: PublicKey\n) {\n  const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);\n  return PublicKey.findProgramAddressSync(\n    [presetParameterKey.toBuffer(), minKey.toBuffer(), maxKey.toBuffer()],\n    programId\n  );\n}\n\n/**\n *\n * @deprecated Use derivePresetParameter2\n */\nexport function derivePresetParameter(binStep: BN, programId: PublicKey) {\n  return PublicKey.findProgramAddressSync(\n    [\n      Buffer.from(\"preset_parameter\"),\n      new Uint8Array(binStep.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\nexport function derivePresetParameter2(\n  binStep: BN,\n  baseFactor: BN,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [\n      Buffer.from(\"preset_parameter\"),\n      new Uint8Array(binStep.toArrayLike(Buffer, \"le\", 2)),\n      new Uint8Array(baseFactor.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\nexport function deriveLbPair2(\n  tokenX: PublicKey,\n  tokenY: PublicKey,\n  binStep: BN,\n  baseFactor: BN,\n  programId: PublicKey\n) {\n  const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);\n  return PublicKey.findProgramAddressSync(\n    [\n      minKey.toBuffer(),\n      maxKey.toBuffer(),\n      new Uint8Array(binStep.toArrayLike(Buffer, \"le\", 2)),\n      new Uint8Array(baseFactor.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\n/**\n *\n * @deprecated Use deriveLbPair2\n */\n\nexport function deriveLbPair(\n  tokenX: PublicKey,\n  tokenY: PublicKey,\n  binStep: BN,\n  programId: PublicKey\n) {\n  const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);\n  return PublicKey.findProgramAddressSync(\n    [\n      minKey.toBuffer(),\n      maxKey.toBuffer(),\n      new Uint8Array(binStep.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\nexport function deriveCustomizablePermissionlessLbPair(\n  tokenX: PublicKey,\n  tokenY: PublicKey,\n  programId: PublicKey\n) {\n  const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);\n  return PublicKey.findProgramAddressSync(\n    [ILM_BASE.toBuffer(), minKey.toBuffer(), maxKey.toBuffer()],\n    programId\n  );\n}\n\nexport function derivePermissionLbPair(\n  baseKey: PublicKey,\n  tokenX: PublicKey,\n  tokenY: PublicKey,\n  binStep: BN,\n  programId: PublicKey\n) {\n  const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);\n  return PublicKey.findProgramAddressSync(\n    [\n      baseKey.toBuffer(),\n      minKey.toBuffer(),\n      maxKey.toBuffer(),\n      new Uint8Array(binStep.toArrayLike(Buffer, \"le\", 2)),\n    ],\n    programId\n  );\n}\n\nexport function deriveOracle(lbPair: PublicKey, programId: PublicKey) {\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"oracle\"), lbPair.toBytes()],\n    programId\n  );\n}\n\nexport function derivePosition(\n  lbPair: PublicKey,\n  base: PublicKey,\n  lowerBinId: BN,\n  width: BN,\n  programId: PublicKey\n) {\n  let lowerBinIdBytes: Uint8Array;\n  if (lowerBinId.isNeg()) {\n    lowerBinIdBytes = new Uint8Array(\n      lowerBinId.toTwos(32).toArrayLike(Buffer, \"le\", 4)\n    );\n  } else {\n    lowerBinIdBytes = new Uint8Array(lowerBinId.toArrayLike(Buffer, \"le\", 4));\n  }\n  return PublicKey.findProgramAddressSync(\n    [\n      Buffer.from(\"position\"),\n      lbPair.toBuffer(),\n      base.toBuffer(),\n      lowerBinIdBytes,\n      new Uint8Array(width.toArrayLike(Buffer, \"le\", 4)),\n    ],\n    programId\n  );\n}\n\nexport function deriveBinArray(\n  lbPair: PublicKey,\n  index: BN,\n  programId: PublicKey\n) {\n  let binArrayBytes: Uint8Array;\n  if (index.isNeg()) {\n    binArrayBytes = new Uint8Array(\n      index.toTwos(64).toArrayLike(Buffer, \"le\", 8)\n    );\n  } else {\n    binArrayBytes = new Uint8Array(index.toArrayLike(Buffer, \"le\", 8));\n  }\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"bin_array\"), lbPair.toBytes(), binArrayBytes],\n    programId\n  );\n}\n\nexport function deriveReserve(\n  token: PublicKey,\n  lbPair: PublicKey,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [lbPair.toBuffer(), token.toBuffer()],\n    programId\n  );\n}\n\nexport function deriveTokenBadge(mint: PublicKey, programId: PublicKey) {\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"token_badge\"), mint.toBuffer()],\n    programId\n  );\n}\n\nexport function deriveEventAuthority(programId: PublicKey) {\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"__event_authority\")],\n    programId\n  );\n}\n\nexport function deriveRewardVault(\n  lbPair: PublicKey,\n  rewardIndex: BN,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [lbPair.toBuffer(), rewardIndex.toArrayLike(Buffer, \"le\", 8)],\n    programId\n  );\n}\n\nexport function derivePlaceHolderAccountMeta(\n  programId: PublicKey\n): AccountMeta {\n  return {\n    pubkey: programId,\n    isWritable: false,\n    isSigner: false,\n  };\n}\n\nexport function deriveOperator(\n  whitelistedSigner: PublicKey,\n  programId: PublicKey\n) {\n  return PublicKey.findProgramAddressSync(\n    [Buffer.from(\"operator\"), whitelistedSigner.toBuffer()],\n    programId\n  )[0];\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/fee.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport {\n  BASIS_POINT_MAX,\n  FEE_PRECISION,\n  MAX_FEE_RATE,\n  SCALE_OFFSET,\n} from \"../constants\";\nimport { Bin, sParameters, vParameters } from \"../types\";\nimport { Rounding, mulShr, shlDiv } from \"./math\";\nimport { getOutAmount } from \".\";\n\nexport function getBaseFee(binStep: number, sParameter: sParameters) {\n  return new BN(sParameter.baseFactor)\n    .mul(new BN(binStep))\n    .mul(new BN(10))\n    .mul(new BN(10).pow(new BN(sParameter.baseFeePowerFactor)));\n}\n\nexport function getVariableFee(\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters\n) {\n  if (sParameter.variableFeeControl > 0) {\n    const square_vfa_bin = new BN(vParameter.volatilityAccumulator)\n      .mul(new BN(binStep))\n      .pow(new BN(2));\n    const v_fee = new BN(sParameter.variableFeeControl).mul(square_vfa_bin);\n\n    return v_fee.add(new BN(99_999_999_999)).div(new BN(100_000_000_000));\n  }\n  return new BN(0);\n}\n\nexport function getTotalFee(\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters\n) {\n  const totalFee = getBaseFee(binStep, sParameter).add(\n    getVariableFee(binStep, sParameter, vParameter)\n  );\n  return totalFee.gt(MAX_FEE_RATE) ? MAX_FEE_RATE : totalFee;\n}\n\nexport function computeFee(\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters,\n  inAmount: BN\n) {\n  const totalFee = getTotalFee(binStep, sParameter, vParameter);\n  const denominator = FEE_PRECISION.sub(totalFee);\n\n  return inAmount\n    .mul(totalFee)\n    .add(denominator)\n    .sub(new BN(1))\n    .div(denominator);\n}\n\nexport function computeFeeFromAmount(\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters,\n  inAmountWithFees: BN\n) {\n  const totalFee = getTotalFee(binStep, sParameter, vParameter);\n  return inAmountWithFees\n    .mul(totalFee)\n    .add(FEE_PRECISION.sub(new BN(1)))\n    .div(FEE_PRECISION);\n}\n\nexport function computeProtocolFee(feeAmount: BN, sParameter: sParameters) {\n  return feeAmount\n    .mul(new BN(sParameter.protocolShare))\n    .div(new BN(BASIS_POINT_MAX));\n}\n\nexport function swapExactOutQuoteAtBin(\n  bin: Bin,\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters,\n  outAmount: BN,\n  swapForY: boolean\n): {\n  amountIn: BN;\n  amountOut: BN;\n  fee: BN;\n  protocolFee: BN;\n} {\n  if (swapForY && bin.amountY.isZero()) {\n    return {\n      amountIn: new BN(0),\n      amountOut: new BN(0),\n      fee: new BN(0),\n      protocolFee: new BN(0),\n    };\n  }\n\n  if (!swapForY && bin.amountX.isZero()) {\n    return {\n      amountIn: new BN(0),\n      amountOut: new BN(0),\n      fee: new BN(0),\n      protocolFee: new BN(0),\n    };\n  }\n\n  let maxAmountOut: BN;\n  let maxAmountIn: BN;\n\n  if (swapForY) {\n    maxAmountOut = bin.amountY;\n    maxAmountIn = shlDiv(bin.amountY, bin.price, SCALE_OFFSET, Rounding.Up);\n  } else {\n    maxAmountOut = bin.amountX;\n    maxAmountIn = mulShr(bin.amountX, bin.price, SCALE_OFFSET, Rounding.Up);\n  }\n\n  if (outAmount.gte(maxAmountOut)) {\n    const maxFee = computeFee(binStep, sParameter, vParameter, maxAmountIn);\n    const protocolFee = computeProtocolFee(maxFee, sParameter);\n    return {\n      amountIn: maxAmountIn,\n      amountOut: maxAmountOut,\n      fee: maxFee,\n      protocolFee,\n    };\n  } else {\n    const amountIn = getAmountIn(outAmount, bin.price, swapForY);\n    const fee = computeFee(binStep, sParameter, vParameter, amountIn);\n    const protocolFee = computeProtocolFee(fee, sParameter);\n    return {\n      amountIn,\n      amountOut: outAmount,\n      fee,\n      protocolFee,\n    };\n  }\n}\n\nexport function swapExactInQuoteAtBin(\n  bin: Bin,\n  binStep: number,\n  sParameter: sParameters,\n  vParameter: vParameters,\n  inAmount: BN,\n  swapForY: boolean\n): {\n  amountIn: BN;\n  amountOut: BN;\n  fee: BN;\n  protocolFee: BN;\n} {\n  if (swapForY && bin.amountY.isZero()) {\n    return {\n      amountIn: new BN(0),\n      amountOut: new BN(0),\n      fee: new BN(0),\n      protocolFee: new BN(0),\n    };\n  }\n\n  if (!swapForY && bin.amountX.isZero()) {\n    return {\n      amountIn: new BN(0),\n      amountOut: new BN(0),\n      fee: new BN(0),\n      protocolFee: new BN(0),\n    };\n  }\n\n  let maxAmountOut: BN;\n  let maxAmountIn: BN;\n\n  if (swapForY) {\n    maxAmountOut = bin.amountY;\n    maxAmountIn = shlDiv(bin.amountY, bin.price, SCALE_OFFSET, Rounding.Up);\n  } else {\n    maxAmountOut = bin.amountX;\n    maxAmountIn = mulShr(bin.amountX, bin.price, SCALE_OFFSET, Rounding.Up);\n  }\n\n  const maxFee = computeFee(binStep, sParameter, vParameter, maxAmountIn);\n  maxAmountIn = maxAmountIn.add(maxFee);\n\n  let amountInWithFees: BN;\n  let amountOut: BN;\n  let fee: BN;\n  let protocolFee: BN;\n\n  if (inAmount.gt(maxAmountIn)) {\n    amountInWithFees = maxAmountIn;\n    amountOut = maxAmountOut;\n    fee = maxFee;\n    protocolFee = computeProtocolFee(maxFee, sParameter);\n  } else {\n    fee = computeFeeFromAmount(binStep, sParameter, vParameter, inAmount);\n    const amountInAfterFee = inAmount.sub(fee);\n    const computedOutAmount = getOutAmount(bin, amountInAfterFee, swapForY);\n\n    amountOut = computedOutAmount.gt(maxAmountOut)\n      ? maxAmountOut\n      : computedOutAmount;\n    protocolFee = computeProtocolFee(fee, sParameter);\n    amountInWithFees = inAmount;\n  }\n\n  return {\n    amountIn: amountInWithFees,\n    amountOut,\n    fee,\n    protocolFee,\n  };\n}\n\nfunction getAmountIn(amountOut: BN, price: BN, swapForY: Boolean): BN {\n  if (swapForY) {\n    return shlDiv(amountOut, price, SCALE_OFFSET, Rounding.Up);\n  } else {\n    return mulShr(amountOut, price, SCALE_OFFSET, Rounding.Up);\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/index.ts",
    "content": "import { AnchorProvider, BN, EventParser, Program } from \"@coral-xyz/anchor\";\nimport { IdlDiscriminator } from \"@coral-xyz/anchor/dist/cjs/idl\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  NATIVE_MINT,\n  TOKEN_PROGRAM_ID,\n  TokenAccountNotFoundError,\n  TokenInvalidAccountOwnerError,\n  createAssociatedTokenAccountIdempotentInstruction,\n  createCloseAccountInstruction,\n  getAccount,\n  getAssociatedTokenAddressSync,\n  getMint,\n} from \"@solana/spl-token\";\nimport {\n  AccountInfo,\n  Cluster,\n  ComputeBudgetProgram,\n  Connection,\n  GetProgramAccountsFilter,\n  PublicKey,\n  SystemProgram,\n  TransactionInstruction,\n} from \"@solana/web3.js\";\nimport { DLMM } from \"..\";\nimport {\n  LBCLMM_PROGRAM_IDS,\n  MAX_BINS_PER_POSITION,\n  SCALE_OFFSET,\n  U64_MAX,\n} from \"../constants\";\nimport IDL from \"../idl/idl.json\";\nimport { LbClmm } from \"../idl/idl\";\nimport {\n  AccountName,\n  ActionType,\n  Bin,\n  BinArray,\n  BinArrayBitmapExtension,\n  ChunkCallback,\n  ClmmProgram,\n  GetOrCreateATAResponse,\n  LbPair,\n  Oracle,\n  Position,\n  PositionV2,\n  PresetParameter,\n  PresetParameter2,\n  REBALANCE_POSITION_PADDING,\n  RebalanceAddLiquidityParam,\n  ShrinkMode,\n  StrategyParameters,\n} from \"../types\";\nimport {\n  deriveBinArrayBitmapExtension,\n  isOverflowDefaultBinArrayBitmap,\n} from \"./binArray\";\nimport {\n  DEFAULT_ADD_LIQUIDITY_CU,\n  DEFAULT_INIT_BIN_ARRAY_CU,\n  MAX_CU,\n  MAX_CU_BUFFER,\n  MIN_CU_BUFFER,\n  getSimulationComputeUnits,\n} from \"./computeUnit\";\nimport { deriveBinArray, derivePlaceHolderAccountMeta } from \"./derive\";\nimport { Rounding, mulShr, shlDiv } from \"./math\";\nimport { chunkBinRange, getBinArrayIndexesCoverage } from \"./positions\";\nimport {\n  LiquidityStrategyParameters,\n  buildBitFlagAndNegateStrategyParameters,\n  toAmountIntoBins,\n} from \"./rebalance\";\nimport { calculateTransferFeeIncludedAmount } from \"./token_2022\";\nimport Decimal from \"decimal.js\";\n\nexport * from \"./binArray\";\nexport * from \"./derive\";\nexport * from \"./fee\";\nexport * from \"./lbPair\";\nexport * from \"./positions\";\nexport * from \"./rebalance\";\nexport * from \"./strategy\";\nexport * from \"./weight\";\nexport * from \"./weightToAmounts\";\nexport * from \"./oracle\";\n\nexport function chunks<T>(array: T[], size: number): T[][] {\n  return Array.apply(0, new Array(Math.ceil(array.length / size))).map(\n    (_, index) => array.slice(index * size, (index + 1) * size),\n  );\n}\n\nexport function range<T>(min: number, max: number, mapfn: (i: number) => T) {\n  const length = max - min + 1;\n  return Array.from({ length }, (_, i) => mapfn(min + i));\n}\n\nexport async function chunkedFetchMultiplePoolAccount(\n  program: ClmmProgram,\n  pks: PublicKey[],\n  chunkSize: number = 100,\n) {\n  const accounts = (\n    await Promise.all(\n      chunks(pks, chunkSize).map((chunk) =>\n        program.account.lbPair.fetchMultiple(chunk),\n      ),\n    )\n  ).flat();\n\n  return accounts.filter(Boolean);\n}\n\nexport async function chunkedFetchMultipleBinArrayBitmapExtensionAccount(\n  program: ClmmProgram,\n  pks: PublicKey[],\n  chunkSize: number = 100,\n) {\n  const accounts = (\n    await Promise.all(\n      chunks(pks, chunkSize).map((chunk) =>\n        program.account.binArrayBitmapExtension.fetchMultiple(chunk),\n      ),\n    )\n  ).flat();\n\n  return accounts;\n}\n\nexport function getOutAmount(bin: Bin, inAmount: BN, swapForY: boolean) {\n  return swapForY\n    ? mulShr(inAmount, bin.price, SCALE_OFFSET, Rounding.Down)\n    : shlDiv(inAmount, bin.price, SCALE_OFFSET, Rounding.Down);\n}\n\nexport async function getTokenDecimals(conn: Connection, mint: PublicKey) {\n  const token = await getMint(conn, mint);\n  return await token.decimals;\n}\n\nexport const getOrCreateATAInstruction = async (\n  connection: Connection,\n  tokenMint: PublicKey,\n  owner: PublicKey,\n  programId?: PublicKey,\n  payer: PublicKey = owner,\n  allowOwnerOffCurve = true,\n): Promise<GetOrCreateATAResponse> => {\n  programId = programId ?? TOKEN_PROGRAM_ID;\n  const toAccount = getAssociatedTokenAddressSync(\n    tokenMint,\n    owner,\n    allowOwnerOffCurve,\n    programId,\n    ASSOCIATED_TOKEN_PROGRAM_ID,\n  );\n\n  try {\n    await getAccount(connection, toAccount, connection.commitment, programId);\n\n    return { ataPubKey: toAccount, ix: undefined };\n  } catch (e) {\n    if (\n      e instanceof TokenAccountNotFoundError ||\n      e instanceof TokenInvalidAccountOwnerError\n    ) {\n      const ix = createAssociatedTokenAccountIdempotentInstruction(\n        payer,\n        toAccount,\n        owner,\n        tokenMint,\n        programId,\n        ASSOCIATED_TOKEN_PROGRAM_ID,\n      );\n\n      return { ataPubKey: toAccount, ix };\n    } else {\n      /* handle error */\n      console.error(\"Error::getOrCreateATAInstruction\", e);\n      throw e;\n    }\n  }\n};\n\nexport async function getTokenBalance(\n  conn: Connection,\n  tokenAccount: PublicKey,\n): Promise<bigint> {\n  const acc = await getAccount(conn, tokenAccount);\n  return acc.amount;\n}\n\nexport const parseLogs = <T>(eventParser: EventParser, logs: string[]) => {\n  if (!logs.length) throw new Error(\"No logs found\");\n\n  for (const event of eventParser?.parseLogs(logs)) {\n    return event.data as T;\n  }\n\n  throw new Error(\"No events found\");\n};\n\nexport const wrapSOLInstruction = (\n  from: PublicKey,\n  to: PublicKey,\n  amount: bigint,\n): TransactionInstruction[] => {\n  return [\n    SystemProgram.transfer({\n      fromPubkey: from,\n      toPubkey: to,\n      lamports: amount,\n    }),\n    new TransactionInstruction({\n      keys: [\n        {\n          pubkey: to,\n          isSigner: false,\n          isWritable: true,\n        },\n      ],\n      data: Buffer.from(new Uint8Array([17])),\n      programId: TOKEN_PROGRAM_ID,\n    }),\n  ];\n};\n\nexport const unwrapSOLInstruction = async (\n  owner: PublicKey,\n  allowOwnerOffCurve = true,\n) => {\n  const wSolATAAccount = getAssociatedTokenAddressSync(\n    NATIVE_MINT,\n    owner,\n    allowOwnerOffCurve,\n  );\n  if (wSolATAAccount) {\n    const closedWrappedSolInstruction = createCloseAccountInstruction(\n      wSolATAAccount,\n      owner,\n      owner,\n      [],\n      TOKEN_PROGRAM_ID,\n    );\n    return closedWrappedSolInstruction;\n  }\n  return null;\n};\n\nexport async function chunkedGetMultipleAccountInfos(\n  connection: Connection,\n  pks: PublicKey[],\n  chunkSize: number = 100,\n) {\n  const accountInfos = (\n    await Promise.all(\n      chunks(pks, chunkSize).map((chunk) =>\n        connection.getMultipleAccountsInfo(chunk),\n      ),\n    )\n  ).flat();\n\n  return accountInfos;\n}\n\n/**\n * Fetches program accounts in a chunked manner to handle large result sets.\n *\n * This function uses a two-phase approach to avoid RPC timeouts and response size limits:\n * 1. First fetches only account pubkeys using dataSlice with zero length\n * 2. Then fetches full account data in chunks using getMultipleAccountsInfo\n *\n * This is particularly useful when fetching many accounts (e.g., 1000+ positions)\n * where a single getProgramAccounts call might timeout or exceed the 50MB response limit.\n *\n * @param connection - The Solana connection object\n * @param programId - The program ID to fetch accounts from\n * @param filters - Array of filters to apply (e.g., account discriminator, owner filter)\n * @param chunkSize - Optional number of accounts to fetch per chunk (default: 100)\n * @param onChunkFetched - Optional callback called as each chunk completes (in parallel mode, order not guaranteed)\n * @param isParallelExecution - Optional flag to control execution mode. When true, chunks are fetched in parallel. When false (default), chunks are fetched sequentially.\n * @returns Array of objects containing pubkey and account info\n */\nexport async function chunkedGetProgramAccounts(\n  connection: Connection,\n  programId: PublicKey,\n  filters: GetProgramAccountsFilter[],\n  chunkSize: number = 100,\n  onChunkFetched?: ChunkCallback,\n  isParallelExecution: boolean = false,\n): Promise<{ pubkey: PublicKey; account: AccountInfo<Buffer> }[]> {\n  // Fetch only pubkeys using dataSlice with zero length\n  const accountsWithoutData = await connection.getProgramAccounts(programId, {\n    filters,\n    dataSlice: { offset: 0, length: 0 },\n  });\n\n  if (accountsWithoutData.length === 0) {\n    return [];\n  }\n\n  const pubkeys = accountsWithoutData.map((account) => account.pubkey);\n  const totalAccounts = pubkeys.length;\n\n  // Fetch full account data in chunks\n  const chunkedPks = chunks(pubkeys, chunkSize);\n  const totalChunks = chunkedPks.length;\n\n  // Track progress for callback\n  let chunksLoaded = 0;\n  let accountsLoaded = 0;\n\n  // Results array to maintain order\n  const chunkResults: (AccountInfo<Buffer> | null)[][] = new Array(totalChunks);\n\n  const processChunk = async (chunk: PublicKey[], chunkIndex: number) => {\n    const chunkAccountInfos = await connection.getMultipleAccountsInfo(chunk);\n    chunkResults[chunkIndex] = chunkAccountInfos;\n\n    // Call callback if provided\n    if (onChunkFetched) {\n      const chunkAccounts: {\n        pubkey: PublicKey;\n        account: AccountInfo<Buffer>;\n      }[] = [];\n      const startIdx = chunkIndex * chunkSize;\n      for (let i = 0; i < chunkAccountInfos.length; i++) {\n        const accountInfo = chunkAccountInfos[i];\n        if (accountInfo) {\n          chunkAccounts.push({\n            pubkey: pubkeys[startIdx + i],\n            account: accountInfo,\n          });\n        }\n      }\n\n      chunksLoaded++;\n      accountsLoaded += chunkAccounts.length;\n\n      onChunkFetched(chunkAccounts, {\n        chunksLoaded,\n        totalChunks,\n        accountsLoaded,\n        totalAccounts,\n      });\n    }\n  };\n\n  if (isParallelExecution) {\n    // Parallel execution (callback progress is approximate due to parallel execution)\n    await Promise.all(\n      chunkedPks.map((chunk, chunkIndex) => processChunk(chunk, chunkIndex)),\n    );\n  } else {\n    // Sequential execution (callback progress is accurate and in order)\n    for (let chunkIndex = 0; chunkIndex < chunkedPks.length; chunkIndex++) {\n      await processChunk(chunkedPks[chunkIndex], chunkIndex);\n    }\n  }\n\n  // Combine all results in order\n  const result: { pubkey: PublicKey; account: AccountInfo<Buffer> }[] = [];\n  for (let chunkIndex = 0; chunkIndex < chunkResults.length; chunkIndex++) {\n    const chunkAccountInfos = chunkResults[chunkIndex];\n    const startIdx = chunkIndex * chunkSize;\n    for (let i = 0; i < chunkAccountInfos.length; i++) {\n      const accountInfo = chunkAccountInfos[i];\n      if (accountInfo) {\n        result.push({\n          pubkey: pubkeys[startIdx + i],\n          account: accountInfo,\n        });\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Gets the estimated compute unit usage with a buffer.\n * @param connection A Solana connection object.\n * @param instructions The instructions of the transaction to simulate.\n * @param feePayer The public key of the fee payer.\n * @param buffer The buffer to add to the estimated compute unit usage. Max value is 1. Default value is 0.1 if not provided, and will be capped between 50k - 200k.\n * @returns The estimated compute unit usage with the buffer.\n */\nexport const getEstimatedComputeUnitUsageWithBuffer = async (\n  connection: Connection,\n  instructions: TransactionInstruction[],\n  feePayer: PublicKey,\n  buffer?: number,\n  altAddress?: PublicKey,\n) => {\n  if (!buffer) {\n    buffer = 0.1;\n  }\n  // Avoid negative value\n  buffer = Math.max(0, buffer);\n  // Limit buffer to 1\n  buffer = Math.min(1, buffer);\n\n  const altAccounts = [];\n\n  if (altAddress) {\n    const altAccountInfo = await connection.getAddressLookupTable(altAddress);\n    altAccounts.push(altAccountInfo.value);\n  }\n\n  const estimatedComputeUnitUsage = await getSimulationComputeUnits(\n    connection,\n    instructions,\n    feePayer,\n    altAccounts,\n  );\n\n  let extraComputeUnitBuffer = estimatedComputeUnitUsage * buffer;\n  if (extraComputeUnitBuffer > MAX_CU_BUFFER) {\n    extraComputeUnitBuffer = MAX_CU_BUFFER;\n  } else if (extraComputeUnitBuffer < MIN_CU_BUFFER) {\n    extraComputeUnitBuffer = MIN_CU_BUFFER;\n  }\n\n  return estimatedComputeUnitUsage + extraComputeUnitBuffer;\n};\n\n/**\n * Gets the estimated compute unit usage with a buffer and converts it to a SetComputeUnitLimit instruction.\n * If the estimated compute unit usage cannot be retrieved, returns a SetComputeUnitLimit instruction with the fallback unit.\n * @param connection A Solana connection object.\n * @param instructions The instructions of the transaction to simulate.\n * @param feePayer The public key of the fee payer.\n * @param buffer The buffer to add to the estimated compute unit usage. Max value is 1. Default value is 0.1 if not provided, and will be capped between 50k - 200k.\n * @returns A SetComputeUnitLimit instruction with the estimated compute unit usage.\n */\nexport const getEstimatedComputeUnitIxWithBuffer = async (\n  connection: Connection,\n  instructions: TransactionInstruction[],\n  feePayer: PublicKey,\n  buffer?: number,\n  altAddress?: PublicKey,\n) => {\n  const units = await getEstimatedComputeUnitUsageWithBuffer(\n    connection,\n    instructions,\n    feePayer,\n    buffer,\n    altAddress,\n  ).catch((error) => {\n    console.error(\"Error::getEstimatedComputeUnitUsageWithBuffer\", error);\n    return 1_400_000;\n  });\n\n  return ComputeBudgetProgram.setComputeUnitLimit({ units });\n};\n\nexport type Opt = {\n  cluster?: Cluster | \"localhost\";\n  programId?: PublicKey;\n  skipSolWrappingOperation?: boolean;\n};\n\nexport function createProgram(connection: Connection, opt?: Opt) {\n  const cluster = opt?.cluster || \"mainnet-beta\";\n  const provider = new AnchorProvider(\n    connection,\n    {} as any,\n    AnchorProvider.defaultOptions(),\n  );\n\n  return new Program<LbClmm>(\n    { ...IDL, address: opt?.programId ?? LBCLMM_PROGRAM_IDS[cluster] },\n    provider,\n  );\n}\n\nexport function decodeAccount<\n  T extends\n    | LbPair\n    | BinArrayBitmapExtension\n    | BinArray\n    | PositionV2\n    | Position\n    | PresetParameter\n    | PresetParameter2\n    | Oracle,\n>(program: Program<LbClmm>, accountName: AccountName, buffer: Buffer): T {\n  return program.coder.accounts.decode(accountName, buffer);\n}\n\nexport function getAccountDiscriminator(\n  accountName: AccountName,\n): IdlDiscriminator {\n  return IDL.accounts.find(\n    (acc) => acc.name.toLowerCase() === accountName.toLowerCase(),\n  )?.discriminator;\n}\n\n/**\n * Caps a slippage percentage to be between 0 and 100.\n * @param slippage The slippage percentage to be capped.\n * @returns The capped slippage percentage.\n */\nexport function capSlippagePercentage(slippage: number) {\n  if (slippage > 100) {\n    slippage = 100;\n  }\n\n  if (slippage < 0) {\n    slippage = 0;\n  }\n\n  return slippage;\n}\n/**\n * Given a slippage percentage and a bin step, calculate the maximum number of bins\n * that the user is willing to allow the active bin to drift from the target price.\n * If the slippage percentage is 0 or null, return the maxActiveBinSlippage instead.\n *\n * @param slippagePercentage The slippage percentage in basis points.\n * @param binStep The bin step of the pair.\n * @param maxActiveBinSlippage The maximum number of bins that the active bin can drift.\n * @returns The maximum number of bins that the user is willing to allow the active bin to drift.\n */\nexport function getAndCapMaxActiveBinSlippage(\n  slippagePercentage: number,\n  binStep: number,\n  maxActiveBinSlippage: number,\n) {\n  return slippagePercentage\n    ? Math.ceil(slippagePercentage / (binStep / 100))\n    : maxActiveBinSlippage;\n}\n\n/**\n * Calculates the number of bins in a given range.\n *\n * @param minBinId The minimum bin id of the range.\n * @param maxBinId The maximum bin id of the range.\n * @returns The number of bins in the range.\n */\nexport function getBinCount(minBinId: number, maxBinId: number) {\n  return maxBinId - minBinId + 1;\n}\n\n/**\n * Calculates the maximum amount of tokens after applying slippage to the given amount.\n *\n * @param amount The amount of tokens before slippage.\n * @param slippage The percentage of slippage to apply.\n * @returns The maximum amount of tokens after applying slippage. If the slippage is 100%, the maximum amount is U64_MAX.\n *\n **/\nexport function getSlippageMaxAmount(amount: BN, slippage: number) {\n  if (slippage == 100) {\n    return U64_MAX;\n  }\n\n  const amountDecimal = new Decimal(amount.toString());\n\n  const slippageAppliedAmount = new BN(\n    amountDecimal\n      .mul(new Decimal(100 + slippage))\n      .div(new Decimal(100))\n      .floor()\n      .toString(),\n  );\n\n  return slippageAppliedAmount;\n}\n\n/**\n * Calculates the minimum amount of tokens after applying slippage to the given amount.\n *\n * @param amount The amount of tokens before slippage.\n * @param slippage The percentage of slippage to apply.\n * @returns The minimum amount of tokens after applying slippage.\n */\nexport function getSlippageMinAmount(amount: BN, slippage: number) {\n  const amountDecimal = new Decimal(amount.toString());\n  return new BN(\n    amountDecimal\n      .mul(new Decimal(100 - slippage))\n      .div(new Decimal(100))\n      .ceil()\n      .toString(),\n  );\n}\n\n/**\n * Calculates the number of positions required to cover a range of bins.\n *\n * @param binCount The number of bins in the range.\n * @returns The number of positions required to cover the range of bins.\n */\nexport function getPositionCountByBinCount(binCount: number) {\n  return Math.ceil(binCount / MAX_BINS_PER_POSITION.toNumber());\n}\n\n/**\n * Adjusts the liquidity parameters to reset uninvolved liquidity based on delta IDs.\n *\n * This function modifies the provided liquidity strategy parameters by resetting\n * the x0, y0, deltaX, and deltaY values when certain conditions regarding the\n * minDeltaId and maxDeltaId are met. If the maxDeltaId is less than or equal\n * to the end of the bid side delta ID, x0 and deltaX are set to zero. If the\n * minDeltaId is greater than or equal to the start of the ask side delta ID,\n * y0 and deltaY are set to zero.\n *\n * @param minDeltaId - The minimum delta ID.\n * @param maxDeltaId - The maximum delta ID.\n * @param favorXInActiveId - A boolean indicating if X is favored in the active bin.\n * @param params - The liquidity strategy parameters containing x0, y0, deltaX, and deltaY.\n * @returns An object containing the adjusted x0, y0, deltaX, and deltaY values.\n */\n\nexport function resetUninvolvedLiquidityParams(\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  favorXInActiveId: boolean,\n  params: LiquidityStrategyParameters,\n) {\n  const endBidSideDeltaId = favorXInActiveId ? new BN(-1) : new BN(0);\n  const startAskSideDeltaId = endBidSideDeltaId.addn(1);\n\n  let x0 = params.x0;\n  let y0 = params.y0;\n  let deltaX = params.deltaX;\n  let deltaY = params.deltaY;\n\n  if (maxDeltaId.lte(endBidSideDeltaId)) {\n    deltaX = new BN(0);\n    x0 = new BN(0);\n  }\n\n  if (minDeltaId.gte(startAskSideDeltaId)) {\n    deltaY = new BN(0);\n    y0 = new BN(0);\n  }\n\n  return {\n    x0,\n    y0,\n    deltaX,\n    deltaY,\n  };\n}\n\nexport async function chunkDepositWithRebalanceEndpoint(\n  dlmm: DLMM,\n  strategy: StrategyParameters,\n  slippagePercentage: number,\n  maxActiveBinSlippage: number,\n  position: PublicKey,\n  positionMinBinId: number,\n  positionMaxBinId: number,\n  liquidityStrategyParameters: LiquidityStrategyParameters,\n  owner: PublicKey,\n  payer: PublicKey,\n  // When isParallel = false, instructions must be executed sequentially\n  isParallel: boolean,\n  skipSolWrappingOperation: boolean = false,\n) {\n  const { slices, accounts: transferHookAccounts } =\n    dlmm.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n  const userTokenX = getAssociatedTokenAddressSync(\n    dlmm.lbPair.tokenXMint,\n    owner,\n    true,\n    dlmm.tokenX.owner,\n  );\n\n  const userTokenY = getAssociatedTokenAddressSync(\n    dlmm.lbPair.tokenYMint,\n    owner,\n    true,\n    dlmm.tokenY.owner,\n  );\n\n  const createUserTokenXIx = createAssociatedTokenAccountIdempotentInstruction(\n    payer,\n    userTokenX,\n    owner,\n    dlmm.lbPair.tokenXMint,\n    dlmm.tokenX.owner,\n  );\n\n  const createUserTokenYIx = createAssociatedTokenAccountIdempotentInstruction(\n    payer,\n    userTokenY,\n    owner,\n    dlmm.lbPair.tokenYMint,\n    dlmm.tokenY.owner,\n  );\n\n  const bitmapPubkey = deriveBinArrayBitmapExtension(\n    dlmm.pubkey,\n    dlmm.program.programId,\n  )[0];\n\n  let calculatedAddLiquidityCU = 0;\n\n  const chunkedAddLiquidityIx: TransactionInstruction[][] = [];\n  const chunkedBinRange = chunkBinRange(positionMinBinId, positionMaxBinId);\n\n  const binArrayOrBitmapInitTracking = new Set<String>();\n\n  for (let i = 0; i < chunkedBinRange.length; i++) {\n    const chunkMinBinId = chunkedBinRange[i].lowerBinId;\n    const chunkMaxBinId = chunkedBinRange[i].upperBinId;\n\n    const initBinArrayIxs: TransactionInstruction[] = [];\n    const initBitmapIxs: TransactionInstruction[] = [];\n\n    const binArrayIndexes = getBinArrayIndexesCoverage(\n      new BN(chunkMinBinId),\n      new BN(chunkMaxBinId),\n    );\n\n    const overflowDefaultBinArrayBitmap = binArrayIndexes.reduce(\n      (acc, binArrayIndex) =>\n        acc || isOverflowDefaultBinArrayBitmap(binArrayIndex),\n      false,\n    );\n\n    if (overflowDefaultBinArrayBitmap) {\n      const initBitmapIx = await dlmm.program.methods\n        .initializeBinArrayBitmapExtension()\n        .accountsPartial({\n          binArrayBitmapExtension: bitmapPubkey,\n          lbPair: dlmm.pubkey,\n          funder: payer,\n        })\n        .instruction();\n\n      initBitmapIxs.push(initBitmapIx);\n      binArrayOrBitmapInitTracking.add(bitmapPubkey.toBase58());\n    }\n\n    const binArrayPubkeys = binArrayIndexes.map(\n      (index) => deriveBinArray(dlmm.pubkey, index, dlmm.program.programId)[0],\n    );\n\n    for (const [idx, binArrayPubkey] of binArrayPubkeys.entries()) {\n      const initBinArrayIx = await dlmm.program.methods\n        .initializeBinArray(binArrayIndexes[idx])\n        .accountsPartial({\n          binArray: binArrayPubkey,\n          funder: payer,\n          lbPair: dlmm.pubkey,\n        })\n        .instruction();\n\n      if (isParallel) {\n        initBinArrayIxs.push(initBinArrayIx);\n      } else if (!binArrayOrBitmapInitTracking.has(binArrayPubkey.toBase58())) {\n        binArrayOrBitmapInitTracking.add(binArrayPubkey.toBase58());\n        initBinArrayIxs.push(initBinArrayIx);\n        calculatedAddLiquidityCU += DEFAULT_INIT_BIN_ARRAY_CU;\n      }\n    }\n\n    const minDeltaId = new BN(chunkMinBinId - dlmm.lbPair.activeId);\n    const maxDeltaId = new BN(chunkMaxBinId - dlmm.lbPair.activeId);\n\n    const { deltaX, deltaY, x0, y0 } = resetUninvolvedLiquidityParams(\n      minDeltaId,\n      maxDeltaId,\n      strategy.singleSidedX,\n      {\n        ...liquidityStrategyParameters,\n      },\n    );\n\n    const { bitFlag, ...baseAndDelta } =\n      buildBitFlagAndNegateStrategyParameters(x0, y0, deltaX, deltaY);\n\n    const addParam: RebalanceAddLiquidityParam = {\n      minDeltaId: minDeltaId.toNumber(),\n      maxDeltaId: maxDeltaId.toNumber(),\n      x0: baseAndDelta.x0,\n      y0: baseAndDelta.y0,\n      deltaX: baseAndDelta.deltaX,\n      deltaY: baseAndDelta.deltaY,\n      bitFlag,\n      favorXInActiveId: strategy.singleSidedX,\n      padding: Array(36).fill(0),\n    };\n\n    const { totalXAmount, totalYAmount } = toAmountIntoBins(\n      new BN(dlmm.lbPair.activeId),\n      minDeltaId,\n      maxDeltaId,\n      deltaX,\n      deltaY,\n      x0,\n      y0,\n      new BN(dlmm.lbPair.binStep),\n      strategy.singleSidedX,\n    ).reduce(\n      (acc, bin) => {\n        return {\n          totalXAmount: acc.totalXAmount.add(bin.amountX),\n          totalYAmount: acc.totalYAmount.add(bin.amountY),\n        };\n      },\n      {\n        totalXAmount: new BN(0),\n        totalYAmount: new BN(0),\n      },\n    );\n\n    const totalXAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(\n      totalXAmount,\n      dlmm.tokenX.mint,\n      dlmm.clock.epoch.toNumber(),\n    ).amount;\n\n    const totalYAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(\n      totalYAmount,\n      dlmm.tokenY.mint,\n      dlmm.clock.epoch.toNumber(),\n    ).amount;\n\n    const maxDepositXAmount = getSlippageMaxAmount(\n      totalXAmountIncludeTransferFee,\n      slippagePercentage,\n    );\n\n    const maxDepositYAmount = getSlippageMaxAmount(\n      totalYAmountIncludeTransferFee,\n      slippagePercentage,\n    );\n\n    let shrinkMode: ShrinkMode;\n\n    if (isParallel) {\n      if (i == 0) {\n        shrinkMode = ShrinkMode.NoShrinkRight;\n      } else if (i == chunkBinRange.length - 1) {\n        shrinkMode = ShrinkMode.NoShrinkLeft;\n      } else {\n        shrinkMode = ShrinkMode.NoShrinkBoth;\n      }\n    } else {\n      shrinkMode = ShrinkMode.ShrinkBoth;\n    }\n\n    const rebalanceIx = await dlmm.program.methods\n      .rebalanceLiquidity(\n        {\n          activeId: dlmm.lbPair.activeId,\n          maxActiveBinSlippage,\n          shouldClaimFee: false,\n          shouldClaimReward: false,\n          minWithdrawXAmount: new BN(0),\n          minWithdrawYAmount: new BN(0),\n          maxDepositXAmount,\n          maxDepositYAmount,\n          removes: [],\n          adds: [addParam],\n          shrinkMode,\n          padding: REBALANCE_POSITION_PADDING,\n        },\n        {\n          slices,\n        },\n      )\n      .accountsPartial({\n        binArrayBitmapExtension:\n          initBitmapIxs.length > 0 ? bitmapPubkey : dlmm.program.programId,\n        lbPair: dlmm.pubkey,\n        position,\n        owner,\n        tokenXMint: dlmm.lbPair.tokenXMint,\n        tokenYMint: dlmm.lbPair.tokenYMint,\n        userTokenX,\n        userTokenY,\n        tokenXProgram: dlmm.tokenX.owner,\n        tokenYProgram: dlmm.tokenY.owner,\n        rentPayer: payer,\n      })\n      .remainingAccounts([\n        ...transferHookAccounts,\n        ...binArrayPubkeys.map((baPubkey) => ({\n          pubkey: baPubkey,\n          isWritable: true,\n          isSigner: false,\n        })),\n        derivePlaceHolderAccountMeta(dlmm.program.programId),\n      ])\n      .instruction();\n\n    calculatedAddLiquidityCU += DEFAULT_ADD_LIQUIDITY_CU;\n\n    const addLiquidityIxs: TransactionInstruction[] = [];\n\n    addLiquidityIxs.push(...initBitmapIxs, ...initBinArrayIxs);\n\n    if (isParallel) {\n      addLiquidityIxs.push(createUserTokenXIx);\n      addLiquidityIxs.push(createUserTokenYIx);\n    }\n\n    if (\n      dlmm.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        owner,\n        userTokenX,\n        BigInt(totalXAmount.toString()),\n      );\n\n      if (!isParallel) {\n        addLiquidityIxs.push(createUserTokenXIx);\n      }\n      addLiquidityIxs.push(...wrapSOLIx);\n    }\n\n    if (\n      dlmm.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        owner,\n        userTokenY,\n        BigInt(totalYAmount.toString()),\n      );\n\n      if (!isParallel) {\n        addLiquidityIxs.push(createUserTokenYIx);\n      }\n      addLiquidityIxs.push(...wrapSOLIx);\n    }\n\n    addLiquidityIxs.push(rebalanceIx);\n\n    if (\n      dlmm.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !totalXAmount.isZero() &&\n      !skipSolWrappingOperation\n    ) {\n      addLiquidityIxs.push(\n        createCloseAccountInstruction(\n          userTokenX,\n          owner,\n          owner,\n          [],\n          TOKEN_PROGRAM_ID,\n        ),\n      );\n    }\n\n    if (\n      dlmm.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !totalYAmount.isZero() &&\n      !skipSolWrappingOperation\n    ) {\n      addLiquidityIxs.push(\n        createCloseAccountInstruction(\n          userTokenY,\n          owner,\n          owner,\n          [],\n          TOKEN_PROGRAM_ID,\n        ),\n      );\n    }\n\n    if (!isParallel) {\n      addLiquidityIxs.unshift(\n        ComputeBudgetProgram.setComputeUnitLimit({\n          units: Math.min(calculatedAddLiquidityCU, MAX_CU),\n        }),\n      );\n    }\n\n    chunkedAddLiquidityIx.push(addLiquidityIxs);\n  }\n\n  return chunkedAddLiquidityIx;\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/lbPair.ts",
    "content": "import { AnchorProvider, Program } from \"@coral-xyz/anchor\";\nimport { Cluster, Connection, PublicKey } from \"@solana/web3.js\";\nimport { LBCLMM_PROGRAM_IDS } from \"../constants\";\nimport { LbPair } from \"../types\";\nimport { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\nimport { createProgram } from \".\";\n\n/**\n * It fetches the pool account from the AMM program, and returns the mint addresses for the two tokens\n * @param {Connection} connection - Connection - The connection to the Solana cluster\n * @param {string} poolAddress - The address of the pool account.\n * @returns The tokenAMint and tokenBMint addresses for the pool.\n */\nexport async function getTokensMintFromPoolAddress(\n  connection: Connection,\n  poolAddress: string,\n  opt?: {\n    cluster?: Cluster;\n    programId?: PublicKey;\n  }\n) {\n  const program = createProgram(connection, opt);\n\n  const poolAccount = await program.account.lbPair.fetchNullable(\n    new PublicKey(poolAddress)\n  );\n\n  if (!poolAccount) throw new Error(\"Pool account not found\");\n\n  return {\n    tokenXMint: poolAccount.tokenXMint,\n    tokenYMint: poolAccount.tokenYMint,\n  };\n}\n\nexport function getTokenProgramId(lbPairState: LbPair) {\n  const getTokenProgramIdByFlag = (flag: number) => {\n    return flag == 0 ? TOKEN_PROGRAM_ID : TOKEN_2022_PROGRAM_ID;\n  };\n  return {\n    tokenXProgram: getTokenProgramIdByFlag(lbPairState.tokenMintXProgramFlag),\n    tokenYProgram: getTokenProgramIdByFlag(lbPairState.tokenMintYProgramFlag),\n  };\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/math.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport {\n  BASIS_POINT_MAX,\n  DEFAULT_BIN_PER_POSITION,\n  SCALE_OFFSET,\n} from \"../constants\";\nimport Decimal from \"decimal.js\";\nimport { ONE, pow } from \"./u64xu64_math\";\nimport { DLMM } from \"..\";\nimport { getPriceOfBinByBinId } from \"./weight\";\n\nexport enum Rounding {\n  Up,\n  Down,\n}\n\nexport function mulShr(x: BN, y: BN, offset: number, rounding: Rounding) {\n  const denominator = new BN(1).shln(offset);\n  return mulDiv(x, y, denominator, rounding);\n}\n\nexport function shlDiv(x: BN, y: BN, offset: number, rounding: Rounding) {\n  const scale = new BN(1).shln(offset);\n  return mulDiv(x, scale, y, rounding);\n}\n\nexport function mulDiv(x: BN, y: BN, denominator: BN, rounding: Rounding) {\n  const { div, mod } = x.mul(y).divmod(denominator);\n\n  if (rounding == Rounding.Up && !mod.isZero()) {\n    return div.add(new BN(1));\n  }\n  return div;\n}\n\nexport function computeBaseFactorFromFeeBps(binStep: BN, feeBps: BN) {\n  const U16_MAX = 65535;\n  const computedBaseFactor =\n    (feeBps.toNumber() * BASIS_POINT_MAX) / binStep.toNumber();\n\n  if (computedBaseFactor > U16_MAX) {\n    let truncatedBaseFactor = computedBaseFactor;\n    let base_power_factor = 0;\n    while (truncatedBaseFactor > U16_MAX) {\n      const remainder = truncatedBaseFactor % 10;\n      if (remainder == 0) {\n        base_power_factor += 1;\n        truncatedBaseFactor /= 10;\n      } else {\n        throw \"have decimals\";\n      }\n    }\n\n    return [new BN(truncatedBaseFactor), new BN(base_power_factor)];\n  } else {\n    // Sanity check\n    const computedBaseFactorFloor = Math.floor(computedBaseFactor);\n    if (computedBaseFactor != computedBaseFactorFloor) {\n      if (computedBaseFactorFloor >= U16_MAX) {\n        throw \"base factor for the give fee bps overflow u16\";\n      }\n\n      if (computedBaseFactorFloor == 0) {\n        throw \"base factor for the give fee bps underflow\";\n      }\n\n      if (computedBaseFactor % 1 != 0) {\n        throw \"couldn't compute base factor for the exact fee bps\";\n      }\n    }\n\n    return [new BN(computedBaseFactor), new BN(0)];\n  }\n}\n\nexport function getQPriceFromId(binId: BN, binStep: BN): BN {\n  return pow(getQPriceBaseFactor(binStep), binId);\n}\n\nexport function getQPriceBaseFactor(binStep: BN): BN {\n  const bps = binStep.shln(SCALE_OFFSET).div(new BN(BASIS_POINT_MAX));\n  const base = ONE.add(bps);\n  return base;\n}\n\nexport function getC(\n  amount: BN,\n  binStep: number,\n  binId: BN,\n  baseTokenDecimal: number,\n  quoteTokenDecimal: number,\n  minPrice: Decimal,\n  maxPrice: Decimal,\n  k: number\n) {\n  const currentPricePerLamport = new Decimal(1 + binStep / 10000).pow(\n    binId.toNumber()\n  );\n  const currentPricePerToken = currentPricePerLamport.mul(\n    new Decimal(10 ** (baseTokenDecimal - quoteTokenDecimal))\n  );\n  const priceRange = maxPrice.sub(minPrice);\n  const currentPriceDeltaFromMin = currentPricePerToken.sub(\n    new Decimal(minPrice)\n  );\n\n  const c = new Decimal(amount.toString()).mul(\n    currentPriceDeltaFromMin.div(priceRange).pow(k)\n  );\n\n  return c.floor();\n}\n\nexport function distributeAmountToCompressedBinsByRatio(\n  compressedBinAmount: Map<number, BN>,\n  uncompressedAmount: BN,\n  multiplier: BN,\n  binCapAmount: BN\n) {\n  const newCompressedBinAmount = new Map<number, BN>();\n  let totalCompressedAmount = new BN(0);\n\n  for (const compressedAmount of compressedBinAmount.values()) {\n    totalCompressedAmount = totalCompressedAmount.add(compressedAmount);\n  }\n\n  let totalDepositedAmount = new BN(0);\n\n  for (const [binId, compressedAmount] of compressedBinAmount.entries()) {\n    const depositAmount = compressedAmount\n      .mul(uncompressedAmount)\n      .div(totalCompressedAmount);\n\n    let compressedDepositAmount = depositAmount.div(multiplier);\n\n    let newCompressedAmount = compressedAmount.add(compressedDepositAmount);\n    if (newCompressedAmount.gt(binCapAmount)) {\n      compressedDepositAmount = compressedDepositAmount.sub(\n        newCompressedAmount.sub(binCapAmount)\n      );\n      newCompressedAmount = binCapAmount;\n    }\n    newCompressedBinAmount.set(binId, newCompressedAmount);\n\n    totalDepositedAmount = totalDepositedAmount.add(\n      compressedDepositAmount.mul(multiplier)\n    );\n  }\n\n  const loss = uncompressedAmount.sub(totalDepositedAmount);\n\n  return {\n    newCompressedBinAmount,\n    loss,\n  };\n}\n\nexport function getPositionCount(minBinId: BN, maxBinId: BN) {\n  const binDelta = maxBinId.sub(minBinId);\n  const positionCount = binDelta.div(DEFAULT_BIN_PER_POSITION);\n  return positionCount.add(new BN(1));\n}\n\nexport function findOptimumDecompressMultiplier(\n  binAmount: Map<number, BN>,\n  tokenDecimal: BN\n) {\n  let multiplier = new BN(10).pow(tokenDecimal);\n\n  while (!multiplier.isZero()) {\n    let found = true;\n\n    for (const [_binId, amount] of binAmount) {\n      const compressedAmount = amount.div(multiplier);\n      if (compressedAmount.isZero()) {\n        multiplier = multiplier.div(new BN(10));\n        found = false;\n        break;\n      }\n    }\n\n    if (found) {\n      return multiplier;\n    }\n  }\n\n  throw \"Couldn't find optimum multiplier\";\n}\n\nexport function compressBinAmount(binAmount: Map<number, BN>, multiplier: BN) {\n  const compressedBinAmount = new Map<number, BN>();\n\n  let totalAmount = new BN(0);\n  let compressionLoss = new BN(0);\n\n  for (const [binId, amount] of binAmount) {\n    totalAmount = totalAmount.add(amount);\n    const compressedAmount = amount.div(multiplier);\n\n    compressedBinAmount.set(binId, compressedAmount);\n    let loss = amount.sub(compressedAmount.mul(multiplier));\n    compressionLoss = compressionLoss.add(loss);\n  }\n\n  return {\n    compressedBinAmount,\n    compressionLoss,\n  };\n}\n\nexport function generateAmountForBinRange(\n  amount: BN,\n  binStep: number,\n  tokenXDecimal: number,\n  tokenYDecimal: number,\n  minBinId: BN,\n  maxBinId: BN,\n  k: number\n) {\n  const toTokenMultiplier = new Decimal(10 ** (tokenXDecimal - tokenYDecimal));\n  const minPrice = getPriceOfBinByBinId(minBinId.toNumber(), binStep).mul(\n    toTokenMultiplier\n  );\n  const maxPrice = getPriceOfBinByBinId(maxBinId.toNumber(), binStep).mul(\n    toTokenMultiplier\n  );\n  const binAmounts = new Map<number, BN>();\n\n  for (let i = minBinId.toNumber(); i < maxBinId.toNumber(); i++) {\n    const binAmount = generateBinAmount(\n      amount,\n      binStep,\n      new BN(i),\n      tokenXDecimal,\n      tokenYDecimal,\n      minPrice,\n      maxPrice,\n      k\n    );\n\n    if (binAmount.isZero()) {\n      throw \"bin amount is zero\";\n    }\n\n    binAmounts.set(i, binAmount);\n  }\n\n  return binAmounts;\n}\n\nexport function generateBinAmount(\n  amount: BN,\n  binStep: number,\n  binId: BN,\n  tokenXDecimal: number,\n  tokenYDecimal: number,\n  minPrice: Decimal,\n  maxPrice: Decimal,\n  k: number\n) {\n  const c1 = getC(\n    amount,\n    binStep,\n    binId.add(new BN(1)),\n    tokenXDecimal,\n    tokenYDecimal,\n    minPrice,\n    maxPrice,\n    k\n  );\n\n  const c0 = getC(\n    amount,\n    binStep,\n    binId,\n    tokenXDecimal,\n    tokenYDecimal,\n    minPrice,\n    maxPrice,\n    k\n  );\n\n  return new BN(c1.sub(c0).floor().toString());\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/oracle/index.ts",
    "content": "export * from \"./wrapper\";\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/oracle/wrapper.ts",
    "content": "import { PublicKey } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport { Oracle } from \"../../types\";\nimport Decimal from \"decimal.js\";\nimport { getPriceOfBinByBinId } from \"../weight\";\nimport { Program } from \"@coral-xyz/anchor\";\nimport { LbClmm } from \"../../idl/idl\";\nimport { decodeAccount } from \"..\";\n\n/** Size in bytes of the oracle account metadata (discriminator + header fields). */\nconst ORACLE_METADATA_SIZE = 8 + 24;\n/** Size in bytes of a single observation entry (cumulativeActiveBinId: 16 + createdAt: 8 + lastUpdatedAt: 8). */\nconst OBSERVATION_SIZE = 32;\n\n/** Result of a TWAP (Time-Weighted Average Price) computation over a time range. */\nexport interface TwapResult<T> {\n  /** The computed TWAP value (active bin ID or price depending on the query). */\n  value: T;\n  /** Duration in seconds over which the TWAP was computed. */\n  duration: BN;\n}\n\n/**\n * Interface for querying time-weighted average data from an on-chain DLMM oracle.\n * Provides methods to retrieve TWAP active bin IDs and prices over arbitrary time ranges.\n */\nexport interface IDynamicOracle {\n  /** The public key of the oracle account. */\n  readonly oracleAddress: PublicKey;\n  /** The on-chain oracle metadata (idx, activeSize, length). */\n  readonly metadata: Oracle;\n  /** The decoded observation entries. */\n  readonly observations: Observation[];\n  /** Returns the maximum observable duration from the earliest sample to the given timestamp. */\n  getMaxDuration(currentTimestamp: BN): BN;\n  /**\n   * Computes the TWAP active bin ID between two arbitrary time points.\n   * @param timePoint0 - First time boundary (order does not matter).\n   * @param timePoint1 - Second time boundary (order does not matter).\n   * @returns The TWAP active bin ID and duration, or null if the range is not covered by oracle data.\n   */\n  getActiveIdByTime(timePoint0: BN, timePoint1: BN): TwapResult<BN> | null;\n  /**\n   * Computes the TWAP active bin ID from the earliest available observation to the current timestamp.\n   * @param currentTimestamp - The current on-chain timestamp.\n   * @returns The TWAP active bin ID and duration, or null if no data is available.\n   */\n  getActiveId(currentTimestamp: BN): TwapResult<BN> | null;\n  /**\n   * Computes the TWAP price (as a raw Decimal) between two time points.\n   * @param timePoint0 - First time boundary.\n   * @param timePoint1 - Second time boundary.\n   * @returns The TWAP price and duration, or null if the range is not covered.\n   */\n  getPriceByTime(timePoint0: BN, timePoint1: BN): TwapResult<Decimal> | null;\n  /**\n   * Computes the TWAP price adjusted for token decimals (human-readable) between two time points.\n   * @param timePoint0 - First time boundary.\n   * @param timePoint1 - Second time boundary.\n   * @returns The UI-friendly TWAP price and duration, or null if the range is not covered.\n   */\n  getUiPriceByTime(timePoint0: BN, timePoint1: BN): TwapResult<Decimal> | null;\n}\n\nexport class Observation {\n  constructor(\n    public cumulativeActiveBinId: BN,\n    public createdAt: BN,\n    public lastUpdatedAt: BN,\n  ) {}\n\n  isInitialized(): boolean {\n    return !this.createdAt.isZero() && !this.lastUpdatedAt.isZero();\n  }\n}\n\nexport function wrapOracle(\n  oracleAddress: PublicKey,\n  data: Buffer,\n  binStep: number,\n  currentActiveBinId: BN,\n  baseTokenDecimals: number,\n  quoteTokenDecimals: number,\n  program: Program<LbClmm>,\n) {\n  const oracleBaseData = data.subarray(0, ORACLE_METADATA_SIZE);\n  const oracleState: Oracle = decodeAccount(program, \"oracle\", oracleBaseData);\n\n  const observationSlice = data.subarray(ORACLE_METADATA_SIZE);\n  let observations: Observation[] = [];\n\n  for (let i = 0; i < oracleState.length.toNumber(); i++) {\n    let offset = i * OBSERVATION_SIZE;\n\n    const cumulativeActiveBinIdSlice = observationSlice.subarray(\n      offset,\n      offset + 16,\n    );\n\n    const cumulativeActiveBinId = new BN(\n      cumulativeActiveBinIdSlice,\n      \"le\",\n    ).fromTwos(128);\n\n    offset += 16;\n\n    const createdAtSlice = observationSlice.subarray(offset, offset + 8);\n    const createdAt = new BN(createdAtSlice, \"le\");\n\n    offset += 8;\n\n    const lastUpdatedAtSlice = observationSlice.subarray(offset, offset + 8);\n    const lastUpdatedAt = new BN(lastUpdatedAtSlice, \"le\");\n\n    observations.push(\n      new Observation(cumulativeActiveBinId, createdAt, lastUpdatedAt),\n    );\n  }\n\n  return new DynamicOracle(\n    oracleAddress,\n    oracleState,\n    observations,\n    binStep,\n    currentActiveBinId,\n    baseTokenDecimals,\n    quoteTokenDecimals,\n  );\n}\n\nexport class DynamicOracle implements IDynamicOracle {\n  constructor(\n    public readonly oracleAddress: PublicKey,\n    public readonly metadata: Oracle,\n    public readonly observations: Observation[],\n    private binStep: number,\n    private currentActiveBinId: BN,\n    private baseTokenDecimals: number,\n    private quoteTokenDecimals: number,\n  ) {}\n\n  nextIndex(): number {\n    const currentIndex = this.metadata.idx.toNumber();\n    const nextIndex = currentIndex + 1;\n    return nextIndex >= this.metadata.activeSize.toNumber() ? 0 : nextIndex;\n  }\n\n  getEarliestSample(): Observation {\n    const earliestIndex = this.nextIndex();\n    return this.observations[earliestIndex];\n  }\n\n  getLatestSample(): Observation {\n    return this.observations[this.metadata.idx.toNumber()];\n  }\n\n  findCumulativeActiveIdByTimestamp(activeId: BN, timestamp: BN): BN | null {\n    const latestSample = this.getLatestSample();\n\n    if (!latestSample.isInitialized()) {\n      return null;\n    }\n\n    if (timestamp.gte(latestSample.lastUpdatedAt)) {\n      const deltaSeconds = timestamp.sub(latestSample.lastUpdatedAt);\n      const accumulatedActiveId = activeId.mul(deltaSeconds);\n      return latestSample.cumulativeActiveBinId.add(accumulatedActiveId);\n    }\n\n    const earliestSample = this.getEarliestSample();\n\n    if (\n      !earliestSample.isInitialized() ||\n      timestamp.lt(earliestSample.lastUpdatedAt)\n    ) {\n      return null;\n    }\n\n    let currentIndex = this.metadata.idx.toNumber();\n\n    while (true) {\n      let previousIndex =\n        currentIndex == 0\n          ? this.metadata.activeSize.toNumber() - 1\n          : currentIndex - 1;\n\n      if (previousIndex == this.metadata.idx.toNumber()) {\n        return null;\n      }\n\n      const currentSample = this.observations[currentIndex];\n      const previousSample = this.observations[previousIndex];\n\n      if (timestamp.gte(previousSample.lastUpdatedAt)) {\n        const totalWeight = currentSample.lastUpdatedAt.sub(\n          previousSample.lastUpdatedAt,\n        );\n        if (totalWeight.isZero()) {\n          return previousSample.cumulativeActiveBinId;\n        }\n        const prevWeight = currentSample.lastUpdatedAt.sub(timestamp);\n        const nextWeight = timestamp.sub(previousSample.lastUpdatedAt);\n        return previousSample.cumulativeActiveBinId\n          .mul(prevWeight)\n          .add(currentSample.cumulativeActiveBinId.mul(nextWeight))\n          .div(totalWeight);\n      }\n\n      currentIndex = previousIndex;\n    }\n  }\n\n  getActiveIdByTime(timePoint0: BN, timePoint1: BN): TwapResult<BN> | null {\n    const t0 = BN.min(timePoint0, timePoint1);\n    const t1 = BN.max(timePoint0, timePoint1);\n    const duration = t1.sub(t0);\n\n    if (duration.isZero()) {\n      return null;\n    }\n\n    const cumulativeActiveBinId0 = this.findCumulativeActiveIdByTimestamp(\n      this.currentActiveBinId,\n      t0,\n    );\n\n    if (cumulativeActiveBinId0 === null) {\n      return null;\n    }\n\n    const cumulativeActiveBinId1 = this.findCumulativeActiveIdByTimestamp(\n      this.currentActiveBinId,\n      t1,\n    );\n\n    if (cumulativeActiveBinId1 === null) {\n      return null;\n    }\n\n    return {\n      value: cumulativeActiveBinId1.sub(cumulativeActiveBinId0).div(duration),\n      duration,\n    };\n  }\n\n  getActiveId(currentTimestamp: BN): TwapResult<BN> | null {\n    const timePoint0 = this.getEarliestTimestamp();\n\n    if (timePoint0 === null) {\n      return null;\n    }\n\n    const timePoint1 = currentTimestamp;\n    return this.getActiveIdByTime(timePoint0, timePoint1);\n  }\n\n  getEarliestTimestamp(): BN | null {\n    const earliestSample = this.getEarliestSample();\n    return earliestSample.isInitialized() ? earliestSample.lastUpdatedAt : null;\n  }\n\n  getPriceByTime(timePoint0: BN, timePoint1: BN): TwapResult<Decimal> | null {\n    const result = this.getActiveIdByTime(timePoint0, timePoint1);\n\n    if (result === null) {\n      return null;\n    }\n\n    return {\n      value: getPriceOfBinByBinId(result.value.toNumber(), this.binStep),\n      duration: result.duration,\n    };\n  }\n\n  getUiPriceByTime(timePoint0: BN, timePoint1: BN): TwapResult<Decimal> | null {\n    const result = this.getPriceByTime(timePoint0, timePoint1);\n\n    if (result === null) {\n      return null;\n    }\n\n    const uiMultiplier = new Decimal(10).pow(\n      this.baseTokenDecimals - this.quoteTokenDecimals,\n    );\n    const quoteAdjustment = new Decimal(10).pow(this.quoteTokenDecimals);\n\n    return {\n      value: result.value\n        .mul(uiMultiplier)\n        .mul(quoteAdjustment)\n        .floor()\n        .div(quoteAdjustment),\n      duration: result.duration,\n    };\n  }\n\n  getMaxDuration(currentTimestamp: BN): BN {\n    const earliestTimestamp = this.getEarliestTimestamp();\n\n    if (earliestTimestamp === null) {\n      return new BN(0);\n    }\n\n    if (currentTimestamp.lte(earliestTimestamp)) {\n      return new BN(0);\n    }\n\n    return currentTimestamp.sub(earliestTimestamp);\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/positions/index.ts",
    "content": "import { AccountMeta, Connection, PublicKey } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport { binIdToBinArrayIndex } from \"../binArray\";\nimport { deriveBinArray } from \"../derive\";\nimport {\n  ExtendedPositionBinData,\n  LbPosition,\n  POSITION_BIN_DATA_SIZE,\n  POSITION_MIN_SIZE,\n  PositionData,\n  PositionV2,\n} from \"../../types\";\nimport { DEFAULT_BIN_PER_POSITION, POSITION_MAX_LENGTH } from \"../../constants\";\nimport { Program } from \"@coral-xyz/anchor\";\nimport { LbClmm } from \"../../idl/idl\";\n\nexport * from \"./wrapper\";\n\nexport function getBinArrayIndexesCoverage(lowerBinId: BN, upperBinId: BN) {\n  const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);\n  const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);\n\n  const binArrayIndexes: BN[] = [];\n\n  for (\n    let i = lowerBinArrayIndex.toNumber();\n    i <= upperBinArrayIndex.toNumber();\n    i++\n  ) {\n    binArrayIndexes.push(new BN(i));\n  }\n\n  return binArrayIndexes;\n}\n\nexport function getBinArrayKeysCoverage(\n  lowerBinId: BN,\n  upperBinId: BN,\n  lbPair: PublicKey,\n  programId: PublicKey\n) {\n  const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);\n\n  return binArrayIndexes.map((index) => {\n    return deriveBinArray(lbPair, index, programId)[0];\n  });\n}\n\nexport function getBinArrayAccountMetasCoverage(\n  lowerBinId: BN,\n  upperBinId: BN,\n  lbPair: PublicKey,\n  programId: PublicKey\n): AccountMeta[] {\n  return getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId).map(\n    (key) => {\n      return {\n        pubkey: key,\n        isSigner: false,\n        isWritable: true,\n      };\n    }\n  );\n}\n\nexport function getPositionLowerUpperBinIdWithLiquidity(\n  position: PositionData\n): { lowerBinId: BN; upperBinId: BN } | null {\n  const binWithLiquidity = position.positionBinData.filter(\n    (b) =>\n      !new BN(b.binLiquidity).isZero() ||\n      !new BN(b.positionFeeXAmount.toString()).isZero() ||\n      !new BN(b.positionFeeYAmount.toString()).isZero() ||\n      !new BN(b.positionRewardAmount[0].toString()).isZero() ||\n      !new BN(b.positionRewardAmount[1].toString()).isZero()\n  );\n\n  return binWithLiquidity.length > 0\n    ? {\n        lowerBinId: new BN(binWithLiquidity[0].binId),\n        upperBinId: new BN(binWithLiquidity[binWithLiquidity.length - 1].binId),\n      }\n    : null;\n}\n\nexport function isPositionNoFee(position: PositionData): boolean {\n  return position.feeX.isZero() && position.feeY.isZero();\n}\n\nexport function isPositionNoReward(position: PositionData): boolean {\n  return position.rewardOne.isZero() && position.rewardTwo.isZero();\n}\n\n/**\n * Divides a range of bin IDs into chunks, each with a maximum length defined by POSITION_MAX_LENGTH,\n * and returns an array of objects representing the lower and upper bin IDs for each chunk.\n *\n * @param {number} minBinId - The starting bin ID of the range.\n * @param {number} maxBinId - The ending bin ID of the range.\n * @returns {{ lowerBinId: number; upperBinId: number }[]} An array of objects, each containing a\n *   'lowerBinId' and 'upperBinId', representing the range of bin IDs in each chunk.\n */\n\nexport function chunkBinRangeIntoExtendedPositions(\n  minBinId: number,\n  maxBinId: number\n): { lowerBinId: number; upperBinId: number }[] {\n  const chunkedBinRange = [];\n\n  for (\n    let currentMinBinId = minBinId;\n    currentMinBinId <= maxBinId;\n    currentMinBinId += POSITION_MAX_LENGTH.toNumber()\n  ) {\n    const currentMaxBinId = Math.min(\n      currentMinBinId + POSITION_MAX_LENGTH.toNumber() - 1,\n      maxBinId\n    );\n\n    chunkedBinRange.push({\n      lowerBinId: currentMinBinId,\n      upperBinId: currentMaxBinId,\n    });\n  }\n\n  return chunkedBinRange;\n}\n\n/**\n * Divides a range of bin IDs into chunks, each with a length defined by DEFAULT_BIN_PER_POSITION,\n * and returns an array of objects representing the lower and upper bin IDs for each chunk.\n * Mainly used for chunking bin range to execute multiple add/remove liquidity, claim fee/reward\n *\n * @param {number} minBinId - The starting bin ID of the range.\n * @param {number} maxBinId - The ending bin ID of the range.\n * @returns {{ lowerBinId: number; upperBinId: number }[]} An array of objects, each containing a\n *   'lowerBinId' and 'upperBinId', representing the range of bin IDs in each chunk.\n */\nexport function chunkBinRange(\n  minBinId: number,\n  maxBinId: number\n): { lowerBinId: number; upperBinId: number }[] {\n  const chunkedBinRange = [];\n  let startBinId = minBinId;\n\n  while (startBinId <= maxBinId) {\n    const endBinId = Math.min(\n      startBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1,\n      maxBinId\n    );\n\n    chunkedBinRange.push({\n      lowerBinId: startBinId,\n      upperBinId: endBinId,\n    });\n\n    startBinId += DEFAULT_BIN_PER_POSITION.toNumber();\n  }\n\n  return chunkedBinRange;\n}\n\nexport function chunkPositionBinRange(\n  position: LbPosition,\n  minBinId: number,\n  maxBinId: number\n) {\n  const chunkedFeesAndRewards: {\n    minBinId: number;\n    maxBinId: number;\n    amountX: BN;\n    amountY: BN;\n    feeXAmount: BN;\n    feeYAmount: BN;\n    rewardAmounts: BN[];\n  }[] = [];\n\n  let totalAmountX = new BN(0);\n  let totalAmountY = new BN(0);\n  let totalFeeXAmount = new BN(0);\n  let totalFeeYAmount = new BN(0);\n  let totalRewardAmounts = [new BN(0), new BN(0)];\n  let count = 0;\n\n  for (let i = 0; i < position.positionData.positionBinData.length; i++) {\n    const positionBinData = position.positionData.positionBinData[i];\n\n    if (\n      positionBinData.binId >= minBinId &&\n      positionBinData.binId <= maxBinId\n    ) {\n      totalFeeXAmount = totalFeeXAmount.add(\n        new BN(positionBinData.positionFeeXAmount)\n      );\n      totalFeeYAmount = totalFeeYAmount.add(\n        new BN(positionBinData.positionFeeYAmount)\n      );\n      totalAmountX = totalAmountX.add(new BN(positionBinData.positionXAmount));\n      totalAmountY = totalAmountY.add(new BN(positionBinData.positionYAmount));\n\n      for (const [\n        index,\n        reward,\n      ] of positionBinData.positionRewardAmount.entries()) {\n        totalRewardAmounts[index] = totalRewardAmounts[index].add(\n          new BN(reward)\n        );\n      }\n\n      count++;\n    }\n\n    if (\n      count === DEFAULT_BIN_PER_POSITION.toNumber() ||\n      positionBinData.binId == maxBinId\n    ) {\n      chunkedFeesAndRewards.push({\n        minBinId: positionBinData.binId - count + 1,\n        maxBinId: positionBinData.binId,\n        feeXAmount: totalFeeXAmount,\n        feeYAmount: totalFeeYAmount,\n        rewardAmounts: totalRewardAmounts,\n        amountX: totalAmountX,\n        amountY: totalAmountY,\n      });\n\n      totalFeeXAmount = new BN(0);\n      totalFeeYAmount = new BN(0);\n      totalAmountX = new BN(0);\n      totalAmountY = new BN(0);\n      totalRewardAmounts = [new BN(0), new BN(0)];\n\n      count = 0;\n    }\n  }\n\n  return chunkedFeesAndRewards;\n}\n\nexport function calculatePositionSize(binCount: BN) {\n  const extraBinCount = binCount.gt(DEFAULT_BIN_PER_POSITION)\n    ? binCount.sub(DEFAULT_BIN_PER_POSITION)\n    : new BN(0);\n  return new BN(POSITION_MIN_SIZE).add(\n    extraBinCount.mul(new BN(POSITION_BIN_DATA_SIZE))\n  );\n}\n\n/**\n * Get the minimum balance required to pay for the rent exemption of a\n * position with the given bin count.\n *\n * @param connection The connection to the Solana RPC node.\n * @param binCount The number of bins in the position.\n * @returns The minimum balance required to pay for the rent exemption.\n */\nexport function getPositionRentExemption(connection: Connection, binCount: BN) {\n  const size = calculatePositionSize(binCount);\n  return connection.getMinimumBalanceForRentExemption(size.toNumber());\n}\n\n/**\n * Calculate the minimum lamports required to expand a position to a given\n * width.\n *\n * The function takes into account the current width of the position and the\n * width to expand to. If the expanded width is less than or equal to the\n * default bin count per position, the function returns 0.\n *\n * @param currentMinBinId The current minimum bin ID of the position.\n * @param currentMaxBinId The current maximum bin ID of the position.\n * @param connection The connection to the Solana RPC node.\n * @param binCountToExpand The number of bins to expand the position by.\n * @returns The minimum lamports required to expand the position to the given\n * width.\n */\nexport async function getPositionExpandRentExemption(\n  currentMinBinId: BN,\n  currentMaxBinId: BN,\n  connection: Connection,\n  binCountToExpand: BN\n) {\n  const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);\n  const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);\n  if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {\n    return 0;\n  } else {\n    const binCountInExpandedBytes = positionWidthAfterExpand.sub(\n      DEFAULT_BIN_PER_POSITION\n    );\n    const expandSize =\n      binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;\n    const [minimumLamports, rentExemptionLamports] = await Promise.all([\n      connection.getMinimumBalanceForRentExemption(0),\n      connection.getMinimumBalanceForRentExemption(expandSize),\n    ]);\n\n    return rentExemptionLamports - minimumLamports;\n  }\n}\n\n/**\n * Calculate the number of extended bins in a position.\n *\n * @param minBinId The minimum bin ID of the position.\n * @param maxBinId The maximum bin ID of the position.\n * @returns The number of extended bins in the position. If the position width is\n * less than or equal to the default bin count per position, returns 0.\n */\nexport function getExtendedPositionBinCount(minBinId: BN, maxBinId: BN) {\n  const width = maxBinId.sub(minBinId).addn(1);\n  const extended = width.sub(DEFAULT_BIN_PER_POSITION);\n\n  return extended.lte(new BN(0)) ? new BN(0) : extended;\n}\n\n/**\n * Decode the extended position data.\n *\n * @param base The base position with the base data.\n * @param program The program that the position is associated with.\n * @param bytes The buffer of bytes to decode.\n * @returns The decoded extended position data.\n */\nexport function decodeExtendedPosition(\n  base: PositionV2,\n  program: Program<LbClmm>,\n  bytes: Buffer\n): ExtendedPositionBinData[] {\n  const width = base.upperBinId - base.lowerBinId + 1;\n  const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();\n\n  const extendedPosition: ExtendedPositionBinData[] = [];\n\n  for (let i = 0; i < extendedWidth; i++) {\n    const offset = i * POSITION_BIN_DATA_SIZE;\n    const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);\n    const decodedPositionBinData = program.coder.types.decode(\n      // TODO: Find a type safe way\n      \"positionBinData\",\n      data\n    ) as ExtendedPositionBinData;\n    extendedPosition.push(decodedPositionBinData);\n  }\n\n  return extendedPosition;\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/positions/wrapper.ts",
    "content": "import BN from \"bn.js\";\nimport {\n  ExtendedPositionBinData,\n  POSITION_MIN_SIZE,\n  PositionV2,\n  PositionVersion,\n  UserFeeInfo,\n  UserRewardInfo,\n} from \"../../types\";\nimport { AccountInfo, PublicKey } from \"@solana/web3.js\";\nimport { Program } from \"@coral-xyz/anchor\";\nimport { LbClmm } from \"../../idl/idl\";\nimport { decodeExtendedPosition, getBinArrayIndexesCoverage } from \".\";\nimport { binIdToBinArrayIndex } from \"../binArray\";\nimport { deriveBinArray } from \"../derive\";\nimport { decodeAccount, getAccountDiscriminator } from \"..\";\n\nexport interface IPosition {\n  address(): PublicKey;\n  lowerBinId(): BN;\n  upperBinId(): BN;\n  liquidityShares(): BN[];\n  rewardInfos(): UserRewardInfo[];\n  feeInfos(): UserFeeInfo[];\n  lastUpdatedAt(): BN;\n  lbPair(): PublicKey;\n  totalClaimedFeeXAmount(): BN;\n  totalClaimedFeeYAmount(): BN;\n  totalClaimedRewards(): BN[];\n  operator(): PublicKey;\n  lockReleasePoint(): BN;\n  feeOwner(): PublicKey;\n  owner(): PublicKey;\n  getBinArrayIndexesCoverage(): BN[];\n  getBinArrayKeysCoverage(programId: PublicKey): PublicKey[];\n  version(): PositionVersion;\n  width(): BN;\n}\n\ninterface CombinedPositionBinData {\n  liquidityShares: BN[];\n  rewardInfos: UserRewardInfo[];\n  feeInfos: UserFeeInfo[];\n}\n\nfunction combineBaseAndExtendedPositionBinData(\n  base: PositionV2,\n  extended: ExtendedPositionBinData[]\n): CombinedPositionBinData {\n  const combinedLiquidityShares = base.liquidityShares;\n  const combinedRewardInfos = base.rewardInfos;\n  const combinedFeeInfos = base.feeInfos;\n\n  for (const binData of extended) {\n    combinedLiquidityShares.push(binData.liquidityShare);\n    combinedRewardInfos.push(binData.rewardInfo);\n    combinedFeeInfos.push(binData.feeInfo);\n  }\n\n  return {\n    liquidityShares: combinedLiquidityShares,\n    rewardInfos: combinedRewardInfos,\n    feeInfos: combinedFeeInfos,\n  };\n}\n\nexport function wrapPosition(\n  program: Program<LbClmm>,\n  key: PublicKey,\n  account: AccountInfo<Buffer>\n): IPosition {\n  const disc = account.data.subarray(0, 8);\n  if (disc.equals(Buffer.from(getAccountDiscriminator(\"positionV2\")))) {\n    const state = decodeAccount<PositionV2>(\n      program,\n      \"positionV2\",\n      account.data\n    );\n\n    const extended = decodeExtendedPosition(\n      state,\n      program,\n      account.data.subarray(8 + POSITION_MIN_SIZE)\n    );\n\n    const combinedPositionBinData = combineBaseAndExtendedPositionBinData(\n      state,\n      extended\n    );\n\n    return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);\n  } else {\n    throw new Error(\"Unknown position account\");\n  }\n}\n\nexport class PositionV2Wrapper implements IPosition {\n  constructor(\n    public positionAddress: PublicKey,\n    public inner: PositionV2,\n    public extended: ExtendedPositionBinData[],\n    public combinedPositionBinData: CombinedPositionBinData\n  ) {}\n\n  address(): PublicKey {\n    return this.positionAddress;\n  }\n\n  totalClaimedRewards(): BN[] {\n    return this.inner.totalClaimedRewards;\n  }\n\n  feeOwner(): PublicKey {\n    return this.inner.feeOwner;\n  }\n\n  lockReleasePoint(): BN {\n    return this.inner.lockReleasePoint;\n  }\n\n  operator(): PublicKey {\n    return this.inner.operator;\n  }\n\n  totalClaimedFeeYAmount(): BN {\n    return this.inner.totalClaimedFeeYAmount;\n  }\n\n  totalClaimedFeeXAmount(): BN {\n    return this.inner.totalClaimedFeeXAmount;\n  }\n\n  lbPair(): PublicKey {\n    return this.inner.lbPair;\n  }\n\n  lowerBinId(): BN {\n    return new BN(this.inner.lowerBinId);\n  }\n\n  upperBinId(): BN {\n    return new BN(this.inner.upperBinId);\n  }\n\n  liquidityShares(): BN[] {\n    return this.combinedPositionBinData.liquidityShares;\n  }\n\n  rewardInfos(): UserRewardInfo[] {\n    return this.combinedPositionBinData.rewardInfos;\n  }\n\n  feeInfos(): UserFeeInfo[] {\n    return this.combinedPositionBinData.feeInfos;\n  }\n\n  lastUpdatedAt(): BN {\n    return this.inner.lastUpdatedAt;\n  }\n\n  getBinArrayIndexesCoverage(): BN[] {\n    const isExtended = this.extended.length > 0;\n    if (isExtended) {\n      return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());\n    } else {\n      const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());\n      const upperBinArrayIndex = lowerBinArrayIndex.add(new BN(1));\n      return [lowerBinArrayIndex, upperBinArrayIndex];\n    }\n  }\n\n  getBinArrayKeysCoverage(programId: PublicKey): PublicKey[] {\n    return this.getBinArrayIndexesCoverage().map(\n      (index) => deriveBinArray(this.lbPair(), index, programId)[0]\n    );\n  }\n\n  version(): PositionVersion {\n    return PositionVersion.V2;\n  }\n\n  owner(): PublicKey {\n    return this.inner.owner;\n  }\n\n  width(): BN {\n    return this.upperBinId().sub(this.lowerBinId()).add(new BN(1));\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/index.ts",
    "content": "export * from \"./rebalancePosition\";\nexport * from \"./liquidity_strategy\";\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/liquidity_strategy/bidAsk.ts",
    "content": "import BN from \"bn.js\";\nimport { BidAskParameters, LiquidityStrategyParameterBuilder } from \".\";\nimport { SCALE_OFFSET } from \"../../../constants\";\nimport { getQPriceFromId } from \"../../math\";\nimport {\n  getAmountInBinsAskSide,\n  getAmountInBinsBidSide,\n  toAmountIntoBins,\n} from \"../rebalancePosition\";\n\nfunction findMinY0(amountY: BN, minDeltaId: BN, maxDeltaId: BN) {\n  const binCount = maxDeltaId.sub(minDeltaId).addn(1);\n  const totalWeight = binCount.mul(binCount.addn(1)).divn(2);\n  return amountY.div(totalWeight);\n}\n\nfunction findBaseDeltaY(amountY: BN, minDeltaId: BN, maxDeltaId: BN) {\n  // min_delta_id = -m1, max_delta_id = -m2\n  //\n  // active_id - m2 = y0 + delta_y * m2\n  // active_id - (m2 + 1) = y0 + delta_y * (m2-1)\n  // ...\n  // active_id - m1 = y0 + delta_y * m1\n  //\n  // sum(amounts) = y0 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n  // ** default formula is, set y0 = -delta_y * m2, but we don't want last bin amount is 0\n  // set y0 = -delta_y * (m2 - 1)\n  // sum(amounts) = -delta_y * (m2 - 1) * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n  // A = (-m2 + 1) * (m1-m2+1) + (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n  // delta_y = sum(amounts) / A\n  if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN(0))) {\n    return new BN(0);\n  }\n  if (minDeltaId.eq(maxDeltaId)) {\n    return amountY;\n  }\n  const m1 = minDeltaId.neg();\n  const m2 = maxDeltaId.neg();\n  // A = b + (c - d)\n  // b = (-m2 + 1) * (m1-m2+1)\n  // c = m1 * (m1+1)/2\n  // d =  m2 * (m2-1)/2\n  const b = m2.neg().addn(1).mul(m1.sub(m2).addn(1));\n  const c = m1.mul(m1.addn(1)).divn(2);\n  const d = m2.mul(m2.subn(1)).divn(2);\n  const a = b.add(c.sub(d));\n  return amountY.div(a);\n}\n\nfunction findY0AndDeltaY(\n  amountY: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  activeId: BN\n): BidAskParameters {\n  if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n    };\n  }\n\n  let baseDeltaY = findBaseDeltaY(amountY, minDeltaId, maxDeltaId);\n  const y0 = baseDeltaY.neg().mul(maxDeltaId.neg().subn(1));\n\n  while (true) {\n    const amountInBins = getAmountInBinsBidSide(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      baseDeltaY,\n      y0\n    );\n\n    const totalAmountY = amountInBins.reduce((acc, { amountY }) => {\n      return acc.add(amountY);\n    }, new BN(0));\n\n    if (totalAmountY.gt(amountY)) {\n      baseDeltaY = baseDeltaY.sub(new BN(1));\n    } else {\n      return {\n        base: y0,\n        delta: baseDeltaY,\n      };\n    }\n  }\n}\n\nfunction findMinX0(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  activeId: BN,\n  binStep: BN\n) {\n  const minBinId = activeId.add(minDeltaId);\n  const maxBinId = activeId.add(maxDeltaId);\n\n  let totalWeight = new BN(0);\n\n  for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {\n    const binDelta = binId - minBinId.toNumber() + 1;\n    const binPrice = getQPriceFromId(new BN(binId), binStep);\n    const weight = new BN(binDelta).mul(binPrice);\n    totalWeight = totalWeight.add(weight);\n  }\n\n  return amountX.shln(SCALE_OFFSET).div(totalWeight);\n}\n\nfunction findBaseDeltaX(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN(0))) {\n    return new BN(0);\n  }\n\n  // min_delta_id = m1, max_delta_id = m2\n  // pm = (1+b)^-(active_id + m)\n  //\n  // active_id + m1 = (x0 + m1 * delta_x) * p(m1)\n  // active_id + m1 + 1 = (x0 + (m1 + 1) * delta_x) * p(m1+1)\n  // ...\n  // active_id + m2 =  (x0 + m2 * delta_x) * p(m2)\n  //\n  // sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n  // set x0 = -m1 * delta_x\n\n  // sum(amounts) = -m1 * delta_x * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n  // A = -m1 * (p(m1)+..+p(m2)) + (m1 * p(m1) + ... + m2 * p(m2))\n  // B = m1 * (p(m1)+..+p(m2))\n  // C = (m1 * p(m1) + ... + m2 * p(m2))\n  // delta_x = sum(amounts) / (C-B)\n  let b = new BN(0);\n  let c = new BN(0);\n  let m1 = minDeltaId;\n  // +1 ensure no 0 amount in active id\n  let m2 = maxDeltaId.addn(1);\n\n  for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {\n    const binId = activeId.addn(m);\n    const pm = getQPriceFromId(binId.neg(), binStep);\n\n    const bDelta = m1.mul(pm);\n    b = b.add(bDelta);\n\n    const cDelta = new BN(m).mul(pm);\n    c = c.add(cDelta);\n  }\n\n  return amountX.shln(SCALE_OFFSET).div(c.sub(b));\n}\n\nfunction findX0AndDeltaX(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN(0)) || amountX.isZero()) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n    };\n  }\n\n  let baseDeltaX = findBaseDeltaX(\n    amountX,\n    minDeltaId,\n    maxDeltaId,\n    binStep,\n    activeId\n  );\n\n  const x0 = minDeltaId.neg().mul(baseDeltaX).add(baseDeltaX);\n\n  while (true) {\n    const amountInBins = getAmountInBinsAskSide(\n      activeId,\n      binStep,\n      minDeltaId,\n      maxDeltaId,\n      baseDeltaX,\n      x0\n    );\n\n    const totalAmountX = amountInBins.reduce((acc, { amountX }) => {\n      return acc.add(amountX);\n    }, new BN(0));\n\n    if (totalAmountX.gt(amountX)) {\n      baseDeltaX = baseDeltaX.sub(new BN(1));\n    } else {\n      return {\n        base: x0,\n        delta: baseDeltaX,\n      };\n    }\n  }\n}\n\nexport class BidAskStrategyParameterBuilder\n  implements LiquidityStrategyParameterBuilder\n{\n  findXParameters(\n    amountX: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    binStep: BN,\n    activeId: BN\n  ): BidAskParameters {\n    return findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId);\n  }\n\n  findYParameters(\n    amountY: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    activeId: BN\n  ): BidAskParameters {\n    return findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId);\n  }\n\n  suggestBalancedXParametersFromY(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountY: BN\n  ): BidAskParameters & { amountX: BN } {\n    // sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n    // default formula is, set x0 = -m1 * delta_x\n    // set x0 = -m1 * delta_x + e where e = delta_x\n    // Total quote = delta_x * (1 + 2 + ... + max_delta_id)\n    // delta_x = total_quote / (1 + 2 + ... + max_delta_id)\n\n    const deltaX = amountY.div(\n      maxDeltaId.addn(1).mul(maxDeltaId.addn(2)).divn(2)\n    );\n\n    const x0 = minDeltaId.neg().mul(deltaX).add(deltaX);\n\n    const totalAmountX = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      deltaX,\n      new BN(0),\n      x0,\n      new BN(0),\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountX);\n    }, new BN(0));\n\n    return {\n      base: x0,\n      delta: deltaX,\n      amountX: totalAmountX,\n    };\n  }\n\n  suggestBalancedYParametersFromX(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountXInQuoteValue: BN\n  ): BidAskParameters & { amountY: BN } {\n    // set y0 = -delta_y * m2\n    // sum(amounts) = -delta_y * m2 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n    // A = -m2 * (m1-m2+1) + (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n    // delta_y = sum(amounts) / A\n\n    // Total quote = sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n    // delta_y = sum(amounts) / A\n\n    // extra sub 1 to ensure no zero amount\n    const m1 = minDeltaId.neg().subn(1);\n    const m2 = maxDeltaId.neg();\n\n    const a1 = m2.neg().mul(m1.sub(m2).addn(1));\n    const a2 = m1.mul(m1.addn(1)).divn(2);\n    const a3 = m2.mul(m2.subn(1)).divn(2);\n\n    const a = a1.add(a2.sub(a3));\n\n    const deltaY = amountXInQuoteValue.div(a);\n    const y0 = deltaY.neg().mul(m2).add(deltaY); // add the subtracted deltaY back to y0\n\n    const amountY = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      new BN(0),\n      deltaY,\n      new BN(0),\n      y0,\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountY);\n    }, new BN(0));\n\n    return {\n      base: y0,\n      delta: deltaY,\n      amountY,\n    };\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/liquidity_strategy/curve.ts",
    "content": "import BN from \"bn.js\";\nimport { BidAskParameters, LiquidityStrategyParameterBuilder } from \".\";\nimport { SCALE_OFFSET } from \"../../../constants\";\nimport { getQPriceBaseFactor, getQPriceFromId } from \"../../math\";\nimport {\n  getAmountInBinsAskSide,\n  getAmountInBinsBidSide,\n  toAmountIntoBins,\n} from \"../rebalancePosition\";\nimport { getPriceOfBinByBinId } from \"../../weight\";\nimport Decimal from \"decimal.js\";\n\nfunction findBaseY0(amountY: BN, minDeltaId: BN, maxDeltaId: BN) {\n  // min_delta_id = -m1, max_delta_id = -m2\n  //\n  // active_id - m2 = y0 + delta_y * m2\n  // active_id - (m2 + 1) = y0 + delta_y * (m2-1)\n  // ...\n  // active_id - m1 = y0 + delta_y * m1\n  //\n  // sum(amounts) = y0 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n  // set delta_y = -y0 / m1\n  // sum(amounts) = y0 * (m1-m2+1) - y0 * (m1 * (m1+1)/2 - m2 * (m2-1)/2) / m1\n  // A = (m1-m2+1) - (m1 * (m1+1)/2 - m2 * (m2-1)/2) / m1\n  // y0 = sum(amounts) / A\n  if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN(0))) {\n    return new BN(0);\n  }\n\n  if (minDeltaId.eq(maxDeltaId)) {\n    return amountY;\n  }\n\n  const m1 = minDeltaId.neg();\n  const m2 = maxDeltaId.neg();\n\n  // A = b - (c - d) / m1\n  // b = (m1-m2+1)\n  // c = m1 * (m1+1)/2\n  // d =  m2 * (m2-1)/2\n\n  // seems like if we set delta_y = -y0 / (m1 + 1) the amount will be closer to desired amount\n  const b = m1.sub(m2).addn(1);\n  const c = m1.mul(m1.addn(1)).divn(2);\n  const d = m2.mul(m2.subn(1)).divn(2);\n\n  const a = b.sub(c.sub(d).div(m1.addn(1)));\n  return amountY.div(a);\n}\n\nfunction findY0AndDeltaY(\n  amountY: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  activeId: BN\n): BidAskParameters {\n  if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n    };\n  }\n\n  let baseY0 = findBaseY0(amountY, minDeltaId, maxDeltaId);\n\n  while (true) {\n    const deltaY = baseY0.neg().div(minDeltaId.neg().addn(1));\n\n    const amountInBins = getAmountInBinsBidSide(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      deltaY,\n      baseY0\n    );\n\n    const totalAmountY = amountInBins.reduce((acc, { amountY }) => {\n      return acc.add(amountY);\n    }, new BN(0));\n\n    if (totalAmountY.gt(amountY)) {\n      baseY0 = baseY0.sub(new BN(1));\n    } else {\n      return {\n        base: baseY0,\n        delta: deltaY,\n      };\n    }\n  }\n}\n\nfunction findBaseX0(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN(0))) {\n    return new BN(0);\n  }\n\n  // min_delta_id = m1, max_delta_id = m2\n  // pm = (1+b)^-(active_id + m)\n  //\n  // active_id + m1 = (x0 + m1 * delta_x) * p(m1)\n  // active_id + m1 + 1 = (x0 + (m1 + 1) * delta_x) * p(m1+1)\n  // ...\n  // active_id + m2 =  (x0 + m2 * delta_x) * p(m2)\n  //\n  // sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n  // set delta_x = -x0 / m2\n\n  // sum(amounts) = x0 * (p(m1)+..+p(m2)) - x0 * (m1 * p(m1) + ... + m2 * p(m2)) / m2\n  // A = (p(m1)+..+p(m2)) - (m1 * p(m1) + ... + m2 * p(m2)) / m2\n  // B = (p(m1)+..+p(m2))\n  // C = (m1 * p(m1) + ... + m2 * p(m2)) / m2\n  // x0 = sum(amounts) / (B-C)\n\n  let b = new BN(0);\n  let c = new BN(0);\n  let m1 = minDeltaId;\n  let m2 = maxDeltaId;\n\n  for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {\n    const binId = activeId.addn(m);\n\n    const pm = getQPriceFromId(binId.neg(), binStep);\n    b = b.add(pm);\n\n    const cDelta = new BN(m).mul(pm).div(m2);\n    c = c.add(cDelta);\n  }\n\n  return amountX.shln(SCALE_OFFSET).div(b.sub(c));\n}\n\nfunction findX0AndDeltaX(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN(0)) || amountX.isZero()) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n    };\n  }\n\n  let baseX0 = findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId);\n  const deltaX = baseX0.neg().div(maxDeltaId);\n\n  while (true) {\n    const amountInBins = getAmountInBinsAskSide(\n      activeId,\n      binStep,\n      minDeltaId,\n      maxDeltaId,\n      deltaX,\n      baseX0\n    );\n\n    const totalAmountX = amountInBins.reduce((acc, { amountX }) => {\n      return acc.add(amountX);\n    }, new BN(0));\n\n    if (totalAmountX.gt(amountX)) {\n      baseX0 = baseX0.sub(new BN(1));\n    } else {\n      return {\n        base: baseX0,\n        delta: deltaX,\n      };\n    }\n  }\n}\n\nexport class CurveStrategyParameterBuilder\n  implements LiquidityStrategyParameterBuilder\n{\n  findXParameters(\n    amountX: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    binStep: BN,\n    activeId: BN\n  ): BidAskParameters {\n    return findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId);\n  }\n\n  findYParameters(\n    amountY: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    activeId: BN\n  ): BidAskParameters {\n    return findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId);\n  }\n\n  suggestBalancedXParametersFromY(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountY: BN\n  ): BidAskParameters & { amountX: BN } {\n    // p(m) = (1+b)^-(active_id + m)\n    // active_id = x0 * p(0)\n    // active_id + 1= (x0 + delta_x) * p(1)\n    // ...\n    // active_id + max_delta_id =  (x0 + max_delta_id * delta_x) * p(max_delta_id)\n    // Total quote = x0 + (x0 + delta_x) + ... + (x0 + max_delta_id * delta_x)\n    // = x0 * (max_delta_id + 1) + delta_x * (1+2+...+max_delta_id)\n    //\n    // set delta_x = -x0 / max_delta_id\n    // Total quote  = x0 * (max_delta_id + 1) - x0 * (1+2+...+max_delta_id) / max_delta_id = x0 * (max_delta_id + 1) / 2\n    // x0 = total_amount_y * 2 / (max_delta_id + 1)\n\n    const x0 = amountY.muln(2).div(maxDeltaId.addn(1));\n    const deltaX = x0.neg().div(maxDeltaId);\n\n    const totalAmountX = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      deltaX,\n      new BN(0),\n      x0,\n      new BN(0),\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountX);\n    }, new BN(0));\n\n    return {\n      base: x0,\n      delta: deltaX,\n      amountX: totalAmountX,\n    };\n  }\n\n  suggestBalancedYParametersFromX(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountXInQuoteValue: BN\n  ): BidAskParameters & { amountY: BN } {\n    // sum(amounts) = y0 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n    // set delta_y = -y0 / m1\n    // sum(amounts) = y0 * (m1-m2+1) - y0 * (m1 * (m1+1)/2 - m2 * (m2-1)/2) / m1\n    // A = (m1-m2+1) - (m1 * (m1+1)/2 - m2 * (m2-1)/2) / m1\n    // y0 = sum(amounts) / A\n    //\n    // pm = (1+b)(active_id + m)\n    //\n    // Total quote = sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n    // y0 = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2)) / A\n\n    const m1 = minDeltaId.neg();\n    const m2 = maxDeltaId.neg();\n\n    const a1 = m1.sub(m2).addn(1);\n    const a2 = m1.mul(m1.addn(1)).divn(2);\n    const a3 = m2.mul(m2.subn(1)).divn(2);\n\n    const a = m1.sub(a3.sub(a2)).div(m1);\n\n    const y0 = amountXInQuoteValue.div(a);\n    const deltaY = y0.neg().div(m1);\n\n    const amountY = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      new BN(0),\n      deltaY,\n      new BN(0),\n      y0,\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountY);\n    }, new BN(0));\n\n    return {\n      base: y0,\n      delta: deltaY,\n      amountY,\n    };\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/liquidity_strategy/index.ts",
    "content": "import BN from \"bn.js\";\nimport { StrategyType } from \"../../../types\";\nimport { BidAskStrategyParameterBuilder } from \"./bidAsk\";\nimport { CurveStrategyParameterBuilder } from \"./curve\";\nimport { SpotStrategyParameterBuilder } from \"./spot\";\nimport { RebalancePosition, toAmountIntoBins } from \"../rebalancePosition\";\nimport { getPriceOfBinByBinId } from \"../../weight\";\nimport Decimal from \"decimal.js\";\n\nexport interface LiquidityStrategyParameters {\n  x0: BN;\n  y0: BN;\n  deltaX: BN;\n  deltaY: BN;\n}\n\nexport interface BidAskParameters {\n  base: BN;\n  delta: BN;\n}\n\nexport interface LiquidityStrategyParameterBuilder {\n  findXParameters(\n    amountX: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    binStep: BN,\n    activeId: BN\n  ): BidAskParameters;\n  findYParameters(\n    amountY: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    activeId: BN\n  ): BidAskParameters;\n  suggestBalancedXParametersFromY(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountY: BN\n  ): BidAskParameters & { amountX: BN };\n  suggestBalancedYParametersFromX(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountXInQuoteValue: BN\n  ): BidAskParameters & { amountY: BN };\n}\n\nexport function getLiquidityStrategyParameterBuilder(\n  strategyType: StrategyType\n): LiquidityStrategyParameterBuilder {\n  switch (strategyType) {\n    case StrategyType.Spot:\n      return new SpotStrategyParameterBuilder();\n    case StrategyType.Curve:\n      return new CurveStrategyParameterBuilder();\n    case StrategyType.BidAsk:\n      return new BidAskStrategyParameterBuilder();\n    default:\n      throw new Error(\"Strategy not supported\");\n  }\n}\n\nexport function suggestBalancedXParametersFromY(\n  y0: BN,\n  deltaY: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  activeId: BN,\n  binStep: BN,\n  favorXInActiveBin: boolean,\n  builder: LiquidityStrategyParameterBuilder\n) {\n  const endDeltaIdBidSide = favorXInActiveBin ? new BN(-1) : new BN(0);\n\n  if (maxDeltaId.lte(endDeltaIdBidSide)) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n      amountX: new BN(0),\n    };\n  }\n\n  const minYDeltaId = minDeltaId;\n  const maxYDeltaId = endDeltaIdBidSide;\n\n  const totalAmountY = toAmountIntoBins(\n    activeId,\n    minYDeltaId,\n    maxYDeltaId,\n    new BN(0),\n    deltaY,\n    new BN(0),\n    y0,\n    binStep,\n    favorXInActiveBin\n  ).reduce((acc, bin) => {\n    return acc.add(bin.amountY);\n  }, new BN(0));\n\n  const minXDeltaId = maxYDeltaId.addn(1);\n  const maxXDeltaId = maxDeltaId;\n\n  return builder.suggestBalancedXParametersFromY(\n    activeId,\n    binStep,\n    favorXInActiveBin,\n    minXDeltaId,\n    maxXDeltaId,\n    totalAmountY\n  );\n}\n\nexport function getAutoFillAmountByRebalancedPosition(\n  rebalancePosition: RebalancePosition,\n  strategyType: StrategyType\n): {\n  amount: BN;\n  isBidSide: boolean;\n} {\n  let liquidityInBidSide = new BN(0);\n  let liquidityInAskSide = new BN(0);\n\n  const builder = getLiquidityStrategyParameterBuilder(strategyType);\n  const { lbPair } = rebalancePosition;\n  let favorXInActiveBin = false;\n\n  let activeIdIndex = -1;\n\n  for (const [\n    idx,\n    binData,\n  ] of rebalancePosition.rebalancePositionBinData.entries()) {\n    const liquidityBid = binData.amountY;\n    const liquidityAsk = new Decimal(binData.price)\n      .mul(new Decimal(binData.amountX.toString()))\n      .floor()\n      .toString();\n\n    liquidityInBidSide = liquidityInBidSide.add(liquidityBid);\n    liquidityInAskSide = liquidityInAskSide.add(new BN(liquidityAsk));\n\n    if (binData.binId == lbPair.activeId) {\n      favorXInActiveBin = binData.amountX.gt(binData.amountY);\n      activeIdIndex = idx;\n    }\n  }\n\n  if (liquidityInAskSide.gt(liquidityInBidSide)) {\n    const minBinId = rebalancePosition.rebalancePositionBinData[0].binId;\n    let maxBinId: number;\n\n    if (activeIdIndex == -1) {\n      maxBinId =\n        rebalancePosition.rebalancePositionBinData[\n          rebalancePosition.rebalancePositionBinData.length - 1\n        ].binId;\n    } else {\n      maxBinId =\n        rebalancePosition.rebalancePositionBinData[\n          favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex\n        ].binId;\n    }\n\n    const minDeltaId = minBinId - lbPair.activeId;\n    const maxDeltaId = maxBinId - lbPair.activeId;\n\n    const { amountY } = builder.suggestBalancedYParametersFromX(\n      new BN(lbPair.activeId),\n      new BN(lbPair.binStep),\n      favorXInActiveBin,\n      new BN(minDeltaId),\n      new BN(maxDeltaId),\n      liquidityInAskSide\n    );\n\n    const [_, positionAmountY] = rebalancePosition.totalAmounts();\n\n    return {\n      amount: BN.max(amountY.sub(positionAmountY), new BN(0)),\n      isBidSide: true,\n    };\n  } else if (liquidityInAskSide.lt(liquidityInBidSide)) {\n    const maxBinId =\n      rebalancePosition.rebalancePositionBinData[\n        rebalancePosition.rebalancePositionBinData.length - 1\n      ].binId;\n\n    let minBinId: number;\n    if (activeIdIndex == -1) {\n      minBinId = rebalancePosition.rebalancePositionBinData[0].binId;\n    } else {\n      minBinId =\n        rebalancePosition.rebalancePositionBinData[\n          favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex\n        ].binId;\n    }\n\n    const minDeltaId = minBinId - lbPair.activeId;\n    const maxDeltaId = maxBinId - lbPair.activeId;\n\n    const { amountX } = builder.suggestBalancedXParametersFromY(\n      new BN(lbPair.activeId),\n      new BN(lbPair.binStep),\n      favorXInActiveBin,\n      new BN(minDeltaId),\n      new BN(maxDeltaId),\n      liquidityInBidSide\n    );\n\n    const [positionAmountX] = rebalancePosition.totalAmounts();\n\n    return {\n      amount: BN.max(amountX.sub(positionAmountX), new BN(0)),\n      isBidSide: false,\n    };\n  } else {\n    return {\n      amount: new BN(0),\n      isBidSide: false,\n    };\n  }\n}\n\nexport function suggestBalancedYParametersFromX(\n  x0: BN,\n  deltaX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  activeId: BN,\n  binStep: BN,\n  favorXInActiveBin: boolean,\n  builder: LiquidityStrategyParameterBuilder\n) {\n  const startDeltaIdAskSide = favorXInActiveBin ? new BN(0) : new BN(1);\n\n  if (minDeltaId.gte(startDeltaIdAskSide)) {\n    return {\n      base: new BN(0),\n      delta: new BN(0),\n      amountY: new BN(0),\n    };\n  }\n\n  const minXDeltaId = startDeltaIdAskSide;\n  const maxXDeltaId = maxDeltaId;\n\n  const amountXInBins = toAmountIntoBins(\n    activeId,\n    minXDeltaId,\n    maxXDeltaId,\n    deltaX,\n    new BN(0),\n    x0,\n    new BN(0),\n    binStep,\n    favorXInActiveBin\n  );\n\n  const totalAmountXInQuote = amountXInBins.reduce((acc, bin) => {\n    const price = getPriceOfBinByBinId(\n      bin.binId.toNumber(),\n      binStep.toNumber()\n    );\n    return acc.add(price.mul(new Decimal(bin.amountX.toString())));\n  }, new Decimal(0));\n\n  const totalAmountXInQuoteBN = new BN(totalAmountXInQuote.floor().toString());\n\n  const minYDeltaId = minDeltaId;\n  const maxYDeltaId = startDeltaIdAskSide.subn(1);\n\n  return builder.suggestBalancedYParametersFromX(\n    activeId,\n    binStep,\n    favorXInActiveBin,\n    minYDeltaId,\n    maxYDeltaId,\n    totalAmountXInQuoteBN\n  );\n}\n\nexport function buildLiquidityStrategyParameters(\n  amountX: BN,\n  amountY: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  favorXInActiveId: boolean,\n  activeId: BN,\n  strategyParameterBuilder: LiquidityStrategyParameterBuilder\n): LiquidityStrategyParameters {\n  if (minDeltaId.gt(maxDeltaId)) {\n    return {\n      x0: new BN(0),\n      y0: new BN(0),\n      deltaX: new BN(0),\n      deltaY: new BN(0),\n    };\n  }\n\n  const depositOnlyY =\n    maxDeltaId.lt(new BN(0)) || (maxDeltaId.isZero() && !favorXInActiveId);\n\n  const depositOnlyX =\n    minDeltaId.gt(new BN(0)) || (minDeltaId.isZero() && favorXInActiveId);\n\n  if (depositOnlyY) {\n    const { base, delta } = strategyParameterBuilder.findYParameters(\n      amountY,\n      minDeltaId,\n      maxDeltaId,\n      activeId\n    );\n    return {\n      x0: new BN(0),\n      deltaX: new BN(0),\n      y0: base,\n      deltaY: delta,\n    };\n  }\n\n  if (depositOnlyX) {\n    const { base, delta } = strategyParameterBuilder.findXParameters(\n      amountX,\n      minDeltaId,\n      maxDeltaId,\n      binStep,\n      activeId\n    );\n    return {\n      x0: base,\n      deltaX: delta,\n      y0: new BN(0),\n      deltaY: new BN(0),\n    };\n  }\n\n  const maxDeltaIdBidSide = favorXInActiveId ? new BN(-1) : new BN(0);\n  const minDeltaIdAskSide = favorXInActiveId ? new BN(0) : new BN(1);\n\n  const { base: y0, delta: deltaY } = strategyParameterBuilder.findYParameters(\n    amountY,\n    minDeltaId,\n    maxDeltaIdBidSide,\n    activeId\n  );\n\n  const { base: x0, delta: deltaX } = strategyParameterBuilder.findXParameters(\n    amountX,\n    minDeltaIdAskSide,\n    maxDeltaId,\n    binStep,\n    activeId\n  );\n\n  return {\n    x0,\n    deltaX,\n    y0,\n    deltaY,\n  };\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/liquidity_strategy/spot.ts",
    "content": "import BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { BidAskParameters, LiquidityStrategyParameterBuilder } from \".\";\nimport { SCALE_OFFSET } from \"../../../constants\";\nimport { getQPriceBaseFactor, getQPriceFromId } from \"../../math\";\nimport { getPriceOfBinByBinId } from \"../../weight\";\nimport { getAmountInBinsAskSide, toAmountIntoBins } from \"../rebalancePosition\";\n\nfunction findY0(amountY: BN, minDeltaId: BN, maxDeltaId: BN) {\n  if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN(0)) || amountY.isZero()) {\n    return new BN(0);\n  }\n\n  // min_delta_id = -m1, max_delta_id = -m2\n  //\n  // active_id - m2 = y0 + delta_y * m2\n  // active_id - (m2 + 1) = y0 + delta_y * (m2-1)\n  // ...\n  // active_id - m1 = y0 + delta_y * m1\n  //\n  // sum(amounts) = y0 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n  // set delta_y = 0\n  // sum(amounts) = y0 * (m1-m2+1)\n  // A = (m1-m2+1)\n  // y0 = sum(amounts) / A\n\n  const m1 = minDeltaId.neg();\n  const m2 = maxDeltaId.neg();\n\n  const delta = m1.sub(m2).addn(1);\n  return amountY.div(delta);\n}\n\nfunction findBaseX0(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  // min_delta_id = m1, max_delta_id = m2\n  // pm = (1+b)^-(active_id + m)\n  //\n  // active_id + m1 = (x0 + m1 * delta_x) * p(m1)\n  // active_id + m1 + 1 = (x0 + (m1 + 1) * delta_x) * p(m1+1)\n  // ...\n  // active_id + m2 =  (x0 + m2 * delta_x) * p(m2)\n  //\n  // sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n  // set delta_x = 0\n\n  // sum(amounts) = x0 * (p(m1)+..+p(m2))\n  // B = p(m1)+..+p(m2)\n  // x0 = sum(amounts) / B\n\n  let totalWeight = new BN(0);\n\n  const minBinId = activeId.add(minDeltaId);\n  const maxBinId = activeId.add(maxDeltaId);\n\n  let baseFactor = getQPriceBaseFactor(binStep);\n  let basePrice = getQPriceFromId(maxBinId.neg(), binStep);\n\n  for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {\n    totalWeight = totalWeight.add(basePrice);\n    basePrice = basePrice.mul(baseFactor).shrn(SCALE_OFFSET);\n  }\n\n  return amountX.shln(SCALE_OFFSET).div(totalWeight);\n}\n\nfunction findX0(\n  amountX: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  binStep: BN,\n  activeId: BN\n) {\n  if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN(0)) || amountX.isZero()) {\n    return new BN(0);\n  }\n  let x0 = findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId);\n\n  while (true) {\n    const amountInBins = getAmountInBinsAskSide(\n      activeId,\n      binStep,\n      minDeltaId,\n      maxDeltaId,\n      new BN(0),\n      x0\n    );\n\n    const totalAmountX = amountInBins.reduce((acc, bin) => {\n      return acc.add(bin.amountX);\n    }, new BN(0));\n\n    if (totalAmountX.lt(amountX)) {\n      x0 = x0.add(new BN(1));\n    } else {\n      x0 = x0.sub(new BN(1));\n      return x0;\n    }\n  }\n}\n\nexport class SpotStrategyParameterBuilder\n  implements LiquidityStrategyParameterBuilder\n{\n  findXParameters(\n    amountX: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    binStep: BN,\n    activeId: BN\n  ): BidAskParameters {\n    return {\n      base: findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId),\n      delta: new BN(0),\n    };\n  }\n\n  findYParameters(\n    amountY: BN,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    _activeId: BN\n  ): BidAskParameters {\n    return {\n      base: findY0(amountY, minDeltaId, maxDeltaId),\n      delta: new BN(0),\n    };\n  }\n\n  suggestBalancedXParametersFromY(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountY: BN\n  ): BidAskParameters & { amountX: BN } {\n    // pm = (1+b)^-(active_id + m)\n    //\n    // sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n    // set delta_x = 0\n    // Total quote = x0 * (max_delta_id + 1) = total_amount_y\n    // x0 = total_amount_y / (max_delta_id + 1)\n\n    const x0 = amountY.div(maxDeltaId.addn(1));\n\n    const totalAmountX = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      new BN(0),\n      new BN(0),\n      x0,\n      new BN(0),\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountX);\n    }, new BN(0));\n\n    return {\n      base: new BN(x0.toString()),\n      delta: new BN(0),\n      amountX: totalAmountX,\n    };\n  }\n\n  suggestBalancedYParametersFromX(\n    activeId: BN,\n    binStep: BN,\n    favorXInActiveBin: boolean,\n    minDeltaId: BN,\n    maxDeltaId: BN,\n    amountXInQuoteValue: BN\n  ): BidAskParameters & { amountY: BN } {\n    // sum(amounts) = y0 * (m1-m2+1) + delta_y * (m1 * (m1+1)/2 - m2 * (m2-1)/2)\n    // set delta_y = 0\n    // sum(amounts) = y0 * (m1-m2+1)\n    //\n    // pm = (1+b)^(active_id + m)\n    //\n    // Total quote = sum(amounts) = x0 * (p(m1)+..+p(m2)) + delta_x * (m1 * p(m1) + ... + m2 * p(m2))\n    // y0 = sum(amounts) / (m1-m2+1)\n\n    const y0 = amountXInQuoteValue.div(maxDeltaId.sub(minDeltaId).addn(1));\n\n    const amountY = toAmountIntoBins(\n      activeId,\n      minDeltaId,\n      maxDeltaId,\n      new BN(0),\n      new BN(0),\n      new BN(0),\n      y0,\n      binStep,\n      favorXInActiveBin\n    ).reduce((acc, bin) => {\n      return acc.add(bin.amountY);\n    }, new BN(0));\n\n    return {\n      base: y0,\n      delta: new BN(0),\n      amountY,\n    };\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/rebalancePosition.ts",
    "content": "import { Program } from \"@coral-xyz/anchor\";\nimport { Connection, PublicKey, SYSVAR_CLOCK_PUBKEY } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { decodeAccount, deriveBinArray } from \"..\";\nimport { DLMM } from \"../..\";\nimport {\n  BASIS_POINT_MAX,\n  DEFAULT_BIN_PER_POSITION,\n  FEE_PRECISION,\n  SCALE_OFFSET,\n} from \"../../constants\";\nimport { LbClmm } from \"../../idl/idl\";\nimport {\n  Bin,\n  BinArray,\n  Clock,\n  ClockLayout,\n  LbPair,\n  POSITION_BIN_DATA_SIZE,\n  PositionData,\n  RebalanceAddLiquidityParam,\n  RebalanceRemoveLiquidityParam,\n  sParameters,\n  vParameters,\n} from \"../../types\";\nimport {\n  binIdToBinArrayIndex,\n  deriveBinArrayBitmapExtension,\n  getBinArrayLowerUpperBinId,\n  getBinIdIndexInBinArray,\n  isOverflowDefaultBinArrayBitmap,\n} from \"../binArray\";\nimport { getTotalFee } from \"../fee\";\nimport { getQPriceBaseFactor, getQPriceFromId } from \"../math\";\nimport { pow } from \"../u64xu64_math\";\nimport { getPriceOfBinByBinId } from \"../weight\";\n\nexport function buildBitFlagAndNegateStrategyParameters(\n  x0: BN,\n  y0: BN,\n  deltaX: BN,\n  deltaY: BN\n): {\n  bitFlag: number;\n  x0: BN;\n  y0: BN;\n  deltaX: BN;\n  deltaY: BN;\n} {\n  let bitFlag = 0;\n\n  if (x0.isNeg()) {\n    bitFlag |= 0b1;\n    x0 = x0.neg();\n  }\n\n  if (y0.isNeg()) {\n    bitFlag |= 0b10;\n    y0 = y0.neg();\n  }\n\n  if (deltaX.isNeg()) {\n    bitFlag |= 0b100;\n    deltaX = deltaX.neg();\n  }\n\n  if (deltaY.isNeg()) {\n    bitFlag |= 0b1000;\n    deltaY = deltaY.neg();\n  }\n\n  return {\n    bitFlag,\n    x0,\n    y0,\n    deltaX,\n    deltaY,\n  };\n}\n\nexport interface AmountIntoBin {\n  binId: BN;\n  amountX: BN;\n  amountY: BN;\n}\n\nfunction toRebalancePositionBinData(\n  positionData: PositionData\n): RebalancePositionBinData[] {\n  return positionData.positionBinData.map(\n    ({\n      binId,\n      price,\n      pricePerToken,\n      positionXAmount,\n      positionYAmount,\n      positionFeeXAmount,\n      positionFeeYAmount,\n      positionRewardAmount,\n    }) => {\n      return {\n        binId,\n        price,\n        pricePerToken: pricePerToken,\n        amountX: new BN(positionXAmount),\n        amountY: new BN(positionYAmount),\n        claimableRewardAmount: positionRewardAmount.map(\n          (amount) => new BN(amount)\n        ),\n        claimableFeeXAmount: new BN(positionFeeXAmount),\n        claimableFeeYAmount: new BN(positionFeeYAmount),\n      };\n    }\n  );\n}\n\nfunction getDepositBinIds(activeId: BN, deposits: RebalanceWithDeposit[]) {\n  const uniqueBinId = new Set<number>();\n\n  for (const { minDeltaId, maxDeltaId } of deposits) {\n    const minBinId = activeId.add(minDeltaId);\n    const maxBinId = activeId.add(maxDeltaId);\n\n    for (\n      let binId = minBinId.toNumber();\n      binId <= maxBinId.toNumber();\n      binId++\n    ) {\n      uniqueBinId.add(binId);\n    }\n  }\n\n  const binIds = Array.from(uniqueBinId);\n  binIds.sort((a, b) => a - b);\n\n  return binIds;\n}\n\nfunction findMinMaxBinIdWithLiquidity(\n  rebalancePositionBinData: RebalancePositionBinData[]\n) {\n  let minBinId = null;\n  let maxBinId = null;\n\n  for (const binData of rebalancePositionBinData) {\n    if (\n      binData.amountX.isZero() &&\n      binData.amountY.isZero() &&\n      binData.claimableFeeXAmount.isZero() &&\n      binData.claimableFeeYAmount.isZero() &&\n      binData.claimableRewardAmount.every((amount) => amount.isZero())\n    ) {\n      continue;\n    }\n\n    if (minBinId == null || binData.binId < minBinId) {\n      minBinId = binData.binId;\n    }\n\n    if (maxBinId == null || binData.binId > maxBinId) {\n      maxBinId = binData.binId;\n    }\n  }\n\n  return [minBinId, maxBinId];\n}\n\nfunction onlyDepositToBidSide(maxDeltaId: BN, favorXInActiveBin: boolean) {\n  if (favorXInActiveBin) {\n    return maxDeltaId.lt(new BN(0));\n  }\n  return maxDeltaId.lte(new BN(0));\n}\n\nfunction onlyDepositToAskSide(minDeltaId: BN, favorXInActiveBin: boolean) {\n  if (favorXInActiveBin) {\n    return minDeltaId.gte(new BN(0));\n  }\n  return minDeltaId.gt(new BN(0));\n}\n\nexport function getAmountInBinsBidSide(\n  activeId: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  deltaY: BN,\n  y0: BN\n) {\n  const amountInBins: AmountIntoBin[] = [];\n\n  const minBinId = activeId.add(minDeltaId);\n  const maxBinId = activeId.add(maxDeltaId);\n\n  for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {\n    const deltaBin = activeId.toNumber() - binId;\n    const totalDeltaY = deltaY.mul(new BN(deltaBin));\n    const amountY = y0.add(totalDeltaY);\n    amountInBins.push({\n      binId: new BN(binId),\n      amountX: new BN(0),\n      amountY,\n    });\n  }\n\n  return amountInBins;\n}\n\nexport function getAmountInBinsAskSide(\n  activeId: BN,\n  binStep: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  deltaX: BN,\n  x0: BN\n) {\n  const binCount = maxDeltaId.sub(minDeltaId).add(new BN(1));\n\n  const minBinId = activeId.add(minDeltaId);\n  const maxBinId = activeId.add(maxDeltaId);\n\n  const amountInBins: AmountIntoBin[] = new Array(binCount.toNumber());\n\n  const base = getQPriceBaseFactor(binStep);\n  let inverseBasePrice = pow(base, maxBinId.neg());\n\n  for (let binId = maxBinId.toNumber(); binId >= minBinId.toNumber(); binId--) {\n    const delta = binId - activeId.toNumber();\n    const totalDeltaX = deltaX.mul(new BN(delta));\n    const amountX = x0\n      .add(totalDeltaX)\n      .mul(inverseBasePrice)\n      .shrn(SCALE_OFFSET);\n    const idx = binId - minBinId.toNumber();\n    amountInBins[idx] = {\n      binId: new BN(binId),\n      amountX,\n      amountY: new BN(0),\n    };\n    inverseBasePrice = inverseBasePrice.mul(base).shrn(SCALE_OFFSET);\n  }\n\n  return amountInBins;\n}\n\nexport function toAmountIntoBins(\n  activeId: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  deltaX: BN,\n  deltaY: BN,\n  x0: BN,\n  y0: BN,\n  binStep: BN,\n  favorXInActiveBin: boolean\n): AmountIntoBin[] {\n  if (onlyDepositToBidSide(maxDeltaId, favorXInActiveBin)) {\n    return getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0);\n  }\n\n  if (onlyDepositToAskSide(minDeltaId, favorXInActiveBin)) {\n    return getAmountInBinsAskSide(\n      activeId,\n      binStep,\n      minDeltaId,\n      maxDeltaId,\n      deltaX,\n      x0\n    );\n  }\n\n  const [bidSideEndDeltaId, askSideStartDeltaId] = favorXInActiveBin\n    ? [-1, 0]\n    : [0, 1];\n\n  const amountInBinsBidSide = getAmountInBinsBidSide(\n    activeId,\n    minDeltaId,\n    new BN(bidSideEndDeltaId),\n    deltaY,\n    y0\n  );\n\n  const amountInBinsAskSide = getAmountInBinsAskSide(\n    activeId,\n    binStep,\n    new BN(askSideStartDeltaId),\n    maxDeltaId,\n    deltaX,\n    x0\n  );\n\n  return amountInBinsBidSide.concat(amountInBinsAskSide);\n}\n\nfunction getLiquidity(x: BN, y: BN, price: BN) {\n  const px = price.mul(x);\n  const shly = y.shln(SCALE_OFFSET);\n  return px.add(shly);\n}\n\nfunction computeCompositionFee(\n  binStep: BN,\n  sParameters: sParameters,\n  vParameters: vParameters,\n  outAmountX: BN,\n  inAmountX: BN,\n  outAmountY: BN,\n  inAmountY: BN\n) {\n  if (outAmountX.gt(inAmountX)) {\n    const delta = inAmountY.sub(outAmountY);\n    const totalFeeRate = getTotalFee(\n      binStep.toNumber(),\n      sParameters,\n      vParameters\n    );\n    const feeAmount = delta.mul(totalFeeRate);\n    return feeAmount\n      .mul(FEE_PRECISION.add(totalFeeRate))\n      .div(FEE_PRECISION.pow(new BN(2)));\n  }\n  return new BN(0);\n}\n\nfunction simulateDepositBin(\n  binId: BN,\n  binStep: BN,\n  amountX: BN,\n  amountY: BN,\n  bin: Bin | null\n) {\n  if (!bin) {\n    return {\n      amountXIntoBin: amountX,\n      amountYIntoBin: amountY,\n    };\n  }\n\n  const price = getQPriceFromId(binId, binStep);\n  const inLiquidity = getLiquidity(amountX, amountY, price);\n  const binLiquidity = getLiquidity(bin.amountX, bin.amountY, price);\n\n  if (bin.liquiditySupply.isZero()) {\n    return {\n      amountXIntoBin: amountX,\n      amountYIntoBin: amountY,\n    };\n  }\n\n  const liquidityShare = inLiquidity.mul(bin.liquiditySupply).div(binLiquidity);\n  const updatedBinXAmount = bin.amountX.add(amountX);\n  const updatedBinYAmount = bin.amountY.add(amountY);\n  const updatedBinSupply = bin.liquiditySupply.add(liquidityShare);\n\n  let amountXIntoBin = liquidityShare.mul(\n    updatedBinXAmount.div(updatedBinSupply)\n  );\n  let amountYIntoBin = liquidityShare.mul(\n    updatedBinYAmount.div(updatedBinSupply)\n  );\n\n  if (amountXIntoBin.gt(amountX)) {\n  }\n\n  return {\n    amountXIntoBin,\n    amountYIntoBin,\n  };\n}\n\ninterface SimulateWithdrawResult {\n  liquidityAndFeeXWithdrawn: BN;\n  liquidityAndFeeYWithdrawn: BN;\n  rewardsAmountClaimed: BN[];\n}\n\ninterface SimulateDepositResult {\n  totalAmountXDeposited: BN;\n  totalAmountYDeposited: BN;\n  actualTotalAmountXDeposited: BN;\n  actualTotalAmountYDeposited: BN;\n  actualLiquidityAndFeeXWithdrawn: BN;\n  actualLiquidityAndFeeYWithdrawn: BN;\n}\n\nexport interface CreateRebalancePositionParams {\n  program: Program<LbClmm>;\n  pairAddress: PublicKey;\n  positionAddress: PublicKey;\n  positionData: PositionData;\n  shouldClaimFee: boolean;\n  shouldClaimReward: boolean;\n}\n\nexport class RebalancePosition {\n  public address: PublicKey;\n  public lowerBinId: BN;\n  public upperBinId: BN;\n  public lbPair: LbPair;\n  public owner: PublicKey;\n  public shouldClaimFee: boolean;\n  public shouldClaimReward: boolean;\n  public rebalancePositionBinData: RebalancePositionBinData[];\n  public activeBin: Bin | null;\n  public currentTimestamp: BN;\n\n  constructor(\n    positionAddress: PublicKey,\n    positionData: PositionData,\n    lbPair: LbPair,\n    activeBin: Bin | null,\n    shouldClaimFee: boolean,\n    shouldClaimReward: boolean,\n    currentTimestamp: BN\n  ) {\n    this.address = positionAddress;\n    this.rebalancePositionBinData = toRebalancePositionBinData(positionData);\n    this.lowerBinId = new BN(positionData.lowerBinId);\n    this.upperBinId = new BN(positionData.upperBinId);\n    this.lbPair = lbPair;\n    this.shouldClaimFee = shouldClaimFee;\n    this.shouldClaimReward = shouldClaimReward;\n    this.owner = positionData.owner;\n    this.activeBin = activeBin;\n    this.currentTimestamp = currentTimestamp;\n  }\n\n  static async create(\n    params: CreateRebalancePositionParams\n  ): Promise<RebalancePosition> {\n    const {\n      program,\n      positionAddress,\n      pairAddress,\n      positionData,\n      shouldClaimFee,\n      shouldClaimReward,\n    } = params;\n    const [lbPairAccount, clockAccount] =\n      await program.provider.connection.getMultipleAccountsInfo([\n        pairAddress,\n        SYSVAR_CLOCK_PUBKEY,\n      ]);\n\n    const lbPair = decodeAccount<LbPair>(program, \"lbPair\", lbPairAccount.data);\n    const clock = ClockLayout.decode(clockAccount.data) as Clock;\n\n    const activeBinArrayIdx = binIdToBinArrayIndex(new BN(lbPair.activeId));\n    const [activeBinArrayPubkey] = deriveBinArray(\n      pairAddress,\n      activeBinArrayIdx,\n      program.programId\n    );\n\n    const [lowerBinId, upperBinId] =\n      getBinArrayLowerUpperBinId(activeBinArrayIdx);\n    const idx = getBinIdIndexInBinArray(\n      new BN(lbPair.activeId),\n      lowerBinId,\n      upperBinId\n    );\n\n    let activeBin: Bin | null = null;\n    try {\n      const activeBinArrayState = await program.account.binArray.fetch(\n        activeBinArrayPubkey\n      );\n      activeBin = activeBinArrayState[idx.toNumber()];\n    } catch (error) {\n      // error happens when the active bin array is not initialized\n    }\n\n    return new RebalancePosition(\n      positionAddress,\n      positionData,\n      lbPair,\n      activeBin,\n      shouldClaimFee,\n      shouldClaimReward,\n      clock.unixTimestamp\n    );\n  }\n\n  _simulateDeposit(\n    binStep: BN,\n    tokenXDecimal: BN,\n    tokenYDecimal: BN,\n    deposits: RebalanceWithDeposit[],\n    simulatedWithdrawResult: SimulateWithdrawResult\n  ): {\n    result: SimulateDepositResult;\n    depositParams: RebalanceAddLiquidityParam[];\n  } {\n    const { liquidityAndFeeXWithdrawn, liquidityAndFeeYWithdrawn } =\n      simulatedWithdrawResult;\n\n    const activeId = new BN(this.lbPair.activeId);\n    const depositBinIds = getDepositBinIds(activeId, deposits);\n\n    if (depositBinIds.length > 0) {\n      const depositMinBinId = depositBinIds[0];\n      const depositMaxBinId = depositBinIds[depositBinIds.length - 1];\n\n      this._simulateResize(\n        new BN(depositMinBinId),\n        new BN(depositMaxBinId),\n        binStep,\n        tokenXDecimal,\n        tokenYDecimal\n      );\n    }\n\n    let totalAmountXDeposited = new BN(0);\n    let totalAmountYDeposited = new BN(0);\n\n    const addLiquidityParam: RebalanceAddLiquidityParam[] = [];\n\n    for (const {\n      x0,\n      y0,\n      favorXInActiveBin,\n      deltaX,\n      deltaY,\n      minDeltaId,\n      maxDeltaId,\n    } of deposits) {\n      const params = buildBitFlagAndNegateStrategyParameters(\n        x0,\n        y0,\n        deltaX,\n        deltaY\n      );\n\n      addLiquidityParam.push({\n        minDeltaId: minDeltaId.toNumber(),\n        maxDeltaId: maxDeltaId.toNumber(),\n        x0: params.x0,\n        y0: params.y0,\n        deltaX: params.deltaX,\n        deltaY: params.deltaY,\n        bitFlag: params.bitFlag,\n        padding: Array(16).fill(0),\n        favorXInActiveId: favorXInActiveBin,\n      });\n\n      const amountIntoBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      for (const { binId, amountX, amountY } of amountIntoBins) {\n        totalAmountXDeposited = totalAmountXDeposited.add(amountX);\n        totalAmountYDeposited = totalAmountYDeposited.add(amountY);\n\n        const idx = this.rebalancePositionBinData.findIndex(\n          (data) => data.binId == binId.toNumber()\n        );\n\n        if (binId.eq(activeId)) {\n          const vParameters = Object.assign({}, this.lbPair.vParameters);\n          const sParameters = Object.assign({}, this.lbPair.parameters);\n          DLMM.updateReference(\n            activeId.toNumber(),\n            vParameters,\n            sParameters,\n            this.currentTimestamp.toNumber()\n          );\n          DLMM.updateVolatilityAccumulator(\n            vParameters,\n            sParameters,\n            activeId.toNumber()\n          );\n          const { amountXIntoBin, amountYIntoBin } = simulateDepositBin(\n            binId,\n            binStep,\n            amountX,\n            amountY,\n            this.activeBin\n          );\n          const feeY = computeCompositionFee(\n            binStep,\n            sParameters,\n            vParameters,\n            amountXIntoBin,\n            amountX,\n            amountYIntoBin,\n            amountY\n          );\n          const feeX = computeCompositionFee(\n            binStep,\n            sParameters,\n            vParameters,\n            amountYIntoBin,\n            amountY,\n            amountXIntoBin,\n            amountX\n          );\n          const amountXIntoBinExcludeFee = amountXIntoBin.sub(feeX);\n          const amountYIntoBinExcludeFee = amountYIntoBin.sub(feeY);\n          this.rebalancePositionBinData[idx].amountX =\n            this.rebalancePositionBinData[idx].amountX.add(\n              amountXIntoBinExcludeFee\n            );\n          this.rebalancePositionBinData[idx].amountY =\n            this.rebalancePositionBinData[idx].amountY.add(\n              amountYIntoBinExcludeFee\n            );\n        } else {\n          this.rebalancePositionBinData[idx].amountX =\n            this.rebalancePositionBinData[idx].amountX.add(amountX);\n          this.rebalancePositionBinData[idx].amountY =\n            this.rebalancePositionBinData[idx].amountY.add(amountY);\n        }\n      }\n    }\n\n    let actualTotalAmountXDeposited = totalAmountXDeposited;\n    let actualTotalAmountYDeposited = totalAmountYDeposited;\n    let actualLiquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn;\n    let actualLiquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn;\n\n    if (actualTotalAmountXDeposited.gt(actualLiquidityAndFeeXWithdrawn)) {\n      actualTotalAmountXDeposited = actualTotalAmountXDeposited.sub(\n        actualLiquidityAndFeeXWithdrawn\n      );\n      actualLiquidityAndFeeXWithdrawn = new BN(0);\n    } else {\n      actualLiquidityAndFeeXWithdrawn = actualLiquidityAndFeeXWithdrawn.sub(\n        actualTotalAmountXDeposited\n      );\n      actualTotalAmountXDeposited = new BN(0);\n    }\n\n    if (actualTotalAmountYDeposited.gt(actualLiquidityAndFeeYWithdrawn)) {\n      actualTotalAmountYDeposited = actualTotalAmountYDeposited.sub(\n        actualLiquidityAndFeeYWithdrawn\n      );\n      actualLiquidityAndFeeYWithdrawn = new BN(0);\n    } else {\n      actualLiquidityAndFeeYWithdrawn = actualLiquidityAndFeeYWithdrawn.sub(\n        actualTotalAmountYDeposited\n      );\n      actualTotalAmountYDeposited = new BN(0);\n    }\n\n    return {\n      result: {\n        totalAmountXDeposited,\n        totalAmountYDeposited,\n        actualLiquidityAndFeeXWithdrawn,\n        actualLiquidityAndFeeYWithdrawn,\n        actualTotalAmountXDeposited,\n        actualTotalAmountYDeposited,\n      },\n      depositParams: addLiquidityParam,\n    };\n  }\n\n  _simulateResize(\n    depositMinBinId: BN,\n    depositMaxBinId: BN,\n    binStep: BN,\n    tokenXDecimal: BN,\n    tokenYDecimal: BN\n  ) {\n    const tokenXMultiplier = new Decimal(10 ** tokenXDecimal.toNumber());\n    const tokenYMultiplier = new Decimal(10 ** tokenYDecimal.toNumber());\n\n    const [minBinId, maxBinId] = findMinMaxBinIdWithLiquidity(\n      this.rebalancePositionBinData\n    );\n\n    const newMinBinId = new BN(\n      Math.min(depositMinBinId.toNumber(), minBinId ?? Number.MAX_SAFE_INTEGER)\n    );\n    const newMaxBinId = new BN(\n      Math.max(depositMaxBinId.toNumber(), maxBinId ?? Number.MIN_SAFE_INTEGER)\n    );\n\n    if (newMinBinId.lt(this.lowerBinId)) {\n      const binCountToExpand = this.lowerBinId.sub(depositMinBinId);\n      for (let i = 1; i <= binCountToExpand.toNumber(); i++) {\n        const binId = this.lowerBinId.subn(i);\n        const price = getPriceOfBinByBinId(\n          binId.toNumber(),\n          binStep.toNumber()\n        );\n        const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);\n\n        this.rebalancePositionBinData.unshift({\n          binId: binId.toNumber(),\n          price: adjustedPrice.toString(),\n          pricePerToken: adjustedPrice.toString(),\n          amountX: new BN(0),\n          amountY: new BN(0),\n          claimableRewardAmount: [new BN(0), new BN(0)],\n          claimableFeeXAmount: new BN(0),\n          claimableFeeYAmount: new BN(0),\n        });\n      }\n    } else {\n      const binCountToShrink = newMinBinId.sub(this.lowerBinId);\n      for (let i = 1; i <= binCountToShrink.toNumber(); i++) {\n        this.rebalancePositionBinData.shift();\n      }\n    }\n\n    if (newMaxBinId.gt(this.upperBinId)) {\n      const binCountToExpand = newMaxBinId.sub(this.upperBinId);\n      for (let i = 1; i <= binCountToExpand.toNumber(); i++) {\n        const binId = this.upperBinId.addn(i);\n        const price = getPriceOfBinByBinId(\n          binId.toNumber(),\n          binStep.toNumber()\n        );\n        const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);\n\n        this.rebalancePositionBinData.push({\n          binId: binId.toNumber(),\n          price: adjustedPrice.toString(),\n          pricePerToken: adjustedPrice.toString(),\n          amountX: new BN(0),\n          amountY: new BN(0),\n          claimableRewardAmount: [new BN(0), new BN(0)],\n          claimableFeeXAmount: new BN(0),\n          claimableFeeYAmount: new BN(0),\n        });\n      }\n    } else {\n      const binCountToShrink = this.upperBinId.sub(newMaxBinId);\n      for (let i = 1; i <= binCountToShrink.toNumber(); i++) {\n        this.rebalancePositionBinData.pop();\n      }\n    }\n\n    this.lowerBinId = newMinBinId;\n    this.upperBinId = newMaxBinId;\n  }\n\n  _simulateWithdraw(withdraws: RebalanceWithWithdraw[]): {\n    result: SimulateWithdrawResult;\n    withdrawParams: RebalanceRemoveLiquidityParam[];\n  } {\n    let liquidityAndFeeXWithdrawn = new BN(0);\n    let liquidityAndFeeYWithdrawn = new BN(0);\n    let rewardsAmountClaimed = [new BN(0), new BN(0)];\n\n    const activeId = new BN(this.lbPair.activeId);\n\n    for (const { minBinId, maxBinId, bps } of withdraws) {\n      const fromBinId = minBinId ?? activeId;\n      const toBinId = maxBinId ?? activeId;\n\n      const binIds = binRangeToBinIdArray(fromBinId, toBinId).filter(\n        (binId) => binId.gte(this.lowerBinId) && binId.lte(this.upperBinId)\n      );\n\n      for (const binId of binIds) {\n        const idx = this.rebalancePositionBinData.findIndex(\n          (b) => b.binId === binId.toNumber()\n        );\n\n        const binData = this.rebalancePositionBinData[idx];\n\n        // 1. Withdraw\n        const amountXWithdrawn = binData.amountX.mul(bps).divn(BASIS_POINT_MAX);\n        const amountYWithdrawn = binData.amountY.mul(bps).divn(BASIS_POINT_MAX);\n\n        liquidityAndFeeXWithdrawn =\n          liquidityAndFeeXWithdrawn.add(amountXWithdrawn);\n        liquidityAndFeeYWithdrawn =\n          liquidityAndFeeYWithdrawn.add(amountYWithdrawn);\n\n        binData.amountX = binData.amountX.sub(amountXWithdrawn);\n        binData.amountY = binData.amountY.sub(amountYWithdrawn);\n\n        // 2. Claim fee\n        if (this.shouldClaimFee) {\n          liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(\n            binData.claimableFeeXAmount\n          );\n          liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(\n            binData.claimableFeeYAmount\n          );\n\n          binData.claimableFeeXAmount = new BN(0);\n          binData.claimableFeeYAmount = new BN(0);\n        }\n\n        // 3. Claim reward\n        if (this.shouldClaimReward) {\n          for (const [idx, amount] of binData.claimableRewardAmount.entries()) {\n            rewardsAmountClaimed[idx] = rewardsAmountClaimed[idx].add(amount);\n            binData.claimableRewardAmount[idx] = new BN(0);\n          }\n        }\n\n        // Update state\n        this.rebalancePositionBinData[idx] = binData;\n      }\n    }\n\n    const withdrawParams: RebalanceRemoveLiquidityParam[] = withdraws.map(\n      ({ minBinId, maxBinId, bps }) => {\n        return {\n          minBinId: minBinId ? minBinId.toNumber() : null,\n          maxBinId: maxBinId ? maxBinId.toNumber() : null,\n          bps: bps.toNumber(),\n          padding: Array(16).fill(0),\n        };\n      }\n    );\n\n    return {\n      result: {\n        liquidityAndFeeXWithdrawn,\n        liquidityAndFeeYWithdrawn,\n        rewardsAmountClaimed,\n      },\n      withdrawParams,\n    };\n  }\n\n  async simulateRebalance(\n    connection: Connection,\n    binStep: BN,\n    tokenXDecimal: BN,\n    tokenYDecimal: BN,\n    withdraws: RebalanceWithWithdraw[],\n    deposits: RebalanceWithDeposit[]\n  ): Promise<SimulateRebalanceResp> {\n    if (withdraws.length == 0 && deposits.length == 0) {\n      throw \"No rebalance action\";\n    }\n\n    const activeId = new BN(this.lbPair.activeId);\n\n    withdraws = validateAndSortRebalanceWithdraw(withdraws, activeId);\n    deposits = validateAndSortRebalanceDeposit(deposits);\n\n    const beforeWidth = getPositionWidthWithMinWidth(\n      this.lowerBinId.toNumber(),\n      this.upperBinId.toNumber()\n    );\n\n    const { withdrawParams, result: withdrawResult } =\n      this._simulateWithdraw(withdraws);\n\n    const { depositParams, result: depositResult } = this._simulateDeposit(\n      binStep,\n      tokenXDecimal,\n      tokenYDecimal,\n      deposits,\n      withdrawResult\n    );\n\n    const afterWidth = getPositionWidthWithMinWidth(\n      this.lowerBinId.toNumber(),\n      this.upperBinId.toNumber()\n    );\n\n    const widthDelta = afterWidth - beforeWidth;\n\n    let rentalCostLamports = new BN(0);\n\n    if (widthDelta != 0) {\n      const sizeChanges = Math.abs(widthDelta) * POSITION_BIN_DATA_SIZE;\n      const [minimumLamports, rentExemptionLamports] = await Promise.all([\n        connection.getMinimumBalanceForRentExemption(0),\n        connection.getMinimumBalanceForRentExemption(sizeChanges),\n      ]);\n\n      const lamportChanges = new BN(rentExemptionLamports).sub(\n        new BN(minimumLamports)\n      );\n\n      if (widthDelta > 0) {\n        rentalCostLamports = rentalCostLamports.add(lamportChanges);\n      } else {\n        rentalCostLamports = rentalCostLamports.sub(lamportChanges);\n      }\n    }\n\n    return {\n      amountXDeposited: depositResult.totalAmountXDeposited,\n      amountYDeposited: depositResult.totalAmountYDeposited,\n      actualAmountXDeposited: depositResult.actualTotalAmountXDeposited,\n      actualAmountYDeposited: depositResult.actualTotalAmountYDeposited,\n      actualAmountXWithdrawn: depositResult.actualLiquidityAndFeeXWithdrawn,\n      actualAmountYWithdrawn: depositResult.actualLiquidityAndFeeYWithdrawn,\n      rewardAmountsClaimed: withdrawResult.rewardsAmountClaimed,\n      withdrawParams,\n      depositParams,\n      rentalCostLamports,\n    };\n  }\n\n  totalAmounts(): BN[] {\n    let totalAmountX = new BN(0);\n    let totalAmountY = new BN(0);\n\n    for (const binData of this.rebalancePositionBinData) {\n      totalAmountX = totalAmountX.add(binData.amountX);\n      totalAmountY = totalAmountY.add(binData.amountY);\n    }\n\n    return [totalAmountX, totalAmountY];\n  }\n\n  totalFeeAmounts(): BN[] {\n    let totalFeeXAmount = new BN(0);\n    let totalFeeYAmount = new BN(0);\n\n    for (const binData of this.rebalancePositionBinData) {\n      totalFeeXAmount = totalFeeXAmount.add(binData.claimableFeeXAmount);\n      totalFeeYAmount = totalFeeYAmount.add(binData.claimableFeeYAmount);\n    }\n\n    return [totalFeeXAmount, totalFeeYAmount];\n  }\n\n  totalRewardAmounts(): BN[] {\n    let totalRewardAmounts = [new BN(0), new BN(0)];\n\n    for (const binData of this.rebalancePositionBinData) {\n      totalRewardAmounts[0] = totalRewardAmounts[0].add(\n        binData.claimableRewardAmount[0]\n      );\n      totalRewardAmounts[1] = totalRewardAmounts[1].add(\n        binData.claimableRewardAmount[1]\n      );\n    }\n\n    return totalRewardAmounts;\n  }\n}\n\nfunction getPositionWidthWithMinWidth(lowerBinId: number, upperBinId: number) {\n  const width = upperBinId - lowerBinId + 1;\n  return Math.max(width, DEFAULT_BIN_PER_POSITION.toNumber());\n}\n\nfunction validateAndSortRebalanceDeposit(deposits: RebalanceWithDeposit[]) {\n  const sortedDeposits = deposits.sort((a, b) =>\n    a.minDeltaId.sub(b.minDeltaId).toNumber()\n  );\n\n  for (const deposit of deposits) {\n    if (deposit.minDeltaId.gt(deposit.maxDeltaId)) {\n      throw \"Invalid minDeltaId or maxDeltaId\";\n    }\n  }\n\n  for (let i = 1; i < sortedDeposits.length; i++) {\n    const prevDeposit = sortedDeposits[i - 1];\n    const currDeposit = sortedDeposits[i];\n\n    if (prevDeposit.maxDeltaId.gte(currDeposit.minDeltaId)) {\n      throw \"Overlap deposit bin range\";\n    }\n  }\n\n  return sortedDeposits;\n}\n\nfunction validateAndSortRebalanceWithdraw(\n  withdraws: RebalanceWithWithdraw[],\n  activeId: BN\n) {\n  const filledWithdraws: RebalanceWithWithdraw[] = [];\n\n  for (const { minBinId, maxBinId, bps } of withdraws) {\n    if (bps.toNumber() < 0 || bps.toNumber() > BASIS_POINT_MAX) {\n      throw \"Invalid bps\";\n    }\n\n    const filledMinBinId = minBinId ?? activeId;\n    const filledMaxBinId = maxBinId ?? activeId;\n\n    if (filledMinBinId.gt(filledMaxBinId)) {\n      throw \"Invalid minBinId or maxBinId\";\n    }\n\n    filledWithdraws.push({\n      minBinId: filledMinBinId,\n      maxBinId: filledMaxBinId,\n      bps,\n    });\n  }\n\n  filledWithdraws.sort((a, b) => {\n    return a.minBinId.sub(b.minBinId).toNumber();\n  });\n\n  for (let i = 1; i < filledWithdraws.length; i++) {\n    const prev = filledWithdraws[i - 1];\n    const curr = filledWithdraws[i];\n    if (curr.minBinId.lte(prev.maxBinId)) {\n      throw \"Overlap withdraw bin range\";\n    }\n  }\n\n  return filledWithdraws;\n}\n\ninterface RebalancePositionBinData {\n  /// Bin ID\n  binId: number;\n  /// Price of the bin\n  price: string;\n  /// Price per token of the bin\n  pricePerToken: string;\n  /// Amount X in the bin\n  amountX: BN;\n  /// Amount Y in the bin\n  amountY: BN;\n  /// Claimable reward amount in the bin\n  claimableRewardAmount: BN[];\n  /// Claimable fee X amount in the bin\n  claimableFeeXAmount: BN;\n  /// Claimable fee Y amount in the bin\n  claimableFeeYAmount: BN;\n}\n\nexport interface RebalanceWithDeposit {\n  /// minBinId = activeId + minDeltaId\n  minDeltaId: BN;\n  /// maxBinId = activeId + maxDeltaId\n  maxDeltaId: BN;\n  /// X0\n  x0: BN;\n  /// Y0\n  y0: BN;\n  /// Delta X\n  deltaX: BN;\n  /// Delta Y\n  deltaY: BN;\n  /// Deposit token X or Y in active bin\n  favorXInActiveBin: boolean;\n}\n\nexport interface RebalanceWithWithdraw {\n  /// Withdraw start from minBinId. When it's `null`, it will start from activeId.\n  minBinId: BN | null;\n  /// Withdraw end at maxBinId. When it's `null`, it will end at activeId.\n  maxBinId: BN | null;\n  /// BPS of liquidity to be withdrawn from minBinId to maxBinId\n  bps: BN;\n}\n\nexport interface SimulateRebalanceResp {\n  amountXDeposited: BN;\n  amountYDeposited: BN;\n  actualAmountXDeposited: BN;\n  actualAmountYDeposited: BN;\n  actualAmountXWithdrawn: BN;\n  actualAmountYWithdrawn: BN;\n  rewardAmountsClaimed: BN[];\n  depositParams: RebalanceAddLiquidityParam[];\n  withdrawParams: RebalanceRemoveLiquidityParam[];\n  rentalCostLamports: BN;\n}\n\nfunction binRangeToBinIdArray(minBinId: BN, maxBinId: BN): BN[] {\n  const binIdArray = [];\n\n  const fromBinId = minBinId.toNumber();\n  const toBinId = maxBinId.toNumber();\n\n  for (let binId = fromBinId; binId <= toBinId; binId++) {\n    binIdArray.push(new BN(binId));\n  }\n\n  return binIdArray;\n}\n\nexport function getRebalanceBinArrayIndexesAndBitmapCoverage(\n  adds: RebalanceAddLiquidityParam[],\n  removes: RebalanceRemoveLiquidityParam[],\n  activeId: number,\n  pairAddress: PublicKey,\n  programId: PublicKey\n): {\n  binArrayIndexes: BN[];\n  binArrayBitmap: PublicKey;\n} {\n  let indexMap: Map<number, boolean> = new Map();\n  removes.forEach((value) => {\n    let minBinId = value.minBinId;\n    if (minBinId == null) {\n      minBinId = activeId;\n    }\n    let maxBinId = value.maxBinId;\n    if (maxBinId == null) {\n      maxBinId = activeId;\n    }\n    let binArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const upperBinId = new BN(maxBinId);\n    while (true) {\n      indexMap.set(binArrayIndex.toNumber(), true);\n      const [binArrayLowerBinId, binArrayUpperBinId] =\n        getBinArrayLowerUpperBinId(binArrayIndex);\n\n      if (\n        upperBinId.gte(binArrayLowerBinId) &&\n        upperBinId.lte(binArrayUpperBinId)\n      ) {\n        break;\n      } else {\n        binArrayIndex = binArrayIndex.add(new BN(1));\n      }\n    }\n  });\n\n  adds.forEach((value) => {\n    const minBinId = activeId + value.minDeltaId;\n    const maxBinId = activeId + value.maxDeltaId;\n    let binArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const upperBinId = new BN(maxBinId);\n    while (true) {\n      indexMap.set(binArrayIndex.toNumber(), true);\n      const [binArrayLowerBinId, binArrayUpperBinId] =\n        getBinArrayLowerUpperBinId(binArrayIndex);\n\n      if (\n        upperBinId.gte(binArrayLowerBinId) &&\n        upperBinId.lte(binArrayUpperBinId)\n      ) {\n        break;\n      } else {\n        binArrayIndex = binArrayIndex.add(new BN(1));\n      }\n    }\n  });\n  const binArrayIndexes = Array.from(indexMap.keys()).map((idx) => new BN(idx));\n\n  const requireBitmapExtension = binArrayIndexes.some((index) =>\n    isOverflowDefaultBinArrayBitmap(new BN(index))\n  );\n\n  return {\n    binArrayIndexes,\n    binArrayBitmap: requireBitmapExtension\n      ? deriveBinArrayBitmapExtension(pairAddress, programId)[0]\n      : programId,\n  };\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/strategy/balanced.ts",
    "content": "import BN from \"bn.js\";\nimport {\n  capBps,\n  MAX_BPS,\n  RebalanceDepositWithdrawParameters,\n  RebalanceStrategyBuilder,\n} from \".\";\nimport { PositionData, StrategyType } from \"../../../types\";\nimport {\n  buildLiquidityStrategyParameters,\n  getLiquidityStrategyParameterBuilder,\n} from \"../liquidity_strategy\";\nimport {\n  RebalanceWithDeposit,\n  RebalanceWithWithdraw,\n} from \"../rebalancePosition\";\n\nexport class BalancedStrategyBuilder implements RebalanceStrategyBuilder {\n  constructor(\n    public activeId: BN,\n    public binStep: BN,\n    public positionData: PositionData,\n    public topUpAmountX: BN,\n    public topUpAmountY: BN,\n    public xWithdrawBps: BN,\n    public yWithdrawBps: BN,\n    public strategy: StrategyType,\n    public favorXIfImbalance: boolean = false,\n    public favorXInActiveBin: boolean = false\n  ) {}\n\n  // Rebalance to active bin by withdrawing all liquidities and redeposit portion of withdrawn liquidity, together with topup amount\n  buildRebalanceStrategyParameters(): RebalanceDepositWithdrawParameters {\n    const xWithdrawBps = capBps(this.xWithdrawBps);\n    const yWithdrawBps = capBps(this.yWithdrawBps);\n\n    let totalXAmountOut = new BN(this.positionData.totalXAmount);\n    let totalYAmountOut = new BN(this.positionData.totalYAmount);\n\n    totalXAmountOut = totalXAmountOut.add(new BN(this.positionData.feeX));\n    totalYAmountOut = totalYAmountOut.add(new BN(this.positionData.feeY));\n\n    const redepositAmountX = totalXAmountOut\n      .mul(MAX_BPS.sub(xWithdrawBps))\n      .div(MAX_BPS);\n    const redepositAmountY = totalYAmountOut\n      .mul(MAX_BPS.sub(yWithdrawBps))\n      .div(MAX_BPS);\n\n    const depositAmountX = this.topUpAmountX.add(redepositAmountX);\n    const depositAmountY = this.topUpAmountY.add(redepositAmountY);\n\n    const width =\n      this.positionData.upperBinId - this.positionData.lowerBinId + 1;\n    const binPerSide = Math.floor(width / 2);\n    const rem = width % 2;\n\n    let binPerAsk = binPerSide;\n    let binPerBid = binPerSide;\n\n    if (rem == 0) {\n      if (this.favorXIfImbalance) {\n        binPerAsk += 1;\n        binPerBid -= 1;\n      } else {\n        binPerAsk -= 1;\n        binPerBid += 1;\n      }\n    }\n\n    const minDeltaId = new BN(binPerBid).neg();\n    const maxDeltaId = new BN(binPerAsk);\n\n    const strategyParameters = buildLiquidityStrategyParameters(\n      depositAmountX,\n      depositAmountY,\n      minDeltaId,\n      maxDeltaId,\n      this.binStep,\n      this.favorXInActiveBin,\n      this.activeId,\n      getLiquidityStrategyParameterBuilder(this.strategy)\n    );\n\n    const depositParam: RebalanceWithDeposit = {\n      minDeltaId,\n      maxDeltaId,\n      x0: strategyParameters.x0,\n      y0: strategyParameters.y0,\n      deltaX: strategyParameters.deltaX,\n      deltaY: strategyParameters.deltaY,\n      favorXInActiveBin: this.favorXInActiveBin,\n    };\n\n    const withdrawParam: RebalanceWithWithdraw = {\n      minBinId: new BN(this.positionData.lowerBinId),\n      maxBinId: new BN(this.positionData.upperBinId),\n      bps: MAX_BPS,\n    };\n\n    return {\n      shouldClaimFee: true,\n      shouldClaimReward: true,\n      deposits: [depositParam],\n      withdraws: [withdrawParam],\n    };\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/rebalance/strategy/index.ts",
    "content": "import BN from \"bn.js\";\nimport { BASIS_POINT_MAX } from \"../../../constants\";\nimport {\n  RebalanceWithDeposit,\n  RebalanceWithWithdraw,\n} from \"../rebalancePosition\";\n\nexport interface RebalanceDepositWithdrawParameters {\n  shouldClaimFee: boolean;\n  shouldClaimReward: boolean;\n  deposits: RebalanceWithDeposit[];\n  withdraws: RebalanceWithWithdraw[];\n}\n\nexport interface RebalanceStrategyBuilder {\n  buildRebalanceStrategyParameters(): RebalanceDepositWithdrawParameters;\n}\n\nexport const MAX_BPS = new BN(BASIS_POINT_MAX);\n\nexport function capBps(bps: BN) {\n  return bps.lt(new BN(0))\n    ? new BN(0)\n    : bps.gt(MAX_BPS)\n    ? new BN(MAX_BPS)\n    : bps;\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/strategy.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport { Mint } from \"@solana/spl-token\";\nimport {\n  Clock,\n  ProgramStrategyParameter,\n  StrategyParameters,\n  StrategyType,\n} from \"../types\";\nimport {\n  autoFillXByWeight,\n  autoFillYByWeight,\n  toAmountAskSide,\n  toAmountBidSide,\n  toAmountBothSide,\n} from \"./weightToAmounts\";\n\nconst DEFAULT_MAX_WEIGHT = 2000;\nconst DEFAULT_MIN_WEIGHT = 200;\n\nfunction toWeightSpotBalanced(\n  minBinId: number,\n  maxBinId: number\n): {\n  binId: number;\n  weight: number;\n}[] {\n  let distributions = [];\n  for (let i = minBinId; i <= maxBinId; i++) {\n    distributions.push({\n      binId: i,\n      weight: 1,\n    });\n  }\n  return distributions;\n}\n\nfunction toWeightDescendingOrder(\n  minBinId: number,\n  maxBinId: number\n): {\n  binId: number;\n  weight: number;\n}[] {\n  let distributions = [];\n  for (let i = minBinId; i <= maxBinId; i++) {\n    distributions.push({\n      binId: i,\n      weight: maxBinId - i + 1,\n    });\n  }\n  return distributions;\n}\n\nfunction toWeightAscendingOrder(\n  minBinId: number,\n  maxBinId: number\n): {\n  binId: number;\n  weight: number;\n}[] {\n  let distributions = [];\n  for (let i = minBinId; i <= maxBinId; i++) {\n    distributions.push({\n      binId: i,\n      weight: i - minBinId + 1,\n    });\n  }\n  return distributions;\n}\n\nfunction toWeightCurve(\n  minBinId: number,\n  maxBinId: number,\n  activeId: number\n): {\n  binId: number;\n  weight: number;\n}[] {\n  if (activeId < minBinId || activeId > maxBinId) {\n    throw \"Invalid strategy params\";\n  }\n  let maxWeight = DEFAULT_MAX_WEIGHT;\n  let minWeight = DEFAULT_MIN_WEIGHT;\n\n  let diffWeight = maxWeight - minWeight;\n  let diffMinWeight =\n    activeId > minBinId ? Math.floor(diffWeight / (activeId - minBinId)) : 0;\n  let diffMaxWeight =\n    maxBinId > activeId ? Math.floor(diffWeight / (maxBinId - activeId)) : 0;\n\n  let distributions = [];\n  for (let i = minBinId; i <= maxBinId; i++) {\n    if (i < activeId) {\n      distributions.push({\n        binId: i,\n        weight: maxWeight - (activeId - i) * diffMinWeight,\n      });\n    } else if (i > activeId) {\n      distributions.push({\n        binId: i,\n        weight: maxWeight - (i - activeId) * diffMaxWeight,\n      });\n    } else {\n      distributions.push({\n        binId: i,\n        weight: maxWeight,\n      });\n    }\n  }\n  return distributions;\n}\n\nfunction toWeightBidAsk(\n  minBinId: number,\n  maxBinId: number,\n  activeId: number\n): {\n  binId: number;\n  weight: number;\n}[] {\n  if (activeId < minBinId || activeId > maxBinId) {\n    throw \"Invalid strategy params\";\n  }\n  let maxWeight = DEFAULT_MAX_WEIGHT;\n  let minWeight = DEFAULT_MIN_WEIGHT;\n\n  let diffWeight = maxWeight - minWeight;\n  let diffMinWeight =\n    activeId > minBinId ? Math.floor(diffWeight / (activeId - minBinId)) : 0;\n  let diffMaxWeight =\n    maxBinId > activeId ? Math.floor(diffWeight / (maxBinId - activeId)) : 0;\n\n  let distributions = [];\n  for (let i = minBinId; i <= maxBinId; i++) {\n    if (i < activeId) {\n      distributions.push({\n        binId: i,\n        weight: minWeight + (activeId - i) * diffMinWeight,\n      });\n    } else if (i > activeId) {\n      distributions.push({\n        binId: i,\n        weight: minWeight + (i - activeId) * diffMaxWeight,\n      });\n    } else {\n      distributions.push({\n        binId: i,\n        weight: minWeight,\n      });\n    }\n  }\n  return distributions;\n}\n\n/**\n * Given a strategy type and amounts of X and Y, returns the distribution of liquidity.\n * @param activeId The bin id of the active bin.\n * @param binStep The step size of each bin.\n * @param minBinId The min bin id.\n * @param maxBinId The max bin id.\n * @param amountX The amount of X token to deposit.\n * @param amountY The amount of Y token to deposit.\n * @param amountXInActiveBin The amount of X token in the active bin.\n * @param amountYInActiveBin The amount of Y token in the active bin.\n * @param strategyType The strategy type.\n * @param mintX The mint info of X token. Get from DLMM instance.\n * @param mintY The mint info of Y token. Get from DLMM instance.\n * @param clock The clock info. Get from DLMM instance.\n * @returns The distribution of liquidity.\n */\nexport function toAmountsBothSideByStrategy(\n  activeId: number,\n  binStep: number,\n  minBinId: number,\n  maxBinId: number,\n  amountX: BN,\n  amountY: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  strategyType: StrategyType,\n  mintX: Mint,\n  mintY: Mint,\n  clock: Clock\n): {\n  binId: number;\n  amountX: BN;\n  amountY: BN;\n}[] {\n  const isSingleSideX = amountY.isZero();\n  switch (strategyType) {\n    case StrategyType.Spot: {\n      if (activeId < minBinId || activeId > maxBinId) {\n        const weights = toWeightSpotBalanced(minBinId, maxBinId);\n        return toAmountBothSide(\n          activeId,\n          binStep,\n          amountX,\n          amountY,\n          amountXInActiveBin,\n          amountYInActiveBin,\n          weights,\n          mintX,\n          mintY,\n          clock\n        );\n      }\n      const amountsInBin = [];\n      if (!isSingleSideX) {\n        if (minBinId <= activeId) {\n          const weights = toWeightSpotBalanced(minBinId, activeId);\n          const amounts = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId < maxBinId) {\n          const weights = toWeightSpotBalanced(activeId + 1, maxBinId);\n          const amounts = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      } else {\n        if (minBinId < activeId) {\n          const weights = toWeightSpotBalanced(minBinId, activeId - 1);\n          const amountsIntoBidSide = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n          for (let bin of amountsIntoBidSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId <= maxBinId) {\n          const weights = toWeightSpotBalanced(activeId, maxBinId);\n          const amountsIntoAskSide = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amountsIntoAskSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      }\n      return amountsInBin;\n    }\n    case StrategyType.Curve: {\n      // ask side\n      if (activeId < minBinId) {\n        let weights = toWeightDescendingOrder(minBinId, maxBinId);\n        return toAmountBothSide(\n          activeId,\n          binStep,\n          amountX,\n          amountY,\n          amountXInActiveBin,\n          amountYInActiveBin,\n          weights,\n          mintX,\n          mintY,\n          clock\n        );\n      }\n      // bid side\n      if (activeId > maxBinId) {\n        const weights = toWeightAscendingOrder(minBinId, maxBinId);\n        return toAmountBothSide(\n          activeId,\n          binStep,\n          amountX,\n          amountY,\n          amountXInActiveBin,\n          amountYInActiveBin,\n          weights,\n          mintX,\n          mintY,\n          clock\n        );\n      }\n      const amountsInBin = [];\n      if (!isSingleSideX) {\n        if (minBinId <= activeId) {\n          const weights = toWeightAscendingOrder(minBinId, activeId);\n          const amounts = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId < maxBinId) {\n          const weights = toWeightDescendingOrder(activeId + 1, maxBinId);\n          const amounts = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      } else {\n        if (minBinId < activeId) {\n          const weights = toWeightAscendingOrder(minBinId, activeId - 1);\n          const amountsIntoBidSide = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n          for (let bin of amountsIntoBidSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId <= maxBinId) {\n          const weights = toWeightDescendingOrder(activeId, maxBinId);\n          const amountsIntoAskSide = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amountsIntoAskSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      }\n      return amountsInBin;\n    }\n    case StrategyType.BidAsk: {\n      // ask side\n      if (activeId < minBinId) {\n        const weights = toWeightAscendingOrder(minBinId, maxBinId);\n        return toAmountBothSide(\n          activeId,\n          binStep,\n          amountX,\n          amountY,\n          amountXInActiveBin,\n          amountYInActiveBin,\n          weights,\n          mintX,\n          mintY,\n          clock\n        );\n      }\n      // bid side\n      if (activeId > maxBinId) {\n        const weights = toWeightDescendingOrder(minBinId, maxBinId);\n        return toAmountBothSide(\n          activeId,\n          binStep,\n          amountX,\n          amountY,\n          amountXInActiveBin,\n          amountYInActiveBin,\n          weights,\n          mintX,\n          mintY,\n          clock\n        );\n      }\n      const amountsInBin = [];\n      if (!isSingleSideX) {\n        if (minBinId <= activeId) {\n          const weights = toWeightDescendingOrder(minBinId, activeId);\n          const amounts = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId < maxBinId) {\n          const weights = toWeightAscendingOrder(activeId + 1, maxBinId);\n          const amounts = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amounts) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      } else {\n        if (minBinId < activeId) {\n          const weights = toWeightDescendingOrder(minBinId, activeId - 1);\n          const amountsIntoBidSide = toAmountBidSide(\n            activeId,\n            amountY,\n            weights,\n            mintY,\n            clock\n          );\n          for (let bin of amountsIntoBidSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: new BN(0),\n              amountY: bin.amount,\n            });\n          }\n        }\n        if (activeId <= maxBinId) {\n          const weights = toWeightAscendingOrder(activeId, maxBinId);\n          const amountsIntoAskSide = toAmountAskSide(\n            activeId,\n            binStep,\n            amountX,\n            weights,\n            mintX,\n            clock\n          );\n          for (let bin of amountsIntoAskSide) {\n            amountsInBin.push({\n              binId: bin.binId,\n              amountX: bin.amount,\n              amountY: new BN(0),\n            });\n          }\n        }\n      }\n      return amountsInBin;\n    }\n  }\n}\n\n// only apply for\nexport function autoFillYByStrategy(\n  activeId: number,\n  binStep: number,\n  amountX: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  minBinId: number,\n  maxBinId: number,\n  strategyType: StrategyType\n): BN {\n  switch (strategyType) {\n    case StrategyType.Spot: {\n      let weights = toWeightSpotBalanced(minBinId, maxBinId);\n      return autoFillYByWeight(\n        activeId,\n        binStep,\n        amountX,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n    case StrategyType.Curve: {\n      let weights = toWeightCurve(minBinId, maxBinId, activeId);\n      return autoFillYByWeight(\n        activeId,\n        binStep,\n        amountX,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n    case StrategyType.BidAsk: {\n      let weights = toWeightBidAsk(minBinId, maxBinId, activeId);\n      return autoFillYByWeight(\n        activeId,\n        binStep,\n        amountX,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n  }\n}\n\n// only apply for balanced deposit\nexport function autoFillXByStrategy(\n  activeId: number,\n  binStep: number,\n  amountY: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  minBinId: number,\n  maxBinId: number,\n  strategyType: StrategyType\n): BN {\n  switch (strategyType) {\n    case StrategyType.Spot: {\n      let weights = toWeightSpotBalanced(minBinId, maxBinId);\n      return autoFillXByWeight(\n        activeId,\n        binStep,\n        amountY,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n    case StrategyType.Curve: {\n      let weights = toWeightCurve(minBinId, maxBinId, activeId);\n      return autoFillXByWeight(\n        activeId,\n        binStep,\n        amountY,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n    case StrategyType.BidAsk: {\n      let weights = toWeightBidAsk(minBinId, maxBinId, activeId);\n      return autoFillXByWeight(\n        activeId,\n        binStep,\n        amountY,\n        amountXInActiveBin,\n        amountYInActiveBin,\n        weights\n      );\n    }\n  }\n}\n\nexport function toStrategyParameters({\n  maxBinId,\n  minBinId,\n  strategyType,\n  singleSidedX,\n}: StrategyParameters): ProgramStrategyParameter {\n  // Favor ask = 1\n  const parameteres = new Array<number>(64).fill(0);\n  const favorSide = singleSidedX ? 1 : 0;\n  parameteres[0] = favorSide;\n\n  switch (strategyType) {\n    case StrategyType.Spot: {\n      return {\n        minBinId,\n        maxBinId,\n        strategyType: { spotImBalanced: {} },\n        parameteres,\n      };\n    }\n    case StrategyType.Curve: {\n      return {\n        minBinId,\n        maxBinId,\n        strategyType: { curveImBalanced: {} },\n        parameteres,\n      };\n    }\n    case StrategyType.BidAsk: {\n      return {\n        minBinId,\n        maxBinId,\n        strategyType: { bidAskImBalanced: {} },\n        parameteres,\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/token_2022.ts",
    "content": "import {\n  addExtraAccountMetasForExecute,\n  calculateFee,\n  createTransferCheckedInstruction,\n  getEpochFee,\n  getTransferFeeConfig,\n  getTransferHook,\n  MAX_FEE_BASIS_POINTS,\n  Mint,\n  TOKEN_2022_PROGRAM_ID,\n  TOKEN_PROGRAM_ID,\n  TransferFee,\n  unpackMint,\n} from \"@solana/spl-token\";\nimport {\n  AccountInfo,\n  AccountMeta,\n  Connection,\n  PublicKey,\n} from \"@solana/web3.js\";\nimport BN from \"bn.js\";\n\nexport async function getMultipleMintsExtraAccountMetasForTransferHook(\n  connection: Connection,\n  mintAddressesWithAccountInfo: {\n    mintAddress: PublicKey;\n    mintAccountInfo: AccountInfo<Buffer>;\n  }[]\n): Promise<Map<String, AccountMeta[]>> {\n  const extraAccountMetas = await Promise.all(\n    mintAddressesWithAccountInfo.map(({ mintAddress, mintAccountInfo }) =>\n      getExtraAccountMetasForTransferHook(\n        connection,\n        mintAddress,\n        mintAccountInfo\n      )\n    )\n  );\n\n  const mintsWithHookAccountMap = new Map<String, AccountMeta[]>();\n\n  for (let i = 0; i < extraAccountMetas.length; i++) {\n    const { mintAddress } = mintAddressesWithAccountInfo[i];\n    const transferHooks = extraAccountMetas[i];\n\n    mintsWithHookAccountMap.set(mintAddress.toBase58(), transferHooks);\n  }\n\n  return mintsWithHookAccountMap;\n}\n\nexport async function getExtraAccountMetasForTransferHook(\n  connection: Connection,\n  mintAddress: PublicKey,\n  mintAccountInfo: AccountInfo<Buffer>\n) {\n  if (\n    ![TOKEN_PROGRAM_ID.toBase58(), TOKEN_2022_PROGRAM_ID.toBase58()].includes(\n      mintAccountInfo.owner.toBase58()\n    )\n  ) {\n    return [];\n  }\n\n  const mintState = unpackMint(\n    mintAddress,\n    mintAccountInfo,\n    mintAccountInfo.owner\n  );\n\n  if (mintAccountInfo.owner.equals(TOKEN_PROGRAM_ID)) {\n    return [];\n  }\n\n  const transferHook = getTransferHook(mintState);\n\n  if (!transferHook || transferHook.programId.equals(PublicKey.default)) {\n    return [];\n  } else {\n    // We just need the instruction, therefore we do not need source and destination key\n    const instruction = createTransferCheckedInstruction(\n      PublicKey.default,\n      mintAddress,\n      PublicKey.default,\n      PublicKey.default,\n      BigInt(0),\n      mintState.decimals,\n      [],\n      mintAccountInfo.owner\n    );\n\n    await addExtraAccountMetasForExecute(\n      connection,\n      instruction,\n      transferHook.programId,\n      PublicKey.default,\n      mintAddress,\n      PublicKey.default,\n      PublicKey.default,\n      BigInt(0)\n    );\n\n    // Only 4 keys needed if it's single signer. https://github.com/solana-labs/solana-program-library/blob/d72289c79a04411c69a8bf1054f7156b6196f9b3/token/js/src/extensions/transferFee/instructions.ts#L251\n    const transferHookAccounts = instruction.keys.slice(4);\n\n    // Token 2022 program allow transfer hook program to be invoked without any accounts. https://github.com/solana-program/transfer-hook/blob/e00f3b5c591fd55b4aed6a1e9b1ccc502cb6da05/interface/src/onchain.rs#L37\n    if (transferHookAccounts.length == 0) {\n      transferHookAccounts.push({\n        pubkey: transferHook.programId,\n        isSigner: false,\n        isWritable: false,\n      });\n    }\n\n    return transferHookAccounts;\n  }\n}\n\nfunction calculatePreFeeAmount(transferFee: TransferFee, postFeeAmount: BN) {\n  if (postFeeAmount.isZero()) {\n    return new BN(0);\n  }\n\n  if (transferFee.transferFeeBasisPoints === 0) {\n    return postFeeAmount;\n  }\n\n  const maximumFee = new BN(transferFee.maximumFee.toString());\n\n  if (transferFee.transferFeeBasisPoints === MAX_FEE_BASIS_POINTS) {\n    return postFeeAmount.add(maximumFee);\n  }\n\n  const ONE_IN_BASIS_POINTS = new BN(MAX_FEE_BASIS_POINTS);\n  const numerator = postFeeAmount.mul(ONE_IN_BASIS_POINTS);\n  const denominator = ONE_IN_BASIS_POINTS.sub(\n    new BN(transferFee.transferFeeBasisPoints)\n  );\n\n  const rawPreFeeAmount = numerator\n    .add(denominator)\n    .sub(new BN(1))\n    .div(denominator);\n\n  if (rawPreFeeAmount.sub(postFeeAmount).gte(maximumFee)) {\n    return postFeeAmount.add(maximumFee);\n  }\n\n  return rawPreFeeAmount;\n}\n\nfunction calculateInverseFee(transferFee: TransferFee, postFeeAmount: BN) {\n  const preFeeAmount = calculatePreFeeAmount(transferFee, postFeeAmount);\n  return new BN(\n    calculateFee(transferFee, BigInt(preFeeAmount.toString())).toString()\n  );\n}\n\ninterface TransferFeeIncludedAmount {\n  amount: BN;\n  transferFee: BN;\n}\n\nexport function calculateTransferFeeIncludedAmount(\n  transferFeeExcludedAmount: BN,\n  mint: Mint,\n  currentEpoch: number\n): TransferFeeIncludedAmount {\n  if (transferFeeExcludedAmount.isZero()) {\n    return {\n      amount: new BN(0),\n      transferFee: new BN(0),\n    };\n  }\n\n  const transferFeeConfig = getTransferFeeConfig(mint);\n\n  if (transferFeeConfig === null) {\n    return {\n      amount: transferFeeExcludedAmount,\n      transferFee: new BN(0),\n    };\n  }\n\n  const epochFee = getEpochFee(transferFeeConfig, BigInt(currentEpoch));\n\n  const transferFee =\n    epochFee.transferFeeBasisPoints == MAX_FEE_BASIS_POINTS\n      ? new BN(epochFee.maximumFee.toString())\n      : calculateInverseFee(epochFee, transferFeeExcludedAmount);\n\n  const transferFeeIncludedAmount = transferFeeExcludedAmount.add(transferFee);\n\n  return {\n    amount: transferFeeIncludedAmount,\n    transferFee,\n  };\n}\n\ninterface TransferFeeExcludedAmount {\n  amount: BN;\n  transferFee: BN;\n}\n\nexport function calculateTransferFeeExcludedAmount(\n  transferFeeIncludedAmount: BN,\n  mint: Mint,\n  currentEpoch: number\n): TransferFeeExcludedAmount {\n  const transferFeeConfig = getTransferFeeConfig(mint);\n  if (transferFeeConfig === null) {\n    return {\n      amount: transferFeeIncludedAmount,\n      transferFee: new BN(0),\n    };\n  }\n\n  const transferFeeIncludedAmountN = BigInt(\n    transferFeeIncludedAmount.toString()\n  );\n\n  const transferFee = calculateFee(\n    getEpochFee(transferFeeConfig, BigInt(currentEpoch)),\n    transferFeeIncludedAmountN\n  );\n\n  const transferFeeExcludedAmount = new BN(\n    (transferFeeIncludedAmountN - transferFee).toString()\n  );\n\n  return {\n    amount: transferFeeExcludedAmount,\n    transferFee: new BN(transferFee.toString()),\n  };\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/u64xu64_math.ts",
    "content": "import BN from \"bn.js\";\nimport { SCALE_OFFSET } from \"../constants\";\n\nconst MAX_EXPONENTIAL = new BN(0x80000);\n\nexport const ONE = new BN(1).shln(SCALE_OFFSET);\nconst MAX = new BN(2).pow(new BN(128)).sub(new BN(1));\n\nexport function pow(base: BN, exp: BN): BN {\n  let invert = exp.isNeg();\n\n  if (exp.isZero()) {\n    return ONE;\n  }\n\n  exp = invert ? exp.abs() : exp;\n\n  if (exp.gt(MAX_EXPONENTIAL)) {\n    return new BN(0);\n  }\n\n  let squaredBase = base;\n  let result = ONE;\n\n  if (squaredBase.gte(result)) {\n    squaredBase = MAX.div(squaredBase);\n    invert = !invert;\n  }\n\n  if (!exp.and(new BN(0x1)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x2)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x4)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x8)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x10)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x20)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x40)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x80)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x100)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x200)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x400)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x800)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x1000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x2000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x4000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x8000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x10000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x20000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);\n\n  if (!exp.and(new BN(0x40000)).isZero()) {\n    result = result.mul(squaredBase).shrn(SCALE_OFFSET);\n  }\n\n  if (result.isZero()) {\n    return new BN(0);\n  }\n\n  if (invert) {\n    result = MAX.div(result);\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/weight.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport gaussian, { Gaussian } from \"gaussian\";\nimport { BASIS_POINT_MAX } from \"../constants\";\nimport Decimal from \"decimal.js\";\nimport {\n  toAmountAskSide,\n  toAmountBidSide,\n  toAmountBothSide,\n} from \"./weightToAmounts\";\nimport { Mint } from \"@solana/spl-token\";\nimport { Clock } from \"../types\";\n\nexport function getPriceOfBinByBinId(binId: number, binStep: number): Decimal {\n  const binStepNum = new Decimal(binStep).div(new Decimal(BASIS_POINT_MAX));\n  return new Decimal(1).add(new Decimal(binStepNum)).pow(new Decimal(binId));\n}\n\n/// Build a gaussian distribution from the bins, with active bin as the mean.\nfunction buildGaussianFromBins(activeBin: number, binIds: number[]) {\n  const smallestBin = Math.min(...binIds);\n  const largestBin = Math.max(...binIds);\n\n  // Define the Gaussian distribution. The mean will be active bin when active bin is within the bin ids. Else, use left or right most bin id as the mean.\n  let mean = 0;\n  const isAroundActiveBin = binIds.find((bid) => bid == activeBin);\n  // The liquidity will be distributed surrounding active bin\n  if (isAroundActiveBin) {\n    mean = activeBin;\n  }\n  // The liquidity will be distributed to the right side of the active bin.\n  else if (activeBin < smallestBin) {\n    mean = smallestBin;\n  }\n  // The liquidity will be distributed to the left side of the active bin.\n  else {\n    mean = largestBin;\n  }\n\n  const TWO_STANDARD_DEVIATION = 4;\n  const stdDev = (largestBin - smallestBin) / TWO_STANDARD_DEVIATION;\n  const variance = Math.max(stdDev ** 2, 1);\n\n  return gaussian(mean, variance);\n}\n\n/// Find the probability of the bin id over the gaussian. The probability ranged from 0 - 1 and will be used as liquidity allocation for that particular bin.\nfunction generateBinLiquidityAllocation(\n  gaussian: Gaussian,\n  binIds: number[],\n  invert: boolean\n) {\n  const allocations = binIds.map((bid) =>\n    invert ? 1 / gaussian.pdf(bid) : gaussian.pdf(bid)\n  );\n  const totalAllocations = allocations.reduce((acc, v) => acc + v, 0);\n  // Gaussian impossible to cover 100%, normalized it to have total of 100%\n  return allocations.map((a) => a / totalAllocations);\n}\n\n/// Convert liquidity allocation from 0..1 to 0..10000 bps unit. The sum of allocations must be 1. Return BPS and the loss after conversion.\nfunction computeAllocationBps(allocations: number[]): {\n  bpsAllocations: BN[];\n  pLoss: BN;\n} {\n  let totalAllocation = new BN(0);\n  const bpsAllocations: BN[] = [];\n\n  for (const allocation of allocations) {\n    const allocBps = new BN(allocation * 10000);\n    bpsAllocations.push(allocBps);\n    totalAllocation = totalAllocation.add(allocBps);\n  }\n\n  const pLoss = new BN(10000).sub(totalAllocation);\n  return {\n    bpsAllocations,\n    pLoss,\n  };\n}\n/** private */\n\nexport function toWeightDistribution(\n  amountX: BN,\n  amountY: BN,\n  distributions: {\n    binId: number;\n    xAmountBpsOfTotal: BN;\n    yAmountBpsOfTotal: BN;\n  }[],\n  binStep: number\n): { binId: number; weight: number }[] {\n  // get all quote amount\n  let totalQuote = new BN(0);\n  const precision = 1_000_000_000_000;\n  const quoteDistributions = distributions.map((bin) => {\n    const price = new BN(\n      getPriceOfBinByBinId(bin.binId, binStep).mul(precision).floor().toString()\n    );\n    const quoteValue = amountX\n      .mul(new BN(bin.xAmountBpsOfTotal))\n      .mul(new BN(price))\n      .div(new BN(BASIS_POINT_MAX))\n      .div(new BN(precision));\n    const quoteAmount = quoteValue.add(\n      amountY.mul(new BN(bin.yAmountBpsOfTotal)).div(new BN(BASIS_POINT_MAX))\n    );\n    totalQuote = totalQuote.add(quoteAmount);\n    return {\n      binId: bin.binId,\n      quoteAmount,\n    };\n  });\n\n  if (totalQuote.eq(new BN(0))) {\n    return [];\n  }\n\n  const distributionWeights = quoteDistributions\n    .map((bin) => {\n      const weight = Math.floor(\n        bin.quoteAmount.mul(new BN(65535)).div(totalQuote).toNumber()\n      );\n      return {\n        binId: bin.binId,\n        weight,\n      };\n    })\n    .filter((item) => item.weight > 0);\n\n  return distributionWeights;\n}\n\nexport function calculateSpotDistribution(\n  activeBin: number,\n  binIds: number[]\n): { binId: number; xAmountBpsOfTotal: BN; yAmountBpsOfTotal: BN }[] {\n  if (!binIds.includes(activeBin)) {\n    const { div: dist, mod: rem } = new BN(10_000).divmod(\n      new BN(binIds.length)\n    );\n    const loss = rem.isZero() ? new BN(0) : new BN(1);\n\n    const distributions =\n      binIds[0] < activeBin\n        ? binIds.map((binId) => ({\n            binId,\n            xAmountBpsOfTotal: new BN(0),\n            yAmountBpsOfTotal: dist,\n          }))\n        : binIds.map((binId) => ({\n            binId,\n            xAmountBpsOfTotal: dist,\n            yAmountBpsOfTotal: new BN(0),\n          }));\n\n    // Add the loss to the left most bin\n    if (binIds[0] < activeBin) {\n      distributions[0].yAmountBpsOfTotal.add(loss);\n    }\n    // Add the loss to the right most bin\n    else {\n      distributions[binIds.length - 1].xAmountBpsOfTotal.add(loss);\n    }\n\n    return distributions;\n  }\n\n  const binYCount = binIds.filter((binId) => binId < activeBin).length;\n  const binXCount = binIds.filter((binId) => binId > activeBin).length;\n\n  const totalYBinCapacity = binYCount + 0.5;\n  const totalXBinCapacity = binXCount + 0.5;\n\n  const yBinBps = new BN(10_000 / totalYBinCapacity);\n  const yActiveBinBps = new BN(10_000).sub(yBinBps.mul(new BN(binYCount)));\n\n  const xBinBps = new BN(10_000 / totalXBinCapacity);\n  const xActiveBinBps = new BN(10_000).sub(xBinBps.mul(new BN(binXCount)));\n\n  return binIds.map((binId) => {\n    const isYBin = binId < activeBin;\n    const isXBin = binId > activeBin;\n    const isActiveBin = binId === activeBin;\n\n    if (isYBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: new BN(0),\n        yAmountBpsOfTotal: yBinBps,\n      };\n    }\n\n    if (isXBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: xBinBps,\n        yAmountBpsOfTotal: new BN(0),\n      };\n    }\n\n    if (isActiveBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: xActiveBinBps,\n        yAmountBpsOfTotal: yActiveBinBps,\n      };\n    }\n  });\n}\n\nexport function calculateBidAskDistribution(\n  activeBin: number,\n  binIds: number[]\n): {\n  binId: number;\n  xAmountBpsOfTotal: BN;\n  yAmountBpsOfTotal: BN;\n}[] {\n  const smallestBin = Math.min(...binIds);\n  const largestBin = Math.max(...binIds);\n\n  const rightOnly = activeBin < smallestBin;\n  const leftOnly = activeBin > largestBin;\n\n  const gaussian = buildGaussianFromBins(activeBin, binIds);\n  const allocations = generateBinLiquidityAllocation(gaussian, binIds, true);\n\n  // To the right of active bin, liquidity distribution consists of only token X.\n  if (rightOnly) {\n    const { bpsAllocations, pLoss } = computeAllocationBps(allocations);\n    const binDistributions = binIds.map((bid, idx) => ({\n      binId: bid,\n      xAmountBpsOfTotal: bpsAllocations[idx],\n      yAmountBpsOfTotal: new BN(0),\n    }));\n    const idx = binDistributions.length - 1;\n    binDistributions[idx].xAmountBpsOfTotal =\n      binDistributions[idx].xAmountBpsOfTotal.add(pLoss);\n    return binDistributions;\n  }\n\n  // To the left of active bin, liquidity distribution consists of only token Y.\n  if (leftOnly) {\n    const { bpsAllocations, pLoss } = computeAllocationBps(allocations);\n    const binDistributions = binIds.map((bid, idx) => ({\n      binId: bid,\n      xAmountBpsOfTotal: new BN(0),\n      yAmountBpsOfTotal: bpsAllocations[idx],\n    }));\n    binDistributions[0].yAmountBpsOfTotal =\n      binDistributions[0].yAmountBpsOfTotal.add(pLoss);\n    return binDistributions;\n  }\n\n  // Find total X, and Y bps allocations for normalization.\n  const [totalXAllocation, totalYAllocation] = allocations.reduce(\n    ([xAcc, yAcc], allocation, idx) => {\n      const binId = binIds[idx];\n      if (binId > activeBin) {\n        return [xAcc + allocation, yAcc];\n      } else if (binId < activeBin) {\n        return [xAcc, yAcc + allocation];\n      } else {\n        const half = allocation / 2;\n        return [xAcc + half, yAcc + half];\n      }\n    },\n    [0, 0]\n  );\n\n  // Normalize and convert to BPS\n  const [normXAllocations, normYAllocations] = allocations.reduce<[BN[], BN[]]>(\n    ([xAllocations, yAllocations], allocation, idx) => {\n      const binId = binIds[idx];\n      if (binId > activeBin) {\n        const distX = new BN((allocation * 10000) / totalXAllocation);\n        xAllocations.push(distX);\n      }\n      if (binId < activeBin) {\n        const distY = new BN((allocation * 10000) / totalYAllocation);\n        yAllocations.push(distY);\n      }\n      if (binId == activeBin) {\n        const half = allocation / 2;\n        const distX = new BN((half * 10000) / totalXAllocation);\n        const distY = new BN((half * 10000) / totalYAllocation);\n        xAllocations.push(distX);\n        yAllocations.push(distY);\n      }\n      return [xAllocations, yAllocations];\n    },\n    [[], []]\n  );\n\n  const totalXNormAllocations = normXAllocations.reduce(\n    (acc, v) => acc.add(v),\n    new BN(0)\n  );\n  const totalYNormAllocations = normYAllocations.reduce(\n    (acc, v) => acc.add(v),\n    new BN(0)\n  );\n\n  const xPLoss = new BN(10000).sub(totalXNormAllocations);\n  const yPLoss = new BN(10000).sub(totalYNormAllocations);\n\n  const distributions = binIds.map((binId) => {\n    if (binId === activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: normXAllocations.shift(),\n        yAmountBpsOfTotal: normYAllocations.shift(),\n      };\n    }\n\n    if (binId > activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: normXAllocations.shift(),\n        yAmountBpsOfTotal: new BN(0),\n      };\n    }\n\n    if (binId < activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: new BN(0),\n        yAmountBpsOfTotal: normYAllocations.shift(),\n      };\n    }\n  });\n\n  if (!yPLoss.isZero()) {\n    distributions[0].yAmountBpsOfTotal =\n      distributions[0].yAmountBpsOfTotal.add(yPLoss);\n  }\n\n  if (!xPLoss.isZero()) {\n    const last = distributions.length - 1;\n    distributions[last].xAmountBpsOfTotal =\n      distributions[last].xAmountBpsOfTotal.add(xPLoss);\n  }\n\n  return distributions;\n}\n\nexport function calculateNormalDistribution(\n  activeBin: number,\n  binIds: number[]\n): {\n  binId: number;\n  xAmountBpsOfTotal: BN;\n  yAmountBpsOfTotal: BN;\n}[] {\n  const smallestBin = Math.min(...binIds);\n  const largestBin = Math.max(...binIds);\n\n  const rightOnly = activeBin < smallestBin;\n  const leftOnly = activeBin > largestBin;\n\n  const gaussian = buildGaussianFromBins(activeBin, binIds);\n  const allocations = generateBinLiquidityAllocation(gaussian, binIds, false);\n\n  // To the right of active bin, liquidity distribution consists of only token X.\n  if (rightOnly) {\n    const { bpsAllocations, pLoss } = computeAllocationBps(allocations);\n    const binDistributions = binIds.map((bid, idx) => ({\n      binId: bid,\n      xAmountBpsOfTotal: bpsAllocations[idx],\n      yAmountBpsOfTotal: new BN(0),\n    }));\n    // When contains only X token, bin closest to active bin will be index 0.\n    // Add back the precision loss\n    binDistributions[0].xAmountBpsOfTotal =\n      binDistributions[0].xAmountBpsOfTotal.add(pLoss);\n    return binDistributions;\n  }\n\n  // To the left of active bin, liquidity distribution consists of only token Y.\n  if (leftOnly) {\n    const { bpsAllocations, pLoss } = computeAllocationBps(allocations);\n    const binDistributions = binIds.map((bid, idx) => ({\n      binId: bid,\n      xAmountBpsOfTotal: new BN(0),\n      yAmountBpsOfTotal: bpsAllocations[idx],\n    }));\n    // When contains only Y token, bin closest to active bin will be last index.\n    // Add back the precision loss\n    const idx = binDistributions.length - 1;\n    binDistributions[idx].yAmountBpsOfTotal =\n      binDistributions[idx].yAmountBpsOfTotal.add(pLoss);\n    return binDistributions;\n  }\n\n  // The liquidity distribution consists of token X and Y. Allocations from gaussian only says how much liquidity percentage per bin over the full bin range.\n  // Normalize liquidity allocation percentage into X - 100%, Y - 100%.\n\n  // Find total X, and Y bps allocations for normalization.\n  const [totalXAllocation, totalYAllocation] = allocations.reduce(\n    ([xAcc, yAcc], allocation, idx) => {\n      const binId = binIds[idx];\n      if (binId > activeBin) {\n        return [xAcc + allocation, yAcc];\n      } else if (binId < activeBin) {\n        return [xAcc, yAcc + allocation];\n      } else {\n        const half = allocation / 2;\n        return [xAcc + half, yAcc + half];\n      }\n    },\n    [0, 0]\n  );\n\n  // Normalize and convert to BPS\n  const [normXAllocations, normYAllocations] = allocations.reduce(\n    ([xAllocations, yAllocations], allocation, idx) => {\n      const binId = binIds[idx];\n      if (binId > activeBin) {\n        const distX = new BN((allocation * 10000) / totalXAllocation);\n        xAllocations.push(distX);\n      }\n      if (binId < activeBin) {\n        const distY = new BN((allocation * 10000) / totalYAllocation);\n        yAllocations.push(distY);\n      }\n      return [xAllocations, yAllocations];\n    },\n    [[], []]\n  );\n\n  const normXActiveBinAllocation = normXAllocations.reduce(\n    (maxBps, bps) => maxBps.sub(bps),\n    new BN(10_000)\n  );\n  const normYActiveBinAllocation = normYAllocations.reduce(\n    (maxBps, bps) => maxBps.sub(bps),\n    new BN(10_000)\n  );\n\n  return binIds.map((binId) => {\n    if (binId === activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: normXActiveBinAllocation,\n        yAmountBpsOfTotal: normYActiveBinAllocation,\n      };\n    }\n\n    if (binId > activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: normXAllocations.shift(),\n        yAmountBpsOfTotal: new BN(0),\n      };\n    }\n\n    if (binId < activeBin) {\n      return {\n        binId,\n        xAmountBpsOfTotal: new BN(0),\n        yAmountBpsOfTotal: normYAllocations.shift(),\n      };\n    }\n  });\n}\n\n/**\n * Converts a weight distribution into token amounts for one side (either bid or ask).\n *\n * @param amount - The total amount of liquidity to distribute.\n * @param distributions - The array of weight distributions for each bin.\n * @param binStep - The step interval between bin ids.\n * @param activeId - The id of the active bin.\n * @param depositForY - Flag indicating if the deposit is for token Y (bid side).\n * @param mint - Mint information for the token. Mint Y if depositForY is true, else Mint X. Get from DLMM instance.\n * @param clock - Clock instance for the current epoch. Get from DLMM instance.\n * @returns An array of objects containing binId and amount for each bin.\n */\n\nexport function fromWeightDistributionToAmountOneSide(\n  amount: BN,\n  distributions: { binId: number; weight: number }[],\n  binStep: number,\n  activeId: number,\n  depositForY: boolean,\n  mint: Mint,\n  clock: Clock\n): { binId: number; amount: BN }[] {\n  if (depositForY) {\n    return toAmountBidSide(activeId, amount, distributions, mint, clock);\n  } else {\n    return toAmountAskSide(\n      activeId,\n      binStep,\n      amount,\n      distributions,\n      mint,\n      clock\n    );\n  }\n}\n\n/**\n * Converts a weight distribution into token amounts for both bid and ask sides.\n *\n * @param amountX - The total amount of token X to distribute.\n * @param amountY - The total amount of token Y to distribute.\n * @param distributions - The array of weight distributions for each bin.\n * @param binStep - The step interval between bin ids.\n * @param activeId - The id of the active bin.\n * @param amountXInActiveBin - The amount of token X in the active bin.\n * @param amountYInActiveBin - The amount of token Y in the active bin.\n * @param mintX - Mint information for token X. Get from DLMM instance.\n * @param mintY - Mint information for token Y. Get from DLMM instance.\n * @param clock - Clock instance for the current epoch. Get from DLMM instance.\n * @returns An array of objects containing binId, amountX, and amountY for each bin.\n */\nexport function fromWeightDistributionToAmount(\n  amountX: BN,\n  amountY: BN,\n  distributions: { binId: number; weight: number }[],\n  binStep: number,\n  activeId: number,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  mintX: Mint,\n  mintY: Mint,\n  clock: Clock\n): { binId: number; amountX: BN; amountY: BN }[] {\n  // sort distribution\n  var distributions = distributions.sort((n1, n2) => {\n    return n1.binId - n2.binId;\n  });\n\n  if (distributions.length == 0) {\n    return [];\n  }\n\n  // only bid side\n  if (activeId > distributions[distributions.length - 1].binId) {\n    let amounts = toAmountBidSide(\n      activeId,\n      amountY,\n      distributions,\n      mintY,\n      clock\n    );\n    return amounts.map((bin) => {\n      return {\n        binId: bin.binId,\n        amountX: new BN(0),\n        amountY: new BN(bin.amount.toString()),\n      };\n    });\n  }\n\n  // only ask side\n  if (activeId < distributions[0].binId) {\n    let amounts = toAmountAskSide(\n      activeId,\n      binStep,\n      amountX,\n      distributions,\n      mintX,\n      clock\n    );\n    return amounts.map((bin) => {\n      return {\n        binId: bin.binId,\n        amountX: new BN(bin.amount.toString()),\n        amountY: new BN(0),\n      };\n    });\n  }\n  return toAmountBothSide(\n    activeId,\n    binStep,\n    amountX,\n    amountY,\n    amountXInActiveBin,\n    amountYInActiveBin,\n    distributions,\n    mintX,\n    mintY,\n    clock\n  );\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/helpers/weightToAmounts.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport { Mint } from \"@solana/spl-token\";\nimport Decimal from \"decimal.js\";\nimport { Clock } from \"../types\";\nimport {\n  calculateTransferFeeExcludedAmount,\n  calculateTransferFeeIncludedAmount,\n} from \"./token_2022\";\nimport { getPriceOfBinByBinId } from \"./weight\";\n\n/**\n * Distribute totalAmount to all bid side bins according to given distributions.\n * @param activeId active bin id\n * @param totalAmount total amount of token Y to be distributed\n * @param distributions weight distribution of each bin\n * @param mintY mint of token Y, get from DLMM instance\n * @param clock clock of the program, for calculating transfer fee, get from DLMM instance\n * @returns array of {binId, amount} where amount is the amount of token Y in each bin\n */\nexport function toAmountBidSide(\n  activeId: number,\n  totalAmount: BN,\n  distributions: { binId: number; weight: number }[],\n  mintY: Mint,\n  clock: Clock\n): {\n  binId: number;\n  amount: BN;\n}[] {\n  totalAmount = calculateTransferFeeExcludedAmount(\n    totalAmount,\n    mintY,\n    clock.epoch.toNumber()\n  ).amount;\n\n  // get sum of weight\n  const totalWeight = distributions.reduce(function (sum, el) {\n    return el.binId > activeId ? sum : sum.add(el.weight); // skip all ask side\n  }, new Decimal(0));\n\n  if (totalWeight.cmp(new Decimal(0)) != 1) {\n    throw Error(\"Invalid parameteres\");\n  }\n  return distributions.map((bin) => {\n    if (bin.binId > activeId) {\n      return {\n        binId: bin.binId,\n        amount: new BN(0),\n      };\n    } else {\n      return {\n        binId: bin.binId,\n        amount: new BN(\n          new Decimal(totalAmount.toString())\n            .mul(new Decimal(bin.weight).div(totalWeight))\n            .floor()\n            .toString()\n        ),\n      };\n    }\n  });\n}\n\n/**\n * Distribute totalAmount to all ask side bins according to given distributions.\n * @param activeId active bin id\n * @param totalAmount total amount of token Y to be distributed\n * @param distributions weight distribution of each bin\n * @param mintX mint of token X, get from DLMM instance\n * @param clock clock of the program, for calculating transfer fee, get from DLMM instance\n * @returns array of {binId, amount} where amount is the amount of token X in each bin\n */\nexport function toAmountAskSide(\n  activeId: number,\n  binStep: number,\n  totalAmount: BN,\n  distributions: { binId: number; weight: number }[],\n  mintX: Mint,\n  clock: Clock\n): {\n  binId: number;\n  amount: BN;\n}[] {\n  totalAmount = calculateTransferFeeExcludedAmount(\n    totalAmount,\n    mintX,\n    clock.epoch.toNumber()\n  ).amount;\n\n  // get sum of weight\n  const totalWeight: Decimal = distributions.reduce(function (sum, el) {\n    if (el.binId < activeId) {\n      return sum;\n    } else {\n      const price = getPriceOfBinByBinId(el.binId, binStep);\n      const weightPerPrice = new Decimal(el.weight).div(price);\n      return sum.add(weightPerPrice);\n    }\n  }, new Decimal(0));\n\n  if (totalWeight.cmp(new Decimal(0)) != 1) {\n    throw Error(\"Invalid parameteres\");\n  }\n\n  return distributions.map((bin) => {\n    if (bin.binId < activeId) {\n      return {\n        binId: bin.binId,\n        amount: new BN(0),\n      };\n    } else {\n      const price = getPriceOfBinByBinId(bin.binId, binStep);\n      const weightPerPrice = new Decimal(bin.weight).div(price);\n      return {\n        binId: bin.binId,\n        amount: new BN(\n          new Decimal(totalAmount.toString())\n            .mul(weightPerPrice)\n            .div(totalWeight)\n            .floor()\n            .toString()\n        ),\n      };\n    }\n  });\n}\n\n/**\n * Distributes the given amounts of tokens X and Y to both bid and ask side bins\n * based on the provided weight distributions.\n *\n * @param activeId - The id of the active bin.\n * @param binStep - The step interval between bin ids.\n * @param amountX - Total amount of token X to distribute.\n * @param amountY - Total amount of token Y to distribute.\n * @param amountXInActiveBin - Amount of token X already in the active bin.\n * @param amountYInActiveBin - Amount of token Y already in the active bin.\n * @param distributions - Array of bins with their respective weight distributions.\n * @param mintX - Mint information for token X. Get from DLMM instance.\n * @param mintY - Mint information for token Y. Get from DLMM instance.\n * @param clock - Clock instance. Get from DLMM instance.\n * @returns An array of objects containing binId, amountX, and amountY for each bin.\n */\n\nexport function toAmountBothSide(\n  activeId: number,\n  binStep: number,\n  amountX: BN,\n  amountY: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  distributions: { binId: number; weight: number }[],\n  mintX: Mint,\n  mintY: Mint,\n  clock: Clock\n): {\n  binId: number;\n  amountX: BN;\n  amountY: BN;\n}[] {\n  // only bid side\n  if (activeId > distributions[distributions.length - 1].binId) {\n    let amounts = toAmountBidSide(\n      activeId,\n      amountY,\n      distributions,\n      mintY,\n      clock\n    );\n    return amounts.map((bin) => {\n      return {\n        binId: bin.binId,\n        amountX: new BN(0),\n        amountY: bin.amount,\n      };\n    });\n  }\n  // only ask side\n  if (activeId < distributions[0].binId) {\n    let amounts = toAmountAskSide(\n      activeId,\n      binStep,\n      amountX,\n      distributions,\n      mintX,\n      clock\n    );\n    return amounts.map((bin) => {\n      return {\n        binId: bin.binId,\n        amountX: bin.amount,\n        amountY: new BN(0),\n      };\n    });\n  }\n\n  amountX = calculateTransferFeeIncludedAmount(\n    amountX,\n    mintX,\n    clock.epoch.toNumber()\n  ).amount;\n\n  amountY = calculateTransferFeeIncludedAmount(\n    amountY,\n    mintY,\n    clock.epoch.toNumber()\n  ).amount;\n\n  const activeBins = distributions.filter((element) => {\n    return element.binId === activeId;\n  });\n\n  if (activeBins.length === 1) {\n    const p0 = getPriceOfBinByBinId(activeId, binStep);\n    let wx0 = new Decimal(0);\n    let wy0 = new Decimal(0);\n    const activeBin = activeBins[0];\n    if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {\n      wx0 = new Decimal(activeBin.weight).div(p0.mul(new Decimal(2)));\n      wy0 = new Decimal(activeBin.weight).div(new Decimal(2));\n    } else {\n      let amountXInActiveBinDec = new Decimal(amountXInActiveBin.toString());\n      let amountYInActiveBinDec = new Decimal(amountYInActiveBin.toString());\n\n      if (!amountXInActiveBin.isZero()) {\n        wx0 = new Decimal(activeBin.weight).div(\n          p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))\n        );\n      }\n      if (!amountYInActiveBin.isZero()) {\n        wy0 = new Decimal(activeBin.weight).div(\n          new Decimal(1).add(\n            p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)\n          )\n        );\n      }\n    }\n\n    let totalWeightX = wx0;\n    let totalWeightY = wy0;\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      }\n      if (element.binId > activeId) {\n        let price = getPriceOfBinByBinId(element.binId, binStep);\n        let weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n    const kx = new Decimal(amountX.toString()).div(totalWeightX);\n    const ky = new Decimal(amountY.toString()).div(totalWeightY);\n    let k = kx.lessThan(ky) ? kx : ky;\n    return distributions.map((bin) => {\n      if (bin.binId < activeId) {\n        const amount = k.mul(new Decimal(bin.weight));\n        return {\n          binId: bin.binId,\n          amountX: new BN(0),\n          amountY: new BN(amount.floor().toString()),\n        };\n      }\n      if (bin.binId > activeId) {\n        const price = getPriceOfBinByBinId(bin.binId, binStep);\n        const weighPerPrice = new Decimal(bin.weight).div(price);\n        const amount = k.mul(weighPerPrice);\n        return {\n          binId: bin.binId,\n          amountX: new BN(amount.floor().toString()),\n          amountY: new BN(0),\n        };\n      }\n\n      const amountXActiveBin = k.mul(wx0);\n      const amountYActiveBin = k.mul(wy0);\n      return {\n        binId: bin.binId,\n        amountX: new BN(amountXActiveBin.floor().toString()),\n        amountY: new BN(amountYActiveBin.floor().toString()),\n      };\n    });\n  } else {\n    let totalWeightX = new Decimal(0);\n    let totalWeightY = new Decimal(0);\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      } else {\n        let price = getPriceOfBinByBinId(element.binId, binStep);\n        let weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n\n    let kx = new Decimal(amountX.toString()).div(totalWeightX);\n    let ky = new Decimal(amountY.toString()).div(totalWeightY);\n    let k = kx.lessThan(ky) ? kx : ky;\n\n    return distributions.map((bin) => {\n      if (bin.binId < activeId) {\n        const amount = k.mul(new Decimal(bin.weight));\n        return {\n          binId: bin.binId,\n          amountX: new BN(0),\n          amountY: new BN(amount.floor().toString()),\n        };\n      } else {\n        let price = getPriceOfBinByBinId(bin.binId, binStep);\n        let weighPerPrice = new Decimal(bin.weight).div(price);\n        const amount = k.mul(weighPerPrice);\n        return {\n          binId: bin.binId,\n          amountX: new BN(amount.floor().toString()),\n          amountY: new BN(0),\n        };\n      }\n    });\n  }\n}\n\nexport function autoFillYByWeight(\n  activeId: number,\n  binStep: number,\n  amountX: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  distributions: { binId: number; weight: number }[]\n): BN {\n  const activeBins = distributions.filter((element) => {\n    return element.binId === activeId;\n  });\n\n  if (activeBins.length === 1) {\n    const p0 = getPriceOfBinByBinId(activeId, binStep);\n    let wx0 = new Decimal(0);\n    let wy0 = new Decimal(0);\n    const activeBin = activeBins[0];\n    if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {\n      wx0 = new Decimal(activeBin.weight).div(p0.mul(new Decimal(2)));\n      wy0 = new Decimal(activeBin.weight).div(new Decimal(2));\n    } else {\n      let amountXInActiveBinDec = new Decimal(amountXInActiveBin.toString());\n      let amountYInActiveBinDec = new Decimal(amountYInActiveBin.toString());\n\n      if (!amountXInActiveBin.isZero()) {\n        wx0 = new Decimal(activeBin.weight).div(\n          p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))\n        );\n      }\n      if (!amountYInActiveBin.isZero()) {\n        wy0 = new Decimal(activeBin.weight).div(\n          new Decimal(1).add(\n            p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)\n          )\n        );\n      }\n    }\n\n    let totalWeightX = wx0;\n    let totalWeightY = wy0;\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      }\n      if (element.binId > activeId) {\n        const price = getPriceOfBinByBinId(element.binId, binStep);\n        const weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n    const kx = totalWeightX.isZero()\n      ? new Decimal(1)\n      : new Decimal(amountX.toString()).div(totalWeightX);\n    const amountY = kx.mul(totalWeightY);\n    return new BN(amountY.floor().toString());\n  } else {\n    let totalWeightX = new Decimal(0);\n    let totalWeightY = new Decimal(0);\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      } else {\n        const price = getPriceOfBinByBinId(element.binId, binStep);\n        const weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n    const kx = totalWeightX.isZero()\n      ? new Decimal(1)\n      : new Decimal(amountX.toString()).div(totalWeightX);\n    const amountY = kx.mul(totalWeightY);\n    return new BN(amountY.floor().toString());\n  }\n}\n\nexport function autoFillXByWeight(\n  activeId: number,\n  binStep: number,\n  amountY: BN,\n  amountXInActiveBin: BN,\n  amountYInActiveBin: BN,\n  distributions: { binId: number; weight: number }[]\n): BN {\n  const activeBins = distributions.filter((element) => {\n    return element.binId === activeId;\n  });\n\n  if (activeBins.length === 1) {\n    const p0 = getPriceOfBinByBinId(activeId, binStep);\n    let wx0 = new Decimal(0);\n    let wy0 = new Decimal(0);\n    const activeBin = activeBins[0];\n    if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {\n      wx0 = new Decimal(activeBin.weight).div(p0.mul(new Decimal(2)));\n      wy0 = new Decimal(activeBin.weight).div(new Decimal(2));\n    } else {\n      let amountXInActiveBinDec = new Decimal(amountXInActiveBin.toString());\n      let amountYInActiveBinDec = new Decimal(amountYInActiveBin.toString());\n\n      if (!amountXInActiveBin.isZero()) {\n        wx0 = new Decimal(activeBin.weight).div(\n          p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))\n        );\n      }\n      if (!amountYInActiveBin.isZero()) {\n        wy0 = new Decimal(activeBin.weight).div(\n          new Decimal(1).add(\n            p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)\n          )\n        );\n      }\n    }\n\n    let totalWeightX = wx0;\n    let totalWeightY = wy0;\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      }\n      if (element.binId > activeId) {\n        const price = getPriceOfBinByBinId(element.binId, binStep);\n        const weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n    const ky = totalWeightY.isZero()\n      ? new Decimal(1)\n      : new Decimal(amountY.toString()).div(totalWeightY);\n    const amountX = ky.mul(totalWeightX);\n    return new BN(amountX.floor().toString());\n  } else {\n    let totalWeightX = new Decimal(0);\n    let totalWeightY = new Decimal(0);\n    distributions.forEach((element) => {\n      if (element.binId < activeId) {\n        totalWeightY = totalWeightY.add(new Decimal(element.weight));\n      } else {\n        const price = getPriceOfBinByBinId(element.binId, binStep);\n        const weighPerPrice = new Decimal(element.weight).div(price);\n        totalWeightX = totalWeightX.add(weighPerPrice);\n      }\n    });\n    const ky = totalWeightY.isZero()\n      ? new Decimal(1)\n      : new Decimal(amountY.toString()).div(totalWeightY);\n    const amountX = ky.mul(totalWeightX);\n    return new BN(amountX.floor().toString());\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/idl/idl.json",
    "content": "{\n  \"address\": \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\",\n  \"metadata\": {\n    \"name\": \"lb_clmm\",\n    \"version\": \"0.11.0\",\n    \"spec\": \"0.1.0\",\n    \"description\": \"Created with Anchor\"\n  },\n  \"instructions\": [\n    {\n      \"name\": \"add_liquidity\",\n      \"discriminator\": [\n        181,\n        157,\n        89,\n        67,\n        143,\n        182,\n        52,\n        72\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity2\",\n      \"discriminator\": [\n        228,\n        162,\n        78,\n        28,\n        70,\n        219,\n        116,\n        115\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameter\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy\",\n      \"discriminator\": [\n        7,\n        3,\n        150,\n        127,\n        148,\n        40,\n        61,\n        200\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategy\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy2\",\n      \"discriminator\": [\n        3,\n        221,\n        149,\n        218,\n        111,\n        141,\n        118,\n        213\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategy\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_strategy_one_side\",\n      \"discriminator\": [\n        41,\n        5,\n        238,\n        175,\n        100,\n        225,\n        6,\n        205\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByStrategyOneSide\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_by_weight\",\n      \"discriminator\": [\n        28,\n        140,\n        238,\n        99,\n        231,\n        162,\n        21,\n        149\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityParameterByWeight\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side\",\n      \"discriminator\": [\n        94,\n        155,\n        103,\n        151,\n        70,\n        95,\n        220,\n        165\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"LiquidityOneSideParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side_precise\",\n      \"discriminator\": [\n        161,\n        194,\n        103,\n        84,\n        171,\n        71,\n        250,\n        154\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"AddLiquiditySingleSidePreciseParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"add_liquidity_one_side_precise2\",\n      \"discriminator\": [\n        33,\n        51,\n        163,\n        201,\n        117,\n        98,\n        125,\n        231\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"liquidity_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"AddLiquiditySingleSidePreciseParameter2\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_fee\",\n      \"discriminator\": [\n        169,\n        32,\n        79,\n        137,\n        136,\n        232,\n        70,\n        137\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"claim_fee2\",\n      \"discriminator\": [\n        112,\n        191,\n        101,\n        171,\n        28,\n        144,\n        127,\n        187\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_reward\",\n      \"discriminator\": [\n        149,\n        95,\n        181,\n        242,\n        94,\n        90,\n        158,\n        162\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"user_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"claim_reward2\",\n      \"discriminator\": [\n        190,\n        3,\n        127,\n        119,\n        178,\n        87,\n        157,\n        183\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"user_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"close_claim_fee_operator_account\",\n      \"discriminator\": [\n        184,\n        213,\n        88,\n        31,\n        179,\n        101,\n        130,\n        36\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"claim_fee_operator\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_operator_account\",\n      \"discriminator\": [\n        171,\n        9,\n        213,\n        74,\n        120,\n        23,\n        3,\n        29\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"operator\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position\",\n      \"discriminator\": [\n        123,\n        134,\n        81,\n        0,\n        49,\n        68,\n        98,\n        98\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position2\",\n      \"discriminator\": [\n        174,\n        90,\n        35,\n        115,\n        186,\n        40,\n        147,\n        226\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_position_if_empty\",\n      \"discriminator\": [\n        59,\n        124,\n        212,\n        118,\n        91,\n        152,\n        110,\n        157\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_preset_parameter\",\n      \"discriminator\": [\n        4,\n        148,\n        145,\n        100,\n        134,\n        26,\n        181,\n        61\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_preset_parameter2\",\n      \"discriminator\": [\n        39,\n        25,\n        95,\n        107,\n        116,\n        17,\n        115,\n        28\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"close_token_badge\",\n      \"discriminator\": [\n        108,\n        146,\n        86,\n        110,\n        179,\n        254,\n        10,\n        104\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"token_badge\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"create_operator_account\",\n      \"discriminator\": [\n        221,\n        64,\n        246,\n        149,\n        240,\n        153,\n        229,\n        163\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"operator\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  112,\n                  101,\n                  114,\n                  97,\n                  116,\n                  111,\n                  114\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"whitelisted_signer\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"whitelisted_signer\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"permission\",\n          \"type\": \"u128\"\n        }\n      ]\n    },\n    {\n      \"name\": \"decrease_position_length\",\n      \"discriminator\": [\n        194,\n        219,\n        136,\n        32,\n        25,\n        96,\n        105,\n        37\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_remove\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"side\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"for_idl_type_generation_do_not_call\",\n      \"discriminator\": [\n        180,\n        105,\n        69,\n        80,\n        95,\n        50,\n        73,\n        108\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"dummy_zc_account\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"_ix\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"DummyIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"fund_reward\",\n      \"discriminator\": [\n        188,\n        50,\n        249,\n        165,\n        93,\n        151,\n        38,\n        63\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array\"\n          ]\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"funder_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"carry_forward\",\n          \"type\": \"bool\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"go_to_a_bin\",\n      \"discriminator\": [\n        146,\n        72,\n        174,\n        224,\n        40,\n        253,\n        84,\n        174\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\",\n            \"from_bin_array\",\n            \"to_bin_array\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"from_bin_array\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"to_bin_array\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_oracle_length\",\n      \"discriminator\": [\n        190,\n        61,\n        125,\n        87,\n        103,\n        79,\n        158,\n        173\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"oracle\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_add\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_position_length\",\n      \"discriminator\": [\n        80,\n        83,\n        117,\n        211,\n        66,\n        13,\n        33,\n        149\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"length_to_add\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"side\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"increase_position_length2\",\n      \"discriminator\": [\n        255,\n        210,\n        204,\n        71,\n        115,\n        137,\n        225,\n        113\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"minimum_upper_bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_bin_array\",\n      \"discriminator\": [\n        35,\n        86,\n        19,\n        185,\n        78,\n        212,\n        75,\n        211\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  110,\n                  95,\n                  97,\n                  114,\n                  114,\n                  97,\n                  121\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"index\",\n          \"type\": \"i64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_bin_array_bitmap_extension\",\n      \"discriminator\": [\n        47,\n        157,\n        226,\n        180,\n        12,\n        240,\n        33,\n        71\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"docs\": [\n            \"Initialize an account to store if a bin array is initialized.\"\n          ],\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"initialize_customizable_permissionless_lb_pair\",\n      \"discriminator\": [\n        46,\n        39,\n        41,\n        135,\n        111,\n        183,\n        200,\n        64\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  114,\n                  97,\n                  99,\n                  108,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"user_token_x\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"user_token_y\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"CustomizableParams\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_customizable_permissionless_lb_pair2\",\n      \"discriminator\": [\n        243,\n        73,\n        129,\n        126,\n        51,\n        19,\n        241,\n        107\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  114,\n                  97,\n                  99,\n                  108,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"user_token_x\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"user_token_y\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"CustomizableParams\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_lb_pair\",\n      \"discriminator\": [\n        45,\n        154,\n        237,\n        210,\n        221,\n        15,\n        166,\n        92\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  114,\n                  97,\n                  99,\n                  108,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"preset_parameter\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"active_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bin_step\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_lb_pair2\",\n      \"discriminator\": [\n        73,\n        59,\n        36,\n        120,\n        237,\n        83,\n        108,\n        198\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  114,\n                  97,\n                  99,\n                  108,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"preset_parameter\"\n        },\n        {\n          \"name\": \"funder\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitializeLbPair2Params\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_permission_lb_pair\",\n      \"discriminator\": [\n        108,\n        102,\n        213,\n        85,\n        251,\n        3,\n        53,\n        21\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  98,\n                  105,\n                  116,\n                  109,\n                  97,\n                  112\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"token_mint_x\"\n        },\n        {\n          \"name\": \"token_mint_y\"\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_x\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint_y\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  111,\n                  114,\n                  97,\n                  99,\n                  108,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_badge_x\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_badge_y\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"token_program_x\"\n        },\n        {\n          \"name\": \"token_program_y\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"ix_data\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitPermissionPairIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position\",\n      \"discriminator\": [\n        219,\n        192,\n        234,\n        71,\n        190,\n        191,\n        102,\n        80\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position2\",\n      \"discriminator\": [\n        143,\n        19,\n        242,\n        145,\n        213,\n        15,\n        104,\n        115\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position_by_operator\",\n      \"discriminator\": [\n        251,\n        189,\n        190,\n        244,\n        117,\n        254,\n        35,\n        148\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  112,\n                  111,\n                  115,\n                  105,\n                  116,\n                  105,\n                  111,\n                  110\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"base\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"lower_bin_id\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"width\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\"\n        },\n        {\n          \"name\": \"operator\",\n          \"docs\": [\n            \"operator\"\n          ],\n          \"signer\": true\n        },\n        {\n          \"name\": \"operator_token_x\"\n        },\n        {\n          \"name\": \"owner_token_x\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"fee_owner\",\n          \"type\": \"pubkey\"\n        },\n        {\n          \"name\": \"lock_release_point\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_position_pda\",\n      \"discriminator\": [\n        46,\n        82,\n        125,\n        146,\n        85,\n        141,\n        228,\n        153\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"base\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"position\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  112,\n                  111,\n                  115,\n                  105,\n                  116,\n                  105,\n                  111,\n                  110\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"base\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"lower_bin_id\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"width\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"owner\",\n          \"docs\": [\n            \"owner\"\n          ],\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"lower_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"width\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_preset_parameter\",\n      \"discriminator\": [\n        66,\n        188,\n        71,\n        211,\n        98,\n        109,\n        14,\n        186\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"preset_parameter\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  112,\n                  114,\n                  101,\n                  115,\n                  101,\n                  116,\n                  95,\n                  112,\n                  97,\n                  114,\n                  97,\n                  109,\n                  101,\n                  116,\n                  101,\n                  114,\n                  50\n                ]\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"ix.index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"ix\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"InitPresetParametersIx\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_reward\",\n      \"discriminator\": [\n        95,\n        135,\n        192,\n        196,\n        242,\n        129,\n        230,\n        68\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"account\",\n                \"path\": \"lb_pair\"\n              },\n              {\n                \"kind\": \"arg\",\n                \"path\": \"reward_index\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"token_badge\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"reward_duration\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"funder\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"initialize_token_badge\",\n      \"discriminator\": [\n        253,\n        77,\n        205,\n        95,\n        27,\n        224,\n        89,\n        223\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"token_badge\",\n          \"writable\": true,\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  116,\n                  111,\n                  107,\n                  101,\n                  110,\n                  95,\n                  98,\n                  97,\n                  100,\n                  103,\n                  101\n                ]\n              },\n              {\n                \"kind\": \"account\",\n                \"path\": \"token_mint\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"migrate_position\",\n      \"discriminator\": [\n        15,\n        132,\n        59,\n        50,\n        199,\n        6,\n        251,\n        46\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position_v2\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"position_v1\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\"\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer_and_payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"rent_receiver\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"rebalance_liquidity\",\n      \"discriminator\": [\n        92,\n        4,\n        176,\n        193,\n        119,\n        185,\n        83,\n        9\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"rent_payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"system_program\",\n          \"address\": \"11111111111111111111111111111111\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"params\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RebalanceLiquidityParams\"\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_all_liquidity\",\n      \"discriminator\": [\n        10,\n        51,\n        61,\n        35,\n        112,\n        105,\n        24,\n        85\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"remove_liquidity\",\n      \"discriminator\": [\n        80,\n        85,\n        209,\n        72,\n        24,\n        206,\n        177,\n        108\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_liquidity_removal\",\n          \"type\": {\n            \"vec\": {\n              \"defined\": {\n                \"name\": \"BinLiquidityReduction\"\n              }\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity2\",\n      \"discriminator\": [\n        230,\n        215,\n        82,\n        127,\n        241,\n        101,\n        227,\n        146\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"bin_liquidity_removal\",\n          \"type\": {\n            \"vec\": {\n              \"defined\": {\n                \"name\": \"BinLiquidityReduction\"\n              }\n            }\n          }\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity_by_range\",\n      \"discriminator\": [\n        26,\n        82,\n        102,\n        152,\n        240,\n        74,\n        105,\n        26\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"from_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"to_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bps_to_remove\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"remove_liquidity_by_range2\",\n      \"discriminator\": [\n        204,\n        2,\n        195,\n        145,\n        53,\n        145,\n        145,\n        205\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"sender\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"from_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"to_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"bps_to_remove\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"reset_bin_array_tombstone_fields\",\n      \"discriminator\": [\n        54,\n        90,\n        252,\n        63,\n        41,\n        206,\n        63,\n        63\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"relations\": [\n            \"bin_array\"\n          ]\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"reset_pool_tombstone_fields\",\n      \"discriminator\": [\n        246,\n        109,\n        19,\n        120,\n        108,\n        113,\n        68,\n        252\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"reset_position_tombstone_fields\",\n      \"discriminator\": [\n        206,\n        6,\n        51,\n        218,\n        211,\n        30,\n        159,\n        84\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"set_activation_point\",\n      \"discriminator\": [\n        91,\n        249,\n        15,\n        165,\n        26,\n        129,\n        254,\n        125\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"activation_point\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pair_status\",\n      \"discriminator\": [\n        67,\n        248,\n        231,\n        137,\n        154,\n        149,\n        217,\n        174\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"status\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pair_status_permissionless\",\n      \"discriminator\": [\n        78,\n        59,\n        152,\n        211,\n        70,\n        183,\n        46,\n        208\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"status\",\n          \"type\": \"u8\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pre_activation_duration\",\n      \"discriminator\": [\n        165,\n        61,\n        201,\n        244,\n        130,\n        159,\n        22,\n        100\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"pre_activation_duration\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"set_pre_activation_swap_address\",\n      \"discriminator\": [\n        57,\n        139,\n        47,\n        123,\n        216,\n        80,\n        223,\n        10\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"pre_activation_swap_address\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap\",\n      \"discriminator\": [\n        248,\n        198,\n        158,\n        145,\n        225,\n        117,\n        135,\n        200\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_amount_out\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap2\",\n      \"discriminator\": [\n        65,\n        75,\n        63,\n        76,\n        235,\n        91,\n        91,\n        136\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"min_amount_out\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_exact_out\",\n      \"discriminator\": [\n        250,\n        73,\n        101,\n        33,\n        38,\n        207,\n        75,\n        184\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_in_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"out_amount\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_exact_out2\",\n      \"discriminator\": [\n        43,\n        215,\n        247,\n        132,\n        137,\n        60,\n        243,\n        81\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_in_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"out_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_with_price_impact\",\n      \"discriminator\": [\n        56,\n        173,\n        230,\n        208,\n        173,\n        228,\n        156,\n        205\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"token_y_program\",\n          \"address\": \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"active_id\",\n          \"type\": {\n            \"option\": \"i32\"\n          }\n        },\n        {\n          \"name\": \"max_price_impact_bps\",\n          \"type\": \"u16\"\n        }\n      ]\n    },\n    {\n      \"name\": \"swap_with_price_impact2\",\n      \"discriminator\": [\n        74,\n        98,\n        192,\n        214,\n        177,\n        51,\n        75,\n        51\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array_bitmap_extension\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_bitmap_extension\",\n          \"optional\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"user_token_in\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"user_token_out\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"oracle\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"host_fee_in\",\n          \"writable\": true,\n          \"optional\": true\n        },\n        {\n          \"name\": \"user\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount_in\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"active_id\",\n          \"type\": {\n            \"option\": \"i32\"\n          }\n        },\n        {\n          \"name\": \"max_price_impact_bps\",\n          \"type\": \"u16\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_base_fee_parameters\",\n      \"discriminator\": [\n        75,\n        168,\n        223,\n        161,\n        16,\n        195,\n        3,\n        47\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"fee_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"BaseFeeParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_dynamic_fee_parameters\",\n      \"discriminator\": [\n        92,\n        161,\n        46,\n        246,\n        255,\n        189,\n        22,\n        22\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"fee_parameter\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"DynamicFeeParameter\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"update_fees_and_reward2\",\n      \"discriminator\": [\n        32,\n        142,\n        184,\n        154,\n        103,\n        65,\n        184,\n        88\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"min_bin_id\",\n          \"type\": \"i32\"\n        },\n        {\n          \"name\": \"max_bin_id\",\n          \"type\": \"i32\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_fees_and_rewards\",\n      \"discriminator\": [\n        154,\n        230,\n        250,\n        13,\n        236,\n        209,\n        75,\n        223\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"position\",\n            \"bin_array_lower\",\n            \"bin_array_upper\"\n          ]\n        },\n        {\n          \"name\": \"bin_array_lower\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"bin_array_upper\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"update_position_operator\",\n      \"discriminator\": [\n        202,\n        184,\n        103,\n        143,\n        180,\n        191,\n        116,\n        217\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"position\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"owner\",\n          \"signer\": true,\n          \"relations\": [\n            \"position\"\n          ]\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"operator\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_reward_duration\",\n      \"discriminator\": [\n        138,\n        174,\n        196,\n        169,\n        213,\n        235,\n        254,\n        107\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array\"\n          ]\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"new_duration\",\n          \"type\": \"u64\"\n        }\n      ]\n    },\n    {\n      \"name\": \"update_reward_funder\",\n      \"discriminator\": [\n        211,\n        28,\n        48,\n        32,\n        215,\n        160,\n        35,\n        23\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"new_funder\",\n          \"type\": \"pubkey\"\n        }\n      ]\n    },\n    {\n      \"name\": \"withdraw_ineligible_reward\",\n      \"discriminator\": [\n        148,\n        206,\n        42,\n        195,\n        247,\n        49,\n        103,\n        8\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true,\n          \"relations\": [\n            \"bin_array\"\n          ]\n        },\n        {\n          \"name\": \"reward_vault\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reward_mint\"\n        },\n        {\n          \"name\": \"funder_token_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"funder\",\n          \"signer\": true\n        },\n        {\n          \"name\": \"bin_array\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"memo_program\",\n          \"address\": \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"\n        },\n        {\n          \"name\": \"event_authority\",\n          \"pda\": {\n            \"seeds\": [\n              {\n                \"kind\": \"const\",\n                \"value\": [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"reward_index\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"withdraw_protocol_fee\",\n      \"discriminator\": [\n        158,\n        201,\n        158,\n        189,\n        33,\n        93,\n        162,\n        103\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve_x\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"reserve_y\",\n          \"writable\": true,\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_x_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"token_y_mint\",\n          \"relations\": [\n            \"lb_pair\"\n          ]\n        },\n        {\n          \"name\": \"receiver_token_x\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"receiver_token_y\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"docs\": [\n            \"operator\"\n          ],\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_x_program\"\n        },\n        {\n          \"name\": \"token_y_program\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_amount_x\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"max_amount_y\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"zap_protocol_fee\",\n      \"discriminator\": [\n        213,\n        155,\n        187,\n        34,\n        56,\n        182,\n        91,\n        240\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"lb_pair\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"reserve\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_mint\"\n        },\n        {\n          \"name\": \"receiver_token\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"operator\"\n        },\n        {\n          \"name\": \"signer\",\n          \"docs\": [\n            \"operator\"\n          ],\n          \"signer\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"sysvar_instructions\",\n          \"address\": \"Sysvar1nstructions1111111111111111111111111\"\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"max_amount\",\n          \"type\": \"u64\"\n        },\n        {\n          \"name\": \"remaining_accounts_info\",\n          \"type\": {\n            \"defined\": {\n              \"name\": \"RemainingAccountsInfo\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"accounts\": [\n    {\n      \"name\": \"BinArray\",\n      \"discriminator\": [\n        92,\n        142,\n        92,\n        220,\n        5,\n        148,\n        70,\n        181\n      ]\n    },\n    {\n      \"name\": \"BinArrayBitmapExtension\",\n      \"discriminator\": [\n        80,\n        111,\n        124,\n        113,\n        55,\n        237,\n        18,\n        5\n      ]\n    },\n    {\n      \"name\": \"ClaimFeeOperator\",\n      \"discriminator\": [\n        166,\n        48,\n        134,\n        86,\n        34,\n        200,\n        188,\n        150\n      ]\n    },\n    {\n      \"name\": \"DummyZcAccount\",\n      \"discriminator\": [\n        94,\n        107,\n        238,\n        80,\n        208,\n        48,\n        180,\n        8\n      ]\n    },\n    {\n      \"name\": \"LbPair\",\n      \"discriminator\": [\n        33,\n        11,\n        49,\n        98,\n        181,\n        101,\n        177,\n        13\n      ]\n    },\n    {\n      \"name\": \"Operator\",\n      \"discriminator\": [\n        219,\n        31,\n        188,\n        145,\n        69,\n        139,\n        204,\n        117\n      ]\n    },\n    {\n      \"name\": \"Oracle\",\n      \"discriminator\": [\n        139,\n        194,\n        131,\n        179,\n        140,\n        179,\n        229,\n        244\n      ]\n    },\n    {\n      \"name\": \"Position\",\n      \"discriminator\": [\n        170,\n        188,\n        143,\n        228,\n        122,\n        64,\n        247,\n        208\n      ]\n    },\n    {\n      \"name\": \"PositionV2\",\n      \"discriminator\": [\n        117,\n        176,\n        212,\n        199,\n        245,\n        180,\n        133,\n        182\n      ]\n    },\n    {\n      \"name\": \"PresetParameter\",\n      \"discriminator\": [\n        242,\n        62,\n        244,\n        34,\n        181,\n        112,\n        58,\n        170\n      ]\n    },\n    {\n      \"name\": \"PresetParameter2\",\n      \"discriminator\": [\n        171,\n        236,\n        148,\n        115,\n        162,\n        113,\n        222,\n        174\n      ]\n    },\n    {\n      \"name\": \"TokenBadge\",\n      \"discriminator\": [\n        116,\n        219,\n        204,\n        229,\n        249,\n        116,\n        255,\n        150\n      ]\n    }\n  ],\n  \"events\": [\n    {\n      \"name\": \"AddLiquidity\",\n      \"discriminator\": [\n        31,\n        94,\n        125,\n        90,\n        227,\n        52,\n        61,\n        186\n      ]\n    },\n    {\n      \"name\": \"ClaimFee\",\n      \"discriminator\": [\n        75,\n        122,\n        154,\n        48,\n        140,\n        74,\n        123,\n        163\n      ]\n    },\n    {\n      \"name\": \"ClaimFee2\",\n      \"discriminator\": [\n        232,\n        171,\n        242,\n        97,\n        58,\n        77,\n        35,\n        45\n      ]\n    },\n    {\n      \"name\": \"ClaimReward\",\n      \"discriminator\": [\n        148,\n        116,\n        134,\n        204,\n        22,\n        171,\n        85,\n        95\n      ]\n    },\n    {\n      \"name\": \"ClaimReward2\",\n      \"discriminator\": [\n        27,\n        143,\n        244,\n        33,\n        80,\n        43,\n        110,\n        146\n      ]\n    },\n    {\n      \"name\": \"CompositionFee\",\n      \"discriminator\": [\n        128,\n        151,\n        123,\n        106,\n        17,\n        102,\n        113,\n        142\n      ]\n    },\n    {\n      \"name\": \"DecreasePositionLength\",\n      \"discriminator\": [\n        52,\n        118,\n        235,\n        85,\n        172,\n        169,\n        15,\n        128\n      ]\n    },\n    {\n      \"name\": \"DynamicFeeParameterUpdate\",\n      \"discriminator\": [\n        88,\n        88,\n        178,\n        135,\n        194,\n        146,\n        91,\n        243\n      ]\n    },\n    {\n      \"name\": \"FeeParameterUpdate\",\n      \"discriminator\": [\n        48,\n        76,\n        241,\n        117,\n        144,\n        215,\n        242,\n        44\n      ]\n    },\n    {\n      \"name\": \"FundReward\",\n      \"discriminator\": [\n        246,\n        228,\n        58,\n        130,\n        145,\n        170,\n        79,\n        204\n      ]\n    },\n    {\n      \"name\": \"GoToABin\",\n      \"discriminator\": [\n        59,\n        138,\n        76,\n        68,\n        138,\n        131,\n        176,\n        67\n      ]\n    },\n    {\n      \"name\": \"IncreaseObservation\",\n      \"discriminator\": [\n        99,\n        249,\n        17,\n        121,\n        166,\n        156,\n        207,\n        215\n      ]\n    },\n    {\n      \"name\": \"IncreasePositionLength\",\n      \"discriminator\": [\n        157,\n        239,\n        42,\n        204,\n        30,\n        56,\n        223,\n        46\n      ]\n    },\n    {\n      \"name\": \"InitializeReward\",\n      \"discriminator\": [\n        211,\n        153,\n        88,\n        62,\n        149,\n        60,\n        177,\n        70\n      ]\n    },\n    {\n      \"name\": \"LbPairCreate\",\n      \"discriminator\": [\n        185,\n        74,\n        252,\n        125,\n        27,\n        215,\n        188,\n        111\n      ]\n    },\n    {\n      \"name\": \"PositionClose\",\n      \"discriminator\": [\n        255,\n        196,\n        16,\n        107,\n        28,\n        202,\n        53,\n        128\n      ]\n    },\n    {\n      \"name\": \"PositionCreate\",\n      \"discriminator\": [\n        144,\n        142,\n        252,\n        84,\n        157,\n        53,\n        37,\n        121\n      ]\n    },\n    {\n      \"name\": \"Rebalancing\",\n      \"discriminator\": [\n        0,\n        109,\n        117,\n        179,\n        61,\n        91,\n        199,\n        200\n      ]\n    },\n    {\n      \"name\": \"RemoveLiquidity\",\n      \"discriminator\": [\n        116,\n        244,\n        97,\n        232,\n        103,\n        31,\n        152,\n        58\n      ]\n    },\n    {\n      \"name\": \"Swap\",\n      \"discriminator\": [\n        81,\n        108,\n        227,\n        190,\n        205,\n        208,\n        10,\n        196\n      ]\n    },\n    {\n      \"name\": \"UpdatePositionLockReleasePoint\",\n      \"discriminator\": [\n        133,\n        214,\n        66,\n        224,\n        64,\n        12,\n        7,\n        191\n      ]\n    },\n    {\n      \"name\": \"UpdatePositionOperator\",\n      \"discriminator\": [\n        39,\n        115,\n        48,\n        204,\n        246,\n        47,\n        66,\n        57\n      ]\n    },\n    {\n      \"name\": \"UpdateRewardDuration\",\n      \"discriminator\": [\n        223,\n        245,\n        224,\n        153,\n        49,\n        29,\n        163,\n        172\n      ]\n    },\n    {\n      \"name\": \"UpdateRewardFunder\",\n      \"discriminator\": [\n        224,\n        178,\n        174,\n        74,\n        252,\n        165,\n        85,\n        180\n      ]\n    },\n    {\n      \"name\": \"WithdrawIneligibleReward\",\n      \"discriminator\": [\n        231,\n        189,\n        65,\n        149,\n        102,\n        215,\n        154,\n        244\n      ]\n    }\n  ],\n  \"errors\": [\n    {\n      \"code\": 6000,\n      \"name\": \"InvalidStartBinIndex\",\n      \"msg\": \"Invalid start bin index\"\n    },\n    {\n      \"code\": 6001,\n      \"name\": \"InvalidBinId\",\n      \"msg\": \"Invalid bin id\"\n    },\n    {\n      \"code\": 6002,\n      \"name\": \"InvalidInput\",\n      \"msg\": \"Invalid input data\"\n    },\n    {\n      \"code\": 6003,\n      \"name\": \"ExceededAmountSlippageTolerance\",\n      \"msg\": \"Exceeded amount slippage tolerance\"\n    },\n    {\n      \"code\": 6004,\n      \"name\": \"ExceededBinSlippageTolerance\",\n      \"msg\": \"Exceeded bin slippage tolerance\"\n    },\n    {\n      \"code\": 6005,\n      \"name\": \"CompositionFactorFlawed\",\n      \"msg\": \"Composition factor flawed\"\n    },\n    {\n      \"code\": 6006,\n      \"name\": \"NonPresetBinStep\",\n      \"msg\": \"Non preset bin step\"\n    },\n    {\n      \"code\": 6007,\n      \"name\": \"ZeroLiquidity\",\n      \"msg\": \"Zero liquidity\"\n    },\n    {\n      \"code\": 6008,\n      \"name\": \"InvalidPosition\",\n      \"msg\": \"Invalid position\"\n    },\n    {\n      \"code\": 6009,\n      \"name\": \"BinArrayNotFound\",\n      \"msg\": \"Bin array not found\"\n    },\n    {\n      \"code\": 6010,\n      \"name\": \"InvalidTokenMint\",\n      \"msg\": \"Invalid token mint\"\n    },\n    {\n      \"code\": 6011,\n      \"name\": \"InvalidAccountForSingleDeposit\",\n      \"msg\": \"Invalid account for single deposit\"\n    },\n    {\n      \"code\": 6012,\n      \"name\": \"PairInsufficientLiquidity\",\n      \"msg\": \"Pair insufficient liquidity\"\n    },\n    {\n      \"code\": 6013,\n      \"name\": \"InvalidFeeOwner\",\n      \"msg\": \"Invalid fee owner\"\n    },\n    {\n      \"code\": 6014,\n      \"name\": \"InvalidFeeWithdrawAmount\",\n      \"msg\": \"Invalid fee withdraw amount\"\n    },\n    {\n      \"code\": 6015,\n      \"name\": \"InvalidAdmin\",\n      \"msg\": \"Invalid admin\"\n    },\n    {\n      \"code\": 6016,\n      \"name\": \"IdenticalFeeOwner\",\n      \"msg\": \"Identical fee owner\"\n    },\n    {\n      \"code\": 6017,\n      \"name\": \"InvalidBps\",\n      \"msg\": \"Invalid basis point\"\n    },\n    {\n      \"code\": 6018,\n      \"name\": \"MathOverflow\",\n      \"msg\": \"Math operation overflow\"\n    },\n    {\n      \"code\": 6019,\n      \"name\": \"TypeCastFailed\",\n      \"msg\": \"Type cast error\"\n    },\n    {\n      \"code\": 6020,\n      \"name\": \"InvalidRewardIndex\",\n      \"msg\": \"Invalid reward index\"\n    },\n    {\n      \"code\": 6021,\n      \"name\": \"InvalidRewardDuration\",\n      \"msg\": \"Invalid reward duration\"\n    },\n    {\n      \"code\": 6022,\n      \"name\": \"RewardInitialized\",\n      \"msg\": \"Reward already initialized\"\n    },\n    {\n      \"code\": 6023,\n      \"name\": \"RewardUninitialized\",\n      \"msg\": \"Reward not initialized\"\n    },\n    {\n      \"code\": 6024,\n      \"name\": \"IdenticalFunder\",\n      \"msg\": \"Identical funder\"\n    },\n    {\n      \"code\": 6025,\n      \"name\": \"RewardCampaignInProgress\",\n      \"msg\": \"Reward campaign in progress\"\n    },\n    {\n      \"code\": 6026,\n      \"name\": \"IdenticalRewardDuration\",\n      \"msg\": \"Reward duration is the same\"\n    },\n    {\n      \"code\": 6027,\n      \"name\": \"InvalidBinArray\",\n      \"msg\": \"Invalid bin array\"\n    },\n    {\n      \"code\": 6028,\n      \"name\": \"NonContinuousBinArrays\",\n      \"msg\": \"Bin arrays must be continuous\"\n    },\n    {\n      \"code\": 6029,\n      \"name\": \"InvalidRewardVault\",\n      \"msg\": \"Invalid reward vault\"\n    },\n    {\n      \"code\": 6030,\n      \"name\": \"NonEmptyPosition\",\n      \"msg\": \"Position is not empty\"\n    },\n    {\n      \"code\": 6031,\n      \"name\": \"UnauthorizedAccess\",\n      \"msg\": \"Unauthorized access\"\n    },\n    {\n      \"code\": 6032,\n      \"name\": \"InvalidFeeParameter\",\n      \"msg\": \"Invalid fee parameter\"\n    },\n    {\n      \"code\": 6033,\n      \"name\": \"MissingOracle\",\n      \"msg\": \"Missing oracle account\"\n    },\n    {\n      \"code\": 6034,\n      \"name\": \"InsufficientSample\",\n      \"msg\": \"Insufficient observation sample\"\n    },\n    {\n      \"code\": 6035,\n      \"name\": \"InvalidLookupTimestamp\",\n      \"msg\": \"Invalid lookup timestamp\"\n    },\n    {\n      \"code\": 6036,\n      \"name\": \"BitmapExtensionAccountIsNotProvided\",\n      \"msg\": \"Bitmap extension account is not provided\"\n    },\n    {\n      \"code\": 6037,\n      \"name\": \"CannotFindNonZeroLiquidityBinArrayId\",\n      \"msg\": \"Cannot find non-zero liquidity binArrayId\"\n    },\n    {\n      \"code\": 6038,\n      \"name\": \"BinIdOutOfBound\",\n      \"msg\": \"Bin id out of bound\"\n    },\n    {\n      \"code\": 6039,\n      \"name\": \"InsufficientOutAmount\",\n      \"msg\": \"Insufficient amount in for minimum out\"\n    },\n    {\n      \"code\": 6040,\n      \"name\": \"InvalidPositionWidth\",\n      \"msg\": \"Invalid position width\"\n    },\n    {\n      \"code\": 6041,\n      \"name\": \"ExcessiveFeeUpdate\",\n      \"msg\": \"Excessive fee update\"\n    },\n    {\n      \"code\": 6042,\n      \"name\": \"PoolDisabled\",\n      \"msg\": \"Pool disabled\"\n    },\n    {\n      \"code\": 6043,\n      \"name\": \"InvalidPoolType\",\n      \"msg\": \"Invalid pool type\"\n    },\n    {\n      \"code\": 6044,\n      \"name\": \"ExceedMaxWhitelist\",\n      \"msg\": \"Whitelist for wallet is full\"\n    },\n    {\n      \"code\": 6045,\n      \"name\": \"InvalidIndex\",\n      \"msg\": \"Invalid index\"\n    },\n    {\n      \"code\": 6046,\n      \"name\": \"RewardNotEnded\",\n      \"msg\": \"Reward not ended\"\n    },\n    {\n      \"code\": 6047,\n      \"name\": \"MustWithdrawnIneligibleReward\",\n      \"msg\": \"Must withdraw ineligible reward\"\n    },\n    {\n      \"code\": 6048,\n      \"name\": \"UnauthorizedAddress\",\n      \"msg\": \"Unauthorized address\"\n    },\n    {\n      \"code\": 6049,\n      \"name\": \"OperatorsAreTheSame\",\n      \"msg\": \"Cannot update because operators are the same\"\n    },\n    {\n      \"code\": 6050,\n      \"name\": \"WithdrawToWrongTokenAccount\",\n      \"msg\": \"Withdraw to wrong token account\"\n    },\n    {\n      \"code\": 6051,\n      \"name\": \"WrongRentReceiver\",\n      \"msg\": \"Wrong rent receiver\"\n    },\n    {\n      \"code\": 6052,\n      \"name\": \"AlreadyPassActivationPoint\",\n      \"msg\": \"Already activated\"\n    },\n    {\n      \"code\": 6053,\n      \"name\": \"ExceedMaxSwappedAmount\",\n      \"msg\": \"Swapped amount is exceeded max swapped amount\"\n    },\n    {\n      \"code\": 6054,\n      \"name\": \"InvalidStrategyParameters\",\n      \"msg\": \"Invalid strategy parameters\"\n    },\n    {\n      \"code\": 6055,\n      \"name\": \"LiquidityLocked\",\n      \"msg\": \"Liquidity locked\"\n    },\n    {\n      \"code\": 6056,\n      \"name\": \"BinRangeIsNotEmpty\",\n      \"msg\": \"Bin range is not empty\"\n    },\n    {\n      \"code\": 6057,\n      \"name\": \"NotExactAmountOut\",\n      \"msg\": \"Amount out is not matched with exact amount out\"\n    },\n    {\n      \"code\": 6058,\n      \"name\": \"InvalidActivationType\",\n      \"msg\": \"Invalid activation type\"\n    },\n    {\n      \"code\": 6059,\n      \"name\": \"InvalidActivationDuration\",\n      \"msg\": \"Invalid activation duration\"\n    },\n    {\n      \"code\": 6060,\n      \"name\": \"MissingTokenAmountAsTokenLaunchProof\",\n      \"msg\": \"Missing token amount as token launch owner proof\"\n    },\n    {\n      \"code\": 6061,\n      \"name\": \"InvalidQuoteToken\",\n      \"msg\": \"Quote token must be SOL or USDC\"\n    },\n    {\n      \"code\": 6062,\n      \"name\": \"InvalidBinStep\",\n      \"msg\": \"Invalid bin step\"\n    },\n    {\n      \"code\": 6063,\n      \"name\": \"InvalidBaseFee\",\n      \"msg\": \"Invalid base fee\"\n    },\n    {\n      \"code\": 6064,\n      \"name\": \"InvalidPreActivationDuration\",\n      \"msg\": \"Invalid pre-activation duration\"\n    },\n    {\n      \"code\": 6065,\n      \"name\": \"AlreadyPassPreActivationSwapPoint\",\n      \"msg\": \"Already pass pre-activation swap point\"\n    },\n    {\n      \"code\": 6066,\n      \"name\": \"InvalidStatus\",\n      \"msg\": \"Invalid status\"\n    },\n    {\n      \"code\": 6067,\n      \"name\": \"ExceededMaxOracleLength\",\n      \"msg\": \"Exceed max oracle length\"\n    },\n    {\n      \"code\": 6068,\n      \"name\": \"InvalidMinimumLiquidity\",\n      \"msg\": \"Invalid minimum liquidity\"\n    },\n    {\n      \"code\": 6069,\n      \"name\": \"NotSupportMint\",\n      \"msg\": \"Not support token_2022 mint extension\"\n    },\n    {\n      \"code\": 6070,\n      \"name\": \"UnsupportedMintExtension\",\n      \"msg\": \"Unsupported mint extension\"\n    },\n    {\n      \"code\": 6071,\n      \"name\": \"UnsupportNativeMintToken2022\",\n      \"msg\": \"Unsupported native mint token2022\"\n    },\n    {\n      \"code\": 6072,\n      \"name\": \"UnmatchTokenMint\",\n      \"msg\": \"Unmatch token mint\"\n    },\n    {\n      \"code\": 6073,\n      \"name\": \"UnsupportedTokenMint\",\n      \"msg\": \"Unsupported token mint\"\n    },\n    {\n      \"code\": 6074,\n      \"name\": \"InsufficientRemainingAccounts\",\n      \"msg\": \"Insufficient remaining accounts\"\n    },\n    {\n      \"code\": 6075,\n      \"name\": \"InvalidRemainingAccountSlice\",\n      \"msg\": \"Invalid remaining account slice\"\n    },\n    {\n      \"code\": 6076,\n      \"name\": \"DuplicatedRemainingAccountTypes\",\n      \"msg\": \"Duplicated remaining account types\"\n    },\n    {\n      \"code\": 6077,\n      \"name\": \"MissingRemainingAccountForTransferHook\",\n      \"msg\": \"Missing remaining account for transfer hook\"\n    },\n    {\n      \"code\": 6078,\n      \"name\": \"NoTransferHookProgram\",\n      \"msg\": \"Remaining account was passed for transfer hook but there's no hook program\"\n    },\n    {\n      \"code\": 6079,\n      \"name\": \"ZeroFundedAmount\",\n      \"msg\": \"Zero funded amount\"\n    },\n    {\n      \"code\": 6080,\n      \"name\": \"InvalidSide\",\n      \"msg\": \"Invalid side\"\n    },\n    {\n      \"code\": 6081,\n      \"name\": \"InvalidResizeLength\",\n      \"msg\": \"Invalid resize length\"\n    },\n    {\n      \"code\": 6082,\n      \"name\": \"NotSupportAtTheMoment\",\n      \"msg\": \"Not support at the moment\"\n    },\n    {\n      \"code\": 6083,\n      \"name\": \"InvalidRebalanceParameters\",\n      \"msg\": \"Invalid rebalance parameters\"\n    },\n    {\n      \"code\": 6084,\n      \"name\": \"InvalidRewardAccounts\",\n      \"msg\": \"Invalid reward accounts\"\n    },\n    {\n      \"code\": 6085,\n      \"name\": \"UndeterminedError\",\n      \"msg\": \"Undetermined error\"\n    },\n    {\n      \"code\": 6086,\n      \"name\": \"ReallocExceedMaxLengthPerInstruction\",\n      \"msg\": \"Realloc exceed max length per instruction\"\n    },\n    {\n      \"code\": 6087,\n      \"name\": \"InvalidBaseFeeMantissa\",\n      \"msg\": \"Mantissa cannot more than two significant digits\"\n    },\n    {\n      \"code\": 6088,\n      \"name\": \"InvalidPositionOwner\",\n      \"msg\": \"Invalid position owner\"\n    },\n    {\n      \"code\": 6089,\n      \"name\": \"InvalidPoolAddress\",\n      \"msg\": \"Invalid pool address\"\n    },\n    {\n      \"code\": 6090,\n      \"name\": \"InvalidTokenBadgeType\",\n      \"msg\": \"Invalid token badge type\"\n    },\n    {\n      \"code\": 6091,\n      \"name\": \"InvalidTransferHookAuthority\",\n      \"msg\": \"Invalid transfer hook authority\"\n    },\n    {\n      \"code\": 6092,\n      \"name\": \"AmountXIsNegative\",\n      \"msg\": \"Amount x is negative\"\n    },\n    {\n      \"code\": 6093,\n      \"name\": \"AmountYIsNegative\",\n      \"msg\": \"Amount y is negative\"\n    },\n    {\n      \"code\": 6094,\n      \"name\": \"InvalidPoolCreator\",\n      \"msg\": \"Invalid pool creator\"\n    },\n    {\n      \"code\": 6095,\n      \"name\": \"InvalidFunctionType\",\n      \"msg\": \"Invalid function type\"\n    },\n    {\n      \"code\": 6096,\n      \"name\": \"InvalidPermission\",\n      \"msg\": \"Invalid permission\"\n    },\n    {\n      \"code\": 6097,\n      \"name\": \"IncorrectATA\",\n      \"msg\": \"Incorrect ATA\"\n    },\n    {\n      \"code\": 6098,\n      \"name\": \"InvalidWithdrawProtocolFeeZapAccounts\",\n      \"msg\": \"Invalid withdraw protocol fee zap accounts\"\n    },\n    {\n      \"code\": 6099,\n      \"name\": \"MintRestrictedFromZap\",\n      \"msg\": \"SOL,USDC protocol fee cannot be withdrawn via zap\"\n    },\n    {\n      \"code\": 6100,\n      \"name\": \"CpiDisabled\",\n      \"msg\": \"CPI disabled\"\n    },\n    {\n      \"code\": 6101,\n      \"name\": \"MissingZapOutInstruction\",\n      \"msg\": \"Missing zap out instruction\"\n    },\n    {\n      \"code\": 6102,\n      \"name\": \"InvalidZapAccounts\",\n      \"msg\": \"Invalid zap accounts\"\n    },\n    {\n      \"code\": 6103,\n      \"name\": \"InvalidZapOutParameters\",\n      \"msg\": \"Invalid zap out parameters\"\n    }\n  ],\n  \"types\": [\n    {\n      \"name\": \"AccountsType\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"TransferHookX\"\n          },\n          {\n            \"name\": \"TransferHookY\"\n          },\n          {\n            \"name\": \"TransferHookReward\"\n          },\n          {\n            \"name\": \"TransferHookMultiReward\",\n            \"fields\": [\n              \"u8\"\n            ]\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ActivationType\",\n      \"docs\": [\n        \"Type of the activation\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Slot\"\n          },\n          {\n            \"name\": \"Timestamp\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquidity\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amounts\",\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_delta_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_delta_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"x0\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y0\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"delta_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"delta_y\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"bit_flag\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"favor_x_in_active_id\",\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"padding\",\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                16\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquiditySingleSidePreciseParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"CompressedBinDepositAmount\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"decompress_multiplier\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"AddLiquiditySingleSidePreciseParameter2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"CompressedBinDepositAmount\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"decompress_multiplier\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BaseFeeParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Base factor for base fee rate\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\n              \"Base fee power factor\"\n            ],\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Bin\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\n              \"Amount of token X in the bin. This already excluded protocol fees.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\n              \"Amount of token Y in the bin. This already excluded protocol fees.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"price\",\n            \"docs\": [\n              \"Bin price\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"liquidity_supply\",\n            \"docs\": [\n              \"Liquidities of the bin. This is the same as LP mint supply. q-number\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"function_bytes\",\n            \"docs\": [\n              \"function bytes, could be used for liquidity mining or other functions in future\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u128\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"fee_amount_x_per_token_stored\",\n            \"docs\": [\n              \"Swap fee amount of token X per liquidity deposited.\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_amount_y_per_token_stored\",\n            \"docs\": [\n              \"Swap fee amount of token Y per liquidity deposited.\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"_padding_0\",\n            \"docs\": [\n              \"_padding_0, previous amount_x_in, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"docs\": [\n              \"_padding_1, previous amount_y_in, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u128\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinArray\",\n      \"docs\": [\n        \"An account to contain a range of bin. For example: Bin 100 <-> 200.\",\n        \"For example:\",\n        \"BinArray index: 0 contains bin 0 <-> 599\",\n        \"index: 2 contains bin 600 <-> 1199, ...\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"index\",\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"version\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                7\n              ]\n            }\n          },\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bins\",\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"Bin\"\n                  }\n                },\n                70\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinArrayBitmapExtension\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"positive_bin_array_bitmap\",\n            \"docs\": [\n              \"Packed initialized bin array state for start_bin_index is positive\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"array\": [\n                    \"u64\",\n                    8\n                  ]\n                },\n                12\n              ]\n            }\n          },\n          {\n            \"name\": \"negative_bin_array_bitmap\",\n            \"docs\": [\n              \"Packed initialized bin array state for start_bin_index is negative\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"array\": [\n                    \"u64\",\n                    8\n                  ]\n                },\n                12\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityDistribution\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"docs\": [\n              \"Define the bin ID wish to deposit to.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"distribution_x\",\n            \"docs\": [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"distribution_y\",\n            \"docs\": [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityDistributionByWeight\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"docs\": [\n              \"Define the bin ID wish to deposit to.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"weight\",\n            \"docs\": [\n              \"weight of liquidity distributed for this bin id\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"BinLiquidityReduction\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bps_to_remove\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFee\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"fee_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFee2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"fee_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimFeeOperator\",\n      \"docs\": [\n        \"Parameter that set by the protocol\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"operator\",\n            \"docs\": [\n              \"operator\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\n              \"Reserve\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                128\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_reward\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ClaimReward2\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_reward\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CompositionFee\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i16\"\n          },\n          {\n            \"name\": \"token_x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"token_y_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_token_x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_token_y_fee_amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CompressedBinDepositAmount\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"CustomizableParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Pool price\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\n              \"Bin step\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Base factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"activation_type\",\n            \"docs\": [\n              \"Activation type. 0 = Slot, 1 = Time. Check ActivationType enum\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"has_alpha_vault\",\n            \"docs\": [\n              \"Whether the pool has an alpha vault\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"activation_point\",\n            \"docs\": [\n              \"Decide when does the pool start trade. None = Now\"\n            ],\n            \"type\": {\n              \"option\": \"u64\"\n            }\n          },\n          {\n            \"name\": \"creator_pool_on_off_control\",\n            \"docs\": [\n              \"Pool creator have permission to enable/disable pool with restricted program validation. Only applicable for customizable permissionless pool.\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\n              \"Base fee power factor\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"function_type\",\n            \"docs\": [\n              \"function type\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\n              \"Padding, for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                61\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DecreasePositionLength\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"length_to_remove\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"side\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DummyIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"_pair_status\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PairStatus\"\n              }\n            }\n          },\n          {\n            \"name\": \"_pair_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PairType\"\n              }\n            }\n          },\n          {\n            \"name\": \"_activation_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ActivationType\"\n              }\n            }\n          },\n          {\n            \"name\": \"_token_program_flag\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"TokenProgramFlags\"\n              }\n            }\n          },\n          {\n            \"name\": \"_resize_side\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ResizeSide\"\n              }\n            }\n          },\n          {\n            \"name\": \"_rounding\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"Rounding\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DummyZcAccount\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position_bin_data\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"PositionBinData\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DynamicFeeParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"DynamicFeeParameterUpdate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FeeInfo\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"fee_x_per_token_complete\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_y_per_token_complete\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"fee_x_pending\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_y_pending\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FeeParameterUpdate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"FundReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"GoToABin\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"to_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"IncreaseObservation\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"oracle\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_observation_length\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"IncreasePositionLength\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"length_to_add\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"side\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitPermissionPairIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"activation_type\",\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitPresetParametersIx\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"index\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\n              \"Bin step. Represent the price increment / decrement.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\n              \"Base fee power factor\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"function_type\",\n            \"docs\": [\n              \"function type\"\n            ],\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitializeLbPair2Params\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Pool price\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\n              \"Padding, for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                96\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"InitializeReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_mint\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_duration\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LbPair\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"parameters\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StaticParameters\"\n              }\n            }\n          },\n          {\n            \"name\": \"v_parameters\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"VariableParameters\"\n              }\n            }\n          },\n          {\n            \"name\": \"bump_seed\",\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                1\n              ]\n            }\n          },\n          {\n            \"name\": \"bin_step_seed\",\n            \"docs\": [\n              \"Bin step signer seed\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"pair_type\",\n            \"docs\": [\n              \"Type of the pair\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Active bin id\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\n              \"Bin step. Represent the price increment / decrement.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"status\",\n            \"docs\": [\n              \"Status of the pair. Check PairStatus enum.\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"require_base_factor_seed\",\n            \"docs\": [\n              \"Require base factor seed\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"base_factor_seed\",\n            \"docs\": [\n              \"Base factor seed\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"activation_type\",\n            \"docs\": [\n              \"Activation type\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"creator_pool_on_off_control\",\n            \"docs\": [\n              \"Allow pool creator to enable/disable pool with restricted validation. Only applicable for customizable permissionless pair type.\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"token_x_mint\",\n            \"docs\": [\n              \"Token X mint\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_y_mint\",\n            \"docs\": [\n              \"Token Y mint\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reserve_x\",\n            \"docs\": [\n              \"LB token X vault\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reserve_y\",\n            \"docs\": [\n              \"LB token Y vault\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"protocol_fee\",\n            \"docs\": [\n              \"Uncollected protocol fee\"\n            ],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"ProtocolFee\"\n              }\n            }\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"docs\": [\n              \"_padding_1, previous Fee owner, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                32\n              ]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\n              \"Farming reward information\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"RewardInfo\"\n                  }\n                },\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"oracle\",\n            \"docs\": [\n              \"Oracle pubkey\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_array_bitmap\",\n            \"docs\": [\n              \"Packed initialized bin array state\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                16\n              ]\n            }\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\n              \"Last time the pool fee parameter was updated\"\n            ],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"_padding_2\",\n            \"docs\": [\n              \"_padding_2, previous whitelisted_wallet, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                32\n              ]\n            }\n          },\n          {\n            \"name\": \"pre_activation_swap_address\",\n            \"docs\": [\n              \"Address allowed to swap when the current point is greater than or equal to the pre-activation point. The pre-activation point is calculated as `activation_point - pre_activation_duration`.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"base_key\",\n            \"docs\": [\n              \"Base keypair. Only required for permission pair\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"activation_point\",\n            \"docs\": [\n              \"Time point to enable the pair. Only applicable for permission pair.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"pre_activation_duration\",\n            \"docs\": [\n              \"Duration before activation activation_point. Used to calculate pre-activation time point for pre_activation_swap_address\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"_padding_3\",\n            \"docs\": [\n              \"_padding 3 is reclaimed free space from swap_cap_deactivate_point and swap_cap_amount before, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                8\n              ]\n            }\n          },\n          {\n            \"name\": \"_padding_4\",\n            \"docs\": [\n              \"_padding_4, previous lock_duration, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"creator\",\n            \"docs\": [\n              \"Pool creator\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_mint_x_program_flag\",\n            \"docs\": [\n              \"token_mint_x_program_flag\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"token_mint_y_program_flag\",\n            \"docs\": [\n              \"token_mint_y_program_flag\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"version\",\n            \"docs\": [\n              \"version to know whether we have reset tombstone fields\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\n              \"Reserved space for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                21\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LbPairCreate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"bin_step\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"token_x\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"token_y\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityOneSideParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount\",\n            \"docs\": [\n              \"Amount of X token or Y token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Active bin that integrator observe off-chain\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\n              \"max active bin slippage allowed\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\n              \"Liquidity distribution to each bins\"\n            ],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistributionByWeight\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\n              \"Amount of X token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\n              \"Amount of Y token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\n              \"Liquidity distribution to each bins\"\n            ],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistribution\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByStrategy\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\n              \"Amount of X token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\n              \"Amount of Y token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Active bin that integrator observe off-chain\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\n              \"max active bin slippage allowed\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_parameters\",\n            \"docs\": [\n              \"strategy parameters\"\n            ],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyParameters\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByStrategyOneSide\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount\",\n            \"docs\": [\n              \"Amount of X token or Y token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Active bin that integrator observe off-chain\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\n              \"max active bin slippage allowed\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_parameters\",\n            \"docs\": [\n              \"strategy parameters\"\n            ],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyParameters\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"LiquidityParameterByWeight\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"docs\": [\n              \"Amount of X token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"docs\": [\n              \"Amount of Y token to deposit\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"Active bin that integrator observe off-chain\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\n              \"max active bin slippage allowed\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"bin_liquidity_dist\",\n            \"docs\": [\n              \"Liquidity distribution to each bins\"\n            ],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"BinLiquidityDistributionByWeight\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Operator\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"signer\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"permission\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"padding\",\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Oracle\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"idx\",\n            \"docs\": [\n              \"Index of latest observation\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"active_size\",\n            \"docs\": [\n              \"Size of active sample. Active sample is initialized observation.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"length\",\n            \"docs\": [\n              \"Number of observations\"\n            ],\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PairStatus\",\n      \"docs\": [\n        \"Pair status. 0 = Enabled, 1 = Disabled. Putting 0 as enabled for backward compatibility.\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Enabled\"\n          },\n          {\n            \"name\": \"Disabled\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PairType\",\n      \"docs\": [\n        \"Type of the Pair. 0 = Permissionless, 1 = Permission, 2 = CustomizablePermissionless. Putting 0 as permissionless for backward compatibility.\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Permissionless\"\n          },\n          {\n            \"name\": \"Permission\"\n          },\n          {\n            \"name\": \"CustomizablePermissionless\"\n          },\n          {\n            \"name\": \"PermissionlessV2\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Position\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"docs\": [\n              \"The LB pair of this position\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"docs\": [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"liquidity_shares\",\n            \"docs\": [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\n              \"Farming reward information\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"UserRewardInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"fee_infos\",\n            \"docs\": [\n              \"Swap fee to claim information\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"FeeInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"lower_bin_id\",\n            \"docs\": [\n              \"Lower bin ID\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"upper_bin_id\",\n            \"docs\": [\n              \"Upper bin ID\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\n              \"Last updated timestamp\"\n            ],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_x_amount\",\n            \"docs\": [\n              \"Total claimed token fee X\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_y_amount\",\n            \"docs\": [\n              \"Total claimed token fee Y\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_rewards\",\n            \"docs\": [\n              \"Total claimed rewards\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\n              \"Reserved space for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                160\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionBinData\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"liquidity_share\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"reward_info\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"UserRewardInfo\"\n              }\n            }\n          },\n          {\n            \"name\": \"fee_info\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"FeeInfo\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionClose\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionCreate\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PositionV2\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"docs\": [\n              \"The LB pair of this position\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"docs\": [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"liquidity_shares\",\n            \"docs\": [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u128\",\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"reward_infos\",\n            \"docs\": [\n              \"Farming reward information\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"UserRewardInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"fee_infos\",\n            \"docs\": [\n              \"Swap fee to claim information\"\n            ],\n            \"type\": {\n              \"array\": [\n                {\n                  \"defined\": {\n                    \"name\": \"FeeInfo\"\n                  }\n                },\n                70\n              ]\n            }\n          },\n          {\n            \"name\": \"lower_bin_id\",\n            \"docs\": [\n              \"Lower bin ID\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"upper_bin_id\",\n            \"docs\": [\n              \"Upper bin ID\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"last_updated_at\",\n            \"docs\": [\n              \"Last updated timestamp\"\n            ],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_x_amount\",\n            \"docs\": [\n              \"Total claimed token fee X\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_fee_y_amount\",\n            \"docs\": [\n              \"Total claimed token fee Y\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"total_claimed_rewards\",\n            \"docs\": [\n              \"Total claimed rewards\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"operator\",\n            \"docs\": [\n              \"Operator of position\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"lock_release_point\",\n            \"docs\": [\n              \"Time point which the locked liquidity can be withdraw\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"_padding_0\",\n            \"docs\": [\n              \"_padding_0, previous subjected_to_bootstrap_liquidity_locking, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"fee_owner\",\n            \"docs\": [\n              \"Address is able to claim fee in this position, only valid for bootstrap_liquidity_position\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"version\",\n            \"docs\": [\n              \"version to know whether we have reset tombstone fields\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_reserved\",\n            \"docs\": [\n              \"Reserved space for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                86\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PresetParameter\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\n              \"Bin step. Represent the price increment / decrement.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"PresetParameter2\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"bin_step\",\n            \"docs\": [\n              \"Bin step. Represent the price increment / decrement.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"index\",\n            \"docs\": [\n              \"index\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\n              \"Base fee power factor\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"function_type\",\n            \"docs\": [\n              \"function type, to check whether the pool should have LM farming or other functions in the future, refer FunctionType\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding_1\",\n            \"docs\": [\n              \"Padding 1 for future use\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                20\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ProtocolFee\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"amount_x\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_y\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RebalanceLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"active_id\",\n            \"docs\": [\n              \"active id\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_active_bin_slippage\",\n            \"docs\": [\n              \"max active bin slippage allowed\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"should_claim_fee\",\n            \"docs\": [\n              \"a flag to indicate that whether fee should be harvested\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"should_claim_reward\",\n            \"docs\": [\n              \"a flag to indicate that whether rewards should be harvested\"\n            ],\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"min_withdraw_x_amount\",\n            \"docs\": [\n              \"threshold for withdraw token x\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_deposit_x_amount\",\n            \"docs\": [\n              \"threshold for deposit token x\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"min_withdraw_y_amount\",\n            \"docs\": [\n              \"threshold for withdraw token y\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"max_deposit_y_amount\",\n            \"docs\": [\n              \"threshold for deposit token y\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"shrink_mode\",\n            \"docs\": [\n              \"shrink mode\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"padding\",\n            \"docs\": [\n              \"padding 32 bytes for future usage\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                31\n              ]\n            }\n          },\n          {\n            \"name\": \"removes\",\n            \"docs\": [\n              \"removes\"\n            ],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"RemoveLiquidityParams\"\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"adds\",\n            \"docs\": [\n              \"adds\"\n            ],\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"AddLiquidityParams\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Rebalancing\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"owner\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"x_withdrawn_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"x_added_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_withdrawn_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_added_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"x_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"y_fee_amount\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_min_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"old_max_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"new_min_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"new_max_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"rewards\",\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemainingAccountsInfo\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"slices\",\n            \"type\": {\n              \"vec\": {\n                \"defined\": {\n                  \"name\": \"RemainingAccountsSlice\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemainingAccountsSlice\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"accounts_type\",\n            \"type\": {\n              \"defined\": {\n                \"name\": \"AccountsType\"\n              }\n            }\n          },\n          {\n            \"name\": \"length\",\n            \"type\": \"u8\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemoveLiquidity\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amounts\",\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"active_bin_id\",\n            \"type\": \"i32\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RemoveLiquidityParams\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_bin_id\",\n            \"type\": {\n              \"option\": \"i32\"\n            }\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"type\": {\n              \"option\": \"i32\"\n            }\n          },\n          {\n            \"name\": \"bps\",\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"padding\",\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                16\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"ResizeSide\",\n      \"docs\": [\n        \"Side of resize, 0 for lower and 1 for upper\"\n      ],\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Lower\"\n          },\n          {\n            \"name\": \"Upper\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"RewardInfo\",\n      \"docs\": [\n        \"Stores the state relevant for tracking liquidity mining rewards\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"mint\",\n            \"docs\": [\n              \"Reward token mint.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"vault\",\n            \"docs\": [\n              \"Reward vault token account.\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"funder\",\n            \"docs\": [\n              \"Authority account that allows to fund rewards\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_duration\",\n            \"docs\": [\n              \"LM reward duration in seconds.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_duration_end\",\n            \"docs\": [\n              \"LM reward duration end time.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"reward_rate\",\n            \"docs\": [\n              \"LM reward rate\"\n            ],\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"last_update_time\",\n            \"docs\": [\n              \"The last time reward states were updated.\"\n            ],\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"cumulative_seconds_with_empty_liquidity_reward\",\n            \"docs\": [\n              \"Accumulated seconds where when farm distribute rewards, but the bin is empty. The reward will be accumulated for next reward time window.\"\n            ],\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Rounding\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"Up\"\n          },\n          {\n            \"name\": \"Down\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StaticParameters\",\n      \"docs\": [\n        \"Parameter that set by the protocol\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"base_factor\",\n            \"docs\": [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"filter_period\",\n            \"docs\": [\n              \"Filter period determine high frequency trading time window.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"decay_period\",\n            \"docs\": [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"reduction_factor\",\n            \"docs\": [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"variable_fee_control\",\n            \"docs\": [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"max_volatility_accumulator\",\n            \"docs\": [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"protocol_share\",\n            \"docs\": [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ],\n            \"type\": \"u16\"\n          },\n          {\n            \"name\": \"base_fee_power_factor\",\n            \"docs\": [\n              \"Base fee power factor\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"function_type\",\n            \"docs\": [\n              \"function type\"\n            ],\n            \"type\": \"u8\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\n              \"Padding for bytemuck safe alignment\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                4\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StrategyParameters\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"min_bin_id\",\n            \"docs\": [\n              \"min bin id\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"max_bin_id\",\n            \"docs\": [\n              \"max bin id\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"strategy_type\",\n            \"docs\": [\n              \"strategy type\"\n            ],\n            \"type\": {\n              \"defined\": {\n                \"name\": \"StrategyType\"\n              }\n            }\n          },\n          {\n            \"name\": \"parameteres\",\n            \"docs\": [\n              \"parameters\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                64\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"StrategyType\",\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"SpotOneSide\"\n          },\n          {\n            \"name\": \"CurveOneSide\"\n          },\n          {\n            \"name\": \"BidAskOneSide\"\n          },\n          {\n            \"name\": \"SpotBalanced\"\n          },\n          {\n            \"name\": \"CurveBalanced\"\n          },\n          {\n            \"name\": \"BidAskBalanced\"\n          },\n          {\n            \"name\": \"SpotImBalanced\"\n          },\n          {\n            \"name\": \"CurveImBalanced\"\n          },\n          {\n            \"name\": \"BidAskImBalanced\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"Swap\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"from\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"start_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"end_bin_id\",\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"amount_in\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"amount_out\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"swap_for_y\",\n            \"type\": \"bool\"\n          },\n          {\n            \"name\": \"fee\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"protocol_fee\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"fee_bps\",\n            \"type\": \"u128\"\n          },\n          {\n            \"name\": \"host_fee\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"TokenBadge\",\n      \"docs\": [\n        \"Parameter that set by the protocol\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"token_mint\",\n            \"docs\": [\n              \"token mint\"\n            ],\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\n              \"Reserve\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                128\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"TokenProgramFlags\",\n      \"repr\": {\n        \"kind\": \"rust\"\n      },\n      \"type\": {\n        \"kind\": \"enum\",\n        \"variants\": [\n          {\n            \"name\": \"TokenProgram\"\n          },\n          {\n            \"name\": \"TokenProgram2022\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdatePositionLockReleasePoint\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"current_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"new_lock_release_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_lock_release_point\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"sender\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdatePositionOperator\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"position\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"old_operator\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_operator\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdateRewardDuration\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_reward_duration\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"new_reward_duration\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UpdateRewardFunder\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_index\",\n            \"type\": \"u64\"\n          },\n          {\n            \"name\": \"old_funder\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"new_funder\",\n            \"type\": \"pubkey\"\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"UserRewardInfo\",\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"reward_per_token_completes\",\n            \"type\": {\n              \"array\": [\n                \"u128\",\n                2\n              ]\n            }\n          },\n          {\n            \"name\": \"reward_pendings\",\n            \"type\": {\n              \"array\": [\n                \"u64\",\n                2\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"VariableParameters\",\n      \"docs\": [\n        \"Parameters that changes based on dynamic of the market\"\n      ],\n      \"serialization\": \"bytemuck\",\n      \"repr\": {\n        \"kind\": \"c\"\n      },\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"volatility_accumulator\",\n            \"docs\": [\n              \"Volatility accumulator measure the number of bin crossed since reference bin ID. Normally (without filter period taken into consideration), reference bin ID is the active bin of last swap.\",\n              \"It affects the variable fee rate\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"volatility_reference\",\n            \"docs\": [\n              \"Volatility reference is decayed volatility accumulator. It is always <= volatility_accumulator\"\n            ],\n            \"type\": \"u32\"\n          },\n          {\n            \"name\": \"index_reference\",\n            \"docs\": [\n              \"Active bin id of last swap.\"\n            ],\n            \"type\": \"i32\"\n          },\n          {\n            \"name\": \"_padding\",\n            \"docs\": [\n              \"Padding for bytemuck safe alignment\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                4\n              ]\n            }\n          },\n          {\n            \"name\": \"last_update_timestamp\",\n            \"docs\": [\n              \"Last timestamp the variable parameters was updated\"\n            ],\n            \"type\": \"i64\"\n          },\n          {\n            \"name\": \"_padding_1\",\n            \"docs\": [\n              \"Padding for bytemuck safe alignment\"\n            ],\n            \"type\": {\n              \"array\": [\n                \"u8\",\n                8\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"name\": \"WithdrawIneligibleReward\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"lb_pair\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"reward_mint\",\n            \"type\": \"pubkey\"\n          },\n          {\n            \"name\": \"amount\",\n            \"type\": \"u64\"\n          }\n        ]\n      }\n    }\n  ],\n  \"constants\": [\n    {\n      \"name\": \"BASIS_POINT_MAX\",\n      \"type\": \"i32\",\n      \"value\": \"10000\"\n    },\n    {\n      \"name\": \"BIN_ARRAY\",\n      \"type\": \"bytes\",\n      \"value\": \"[98, 105, 110, 95, 97, 114, 114, 97, 121]\"\n    },\n    {\n      \"name\": \"BIN_ARRAY_BITMAP_SEED\",\n      \"type\": \"bytes\",\n      \"value\": \"[98, 105, 116, 109, 97, 112]\"\n    },\n    {\n      \"name\": \"BIN_ARRAY_BITMAP_SIZE\",\n      \"type\": \"i32\",\n      \"value\": \"512\"\n    },\n    {\n      \"name\": \"CLAIM_PROTOCOL_FEE_OPERATOR\",\n      \"type\": \"bytes\",\n      \"value\": \"[99, 102, 95, 111, 112, 101, 114, 97, 116, 111, 114]\"\n    },\n    {\n      \"name\": \"DEFAULT_BIN_PER_POSITION\",\n      \"type\": \"u64\",\n      \"value\": \"70\"\n    },\n    {\n      \"name\": \"EXTENSION_BINARRAY_BITMAP_SIZE\",\n      \"type\": \"u64\",\n      \"value\": \"12\"\n    },\n    {\n      \"name\": \"FEE_PRECISION\",\n      \"type\": \"u64\",\n      \"value\": \"1000000000\"\n    },\n    {\n      \"name\": \"HOST_FEE_BPS\",\n      \"docs\": [\n        \"Host fee. 20%\"\n      ],\n      \"type\": \"u16\",\n      \"value\": \"2000\"\n    },\n    {\n      \"name\": \"ILM_PROTOCOL_SHARE\",\n      \"type\": \"u16\",\n      \"value\": \"2000\"\n    },\n    {\n      \"name\": \"MAX_BASE_FEE\",\n      \"docs\": [\n        \"Maximum base fee, base_fee / 10^9 = fee_in_percentage\"\n      ],\n      \"type\": \"u128\",\n      \"value\": \"100000000\"\n    },\n    {\n      \"name\": \"MAX_BIN_ID_PER_BIN_STEP\",\n      \"docs\": [\n        \"Maximum bin ID per bin step. Computed based on 1 bps. Used for bin id bound estimation.\"\n      ],\n      \"type\": \"i32\",\n      \"value\": \"351639\"\n    },\n    {\n      \"name\": \"MAX_BIN_PER_ARRAY\",\n      \"type\": \"u64\",\n      \"value\": \"70\"\n    },\n    {\n      \"name\": \"MAX_BIN_STEP\",\n      \"docs\": [\n        \"Maximum bin step\"\n      ],\n      \"type\": \"u16\",\n      \"value\": \"400\"\n    },\n    {\n      \"name\": \"MAX_FEE_RATE\",\n      \"docs\": [\n        \"Maximum fee rate. 10%\"\n      ],\n      \"type\": \"u64\",\n      \"value\": \"100000000\"\n    },\n    {\n      \"name\": \"MAX_PROTOCOL_SHARE\",\n      \"docs\": [\n        \"Maximum protocol share of the fee. 25%\"\n      ],\n      \"type\": \"u16\",\n      \"value\": \"2500\"\n    },\n    {\n      \"name\": \"MAX_RESIZE_LENGTH\",\n      \"type\": \"u64\",\n      \"value\": \"91\"\n    },\n    {\n      \"name\": \"MAX_REWARD_BIN_SPLIT\",\n      \"type\": \"u64\",\n      \"value\": \"15\"\n    },\n    {\n      \"name\": \"MAX_REWARD_DURATION\",\n      \"type\": \"u64\",\n      \"value\": \"31536000\"\n    },\n    {\n      \"name\": \"MINIMUM_LIQUIDITY\",\n      \"type\": \"u128\",\n      \"value\": \"1000000\"\n    },\n    {\n      \"name\": \"MIN_BASE_FEE\",\n      \"docs\": [\n        \"Minimum base fee\"\n      ],\n      \"type\": \"u128\",\n      \"value\": \"100000\"\n    },\n    {\n      \"name\": \"MIN_REWARD_DURATION\",\n      \"type\": \"u64\",\n      \"value\": \"1\"\n    },\n    {\n      \"name\": \"NUM_REWARDS\",\n      \"type\": \"u64\",\n      \"value\": \"2\"\n    },\n    {\n      \"name\": \"OPERATOR_PREFIX\",\n      \"type\": \"bytes\",\n      \"value\": \"[111, 112, 101, 114, 97, 116, 111, 114]\"\n    },\n    {\n      \"name\": \"ORACLE\",\n      \"type\": \"bytes\",\n      \"value\": \"[111, 114, 97, 99, 108, 101]\"\n    },\n    {\n      \"name\": \"POSITION\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 111, 115, 105, 116, 105, 111, 110]\"\n    },\n    {\n      \"name\": \"POSITION_MAX_LENGTH\",\n      \"type\": \"u64\",\n      \"value\": \"1400\"\n    },\n    {\n      \"name\": \"PRESET_PARAMETER\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114]\"\n    },\n    {\n      \"name\": \"PRESET_PARAMETER2\",\n      \"type\": \"bytes\",\n      \"value\": \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114, 50]\"\n    },\n    {\n      \"name\": \"PROTOCOL_SHARE\",\n      \"type\": \"u16\",\n      \"value\": \"500\"\n    }\n  ]\n}"
  },
  {
    "path": "ts-client/src/dlmm/idl/idl.ts",
    "content": "/**\n * Program IDL in camelCase format in order to be used in JS/TS.\n *\n * Note that this is only a type helper and is not the actual IDL. The original\n * IDL can be found at `target/idl/lb_clmm.json`.\n */\nexport type LbClmm = {\n  address: \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\";\n  metadata: {\n    name: \"lbClmm\";\n    version: \"0.11.0\";\n    spec: \"0.1.0\";\n    description: \"Created with Anchor\";\n  };\n  instructions: [\n    {\n      name: \"addLiquidity\";\n      discriminator: [181, 157, 89, 67, 143, 182, 52, 72];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameter\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidity2\";\n      discriminator: [228, 162, 78, 28, 70, 219, 116, 115];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameter\";\n            };\n          };\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityByStrategy\";\n      discriminator: [7, 3, 150, 127, 148, 40, 61, 200];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameterByStrategy\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityByStrategy2\";\n      discriminator: [3, 221, 149, 218, 111, 141, 118, 213];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameterByStrategy\";\n            };\n          };\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityByStrategyOneSide\";\n      discriminator: [41, 5, 238, 175, 100, 225, 6, 205];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userToken\";\n          writable: true;\n        },\n        {\n          name: \"reserve\";\n          writable: true;\n        },\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameterByStrategyOneSide\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityByWeight\";\n      discriminator: [28, 140, 238, 99, 231, 162, 21, 149];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityParameterByWeight\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityOneSide\";\n      discriminator: [94, 155, 103, 151, 70, 95, 220, 165];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userToken\";\n          writable: true;\n        },\n        {\n          name: \"reserve\";\n          writable: true;\n        },\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"liquidityOneSideParameter\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityOneSidePrecise\";\n      discriminator: [161, 194, 103, 84, 171, 71, 250, 154];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userToken\";\n          writable: true;\n        },\n        {\n          name: \"reserve\";\n          writable: true;\n        },\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"parameter\";\n          type: {\n            defined: {\n              name: \"addLiquiditySingleSidePreciseParameter\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"addLiquidityOneSidePrecise2\";\n      discriminator: [33, 51, 163, 201, 117, 98, 125, 231];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userToken\";\n          writable: true;\n        },\n        {\n          name: \"reserve\";\n          writable: true;\n        },\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"liquidityParameter\";\n          type: {\n            defined: {\n              name: \"addLiquiditySingleSidePreciseParameter2\";\n            };\n          };\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"claimFee\";\n      discriminator: [169, 32, 79, 137, 136, 232, 70, 137];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayLower\", \"binArrayUpper\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"claimFee2\";\n      discriminator: [112, 191, 101, 171, 28, 144, 127, 187];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenProgramX\";\n        },\n        {\n          name: \"tokenProgramY\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"minBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"maxBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"claimReward\";\n      discriminator: [149, 95, 181, 242, 94, 90, 158, 162];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayLower\", \"binArrayUpper\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"rewardVault\";\n          writable: true;\n        },\n        {\n          name: \"rewardMint\";\n        },\n        {\n          name: \"userTokenAccount\";\n          writable: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"claimReward2\";\n      discriminator: [190, 3, 127, 119, 178, 87, 157, 183];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"rewardVault\";\n          writable: true;\n        },\n        {\n          name: \"rewardMint\";\n        },\n        {\n          name: \"userTokenAccount\";\n          writable: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"minBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"maxBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"closeClaimFeeOperatorAccount\";\n      discriminator: [184, 213, 88, 31, 179, 101, 130, 36];\n      accounts: [\n        {\n          name: \"claimFeeOperator\";\n          writable: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closeOperatorAccount\";\n      discriminator: [171, 9, 213, 74, 120, 23, 3, 29];\n      accounts: [\n        {\n          name: \"operator\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closePosition\";\n      discriminator: [123, 134, 81, 0, 49, 68, 98, 98];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closePosition2\";\n      discriminator: [174, 90, 35, 115, 186, 40, 147, 226];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closePositionIfEmpty\";\n      discriminator: [59, 124, 212, 118, 91, 152, 110, 157];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closePresetParameter\";\n      discriminator: [4, 148, 145, 100, 134, 26, 181, 61];\n      accounts: [\n        {\n          name: \"presetParameter\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closePresetParameter2\";\n      discriminator: [39, 25, 95, 107, 116, 17, 115, 28];\n      accounts: [\n        {\n          name: \"presetParameter\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"closeTokenBadge\";\n      discriminator: [108, 146, 86, 110, 179, 254, 10, 104];\n      accounts: [\n        {\n          name: \"tokenBadge\";\n          writable: true;\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"createOperatorAccount\";\n      discriminator: [221, 64, 246, 149, 240, 153, 229, 163];\n      accounts: [\n        {\n          name: \"operator\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 112, 101, 114, 97, 116, 111, 114];\n              },\n              {\n                kind: \"account\";\n                path: \"whitelistedSigner\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"whitelistedSigner\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        }\n      ];\n      args: [\n        {\n          name: \"permission\";\n          type: \"u128\";\n        }\n      ];\n    },\n    {\n      name: \"decreasePositionLength\";\n      discriminator: [194, 219, 136, 32, 25, 96, 105, 37];\n      accounts: [\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"owner\";\n          signer: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lengthToRemove\";\n          type: \"u16\";\n        },\n        {\n          name: \"side\";\n          type: \"u8\";\n        }\n      ];\n    },\n    {\n      name: \"forIdlTypeGenerationDoNotCall\";\n      discriminator: [180, 105, 69, 80, 95, 50, 73, 108];\n      accounts: [\n        {\n          name: \"dummyZcAccount\";\n        }\n      ];\n      args: [\n        {\n          name: \"ix\";\n          type: {\n            defined: {\n              name: \"dummyIx\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"fundReward\";\n      discriminator: [188, 50, 249, 165, 93, 151, 38, 63];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArray\"];\n        },\n        {\n          name: \"rewardVault\";\n          writable: true;\n        },\n        {\n          name: \"rewardMint\";\n        },\n        {\n          name: \"funderTokenAccount\";\n          writable: true;\n        },\n        {\n          name: \"funder\";\n          signer: true;\n        },\n        {\n          name: \"binArray\";\n          writable: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"amount\";\n          type: \"u64\";\n        },\n        {\n          name: \"carryForward\";\n          type: \"bool\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"goToABin\";\n      discriminator: [146, 72, 174, 224, 40, 253, 84, 174];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\", \"fromBinArray\", \"toBinArray\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"fromBinArray\";\n          optional: true;\n        },\n        {\n          name: \"toBinArray\";\n          optional: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"binId\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"increaseOracleLength\";\n      discriminator: [190, 61, 125, 87, 103, 79, 158, 173];\n      accounts: [\n        {\n          name: \"oracle\";\n          writable: true;\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lengthToAdd\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"increasePositionLength\";\n      discriminator: [80, 83, 117, 211, 66, 13, 33, 149];\n      accounts: [\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"lbPair\";\n          relations: [\"position\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"owner\";\n          signer: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lengthToAdd\";\n          type: \"u16\";\n        },\n        {\n          name: \"side\";\n          type: \"u8\";\n        }\n      ];\n    },\n    {\n      name: \"increasePositionLength2\";\n      discriminator: [255, 210, 204, 71, 115, 137, 225, 113];\n      accounts: [\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"lbPair\";\n          relations: [\"position\"];\n        },\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"owner\";\n          signer: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"minimumUpperBinId\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"initializeBinArray\";\n      discriminator: [35, 86, 19, 185, 78, 212, 75, 211];\n      accounts: [\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"binArray\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 110, 95, 97, 114, 114, 97, 121];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"arg\";\n                path: \"index\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        }\n      ];\n      args: [\n        {\n          name: \"index\";\n          type: \"i64\";\n        }\n      ];\n    },\n    {\n      name: \"initializeBinArrayBitmapExtension\";\n      discriminator: [47, 157, 226, 180, 12, 240, 33, 71];\n      accounts: [\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          docs: [\n            \"Initialize an account to store if a bin array is initialized.\"\n          ];\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"rent\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"initializeCustomizablePermissionlessLbPair\";\n      discriminator: [46, 39, 41, 135, 111, 183, 200, 64];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"tokenMintX\";\n        },\n        {\n          name: \"tokenMintY\";\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintX\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintY\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 114, 97, 99, 108, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"userTokenX\";\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"userTokenY\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"params\";\n          type: {\n            defined: {\n              name: \"customizableParams\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"initializeCustomizablePermissionlessLbPair2\";\n      discriminator: [243, 73, 129, 126, 51, 19, 241, 107];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"tokenMintX\";\n        },\n        {\n          name: \"tokenMintY\";\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintX\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintY\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 114, 97, 99, 108, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"userTokenX\";\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenBadgeX\";\n          optional: true;\n        },\n        {\n          name: \"tokenBadgeY\";\n          optional: true;\n        },\n        {\n          name: \"tokenProgramX\";\n        },\n        {\n          name: \"tokenProgramY\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"userTokenY\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"params\";\n          type: {\n            defined: {\n              name: \"customizableParams\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"initializeLbPair\";\n      discriminator: [45, 154, 237, 210, 221, 15, 166, 92];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"tokenMintX\";\n        },\n        {\n          name: \"tokenMintY\";\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintX\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintY\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 114, 97, 99, 108, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"presetParameter\";\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"rent\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"activeId\";\n          type: \"i32\";\n        },\n        {\n          name: \"binStep\";\n          type: \"u16\";\n        }\n      ];\n    },\n    {\n      name: \"initializeLbPair2\";\n      discriminator: [73, 59, 36, 120, 237, 83, 108, 198];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"tokenMintX\";\n        },\n        {\n          name: \"tokenMintY\";\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintX\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintY\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 114, 97, 99, 108, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"presetParameter\";\n        },\n        {\n          name: \"funder\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenBadgeX\";\n          optional: true;\n        },\n        {\n          name: \"tokenBadgeY\";\n          optional: true;\n        },\n        {\n          name: \"tokenProgramX\";\n        },\n        {\n          name: \"tokenProgramY\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"params\";\n          type: {\n            defined: {\n              name: \"initializeLbPair2Params\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"initializePermissionLbPair\";\n      discriminator: [108, 102, 213, 85, 251, 3, 53, 21];\n      accounts: [\n        {\n          name: \"base\";\n          signer: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [98, 105, 116, 109, 97, 112];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"tokenMintX\";\n        },\n        {\n          name: \"tokenMintY\";\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintX\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMintY\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [111, 114, 97, 99, 108, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"tokenBadgeX\";\n          optional: true;\n        },\n        {\n          name: \"tokenBadgeY\";\n          optional: true;\n        },\n        {\n          name: \"tokenProgramX\";\n        },\n        {\n          name: \"tokenProgramY\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"ixData\";\n          type: {\n            defined: {\n              name: \"initPermissionPairIx\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"initializePosition\";\n      discriminator: [219, 192, 234, 71, 190, 191, 102, 80];\n      accounts: [\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"position\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"owner\";\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"rent\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lowerBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"width\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"initializePosition2\";\n      discriminator: [143, 19, 242, 145, 213, 15, 104, 115];\n      accounts: [\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"position\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"owner\";\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lowerBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"width\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"initializePositionByOperator\";\n      discriminator: [251, 189, 190, 244, 117, 254, 35, 148];\n      accounts: [\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"base\";\n          signer: true;\n        },\n        {\n          name: \"position\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [112, 111, 115, 105, 116, 105, 111, 110];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"base\";\n              },\n              {\n                kind: \"arg\";\n                path: \"lowerBinId\";\n              },\n              {\n                kind: \"arg\";\n                path: \"width\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"owner\";\n        },\n        {\n          name: \"operator\";\n          docs: [\"operator\"];\n          signer: true;\n        },\n        {\n          name: \"operatorTokenX\";\n        },\n        {\n          name: \"ownerTokenX\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lowerBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"width\";\n          type: \"i32\";\n        },\n        {\n          name: \"feeOwner\";\n          type: \"pubkey\";\n        },\n        {\n          name: \"lockReleasePoint\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"initializePositionPda\";\n      discriminator: [46, 82, 125, 146, 85, 141, 228, 153];\n      accounts: [\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"base\";\n          signer: true;\n        },\n        {\n          name: \"position\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [112, 111, 115, 105, 116, 105, 111, 110];\n              },\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"account\";\n                path: \"base\";\n              },\n              {\n                kind: \"arg\";\n                path: \"lowerBinId\";\n              },\n              {\n                kind: \"arg\";\n                path: \"width\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"owner\";\n          docs: [\"owner\"];\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"rent\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"lowerBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"width\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"initializePresetParameter\";\n      discriminator: [66, 188, 71, 211, 98, 109, 14, 186];\n      accounts: [\n        {\n          name: \"presetParameter\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  112,\n                  114,\n                  101,\n                  115,\n                  101,\n                  116,\n                  95,\n                  112,\n                  97,\n                  114,\n                  97,\n                  109,\n                  101,\n                  116,\n                  101,\n                  114,\n                  50\n                ];\n              },\n              {\n                kind: \"arg\";\n                path: \"ix.index\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        }\n      ];\n      args: [\n        {\n          name: \"ix\";\n          type: {\n            defined: {\n              name: \"initPresetParametersIx\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"initializeReward\";\n      discriminator: [95, 135, 192, 196, 242, 129, 230, 68];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"rewardVault\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"account\";\n                path: \"lbPair\";\n              },\n              {\n                kind: \"arg\";\n                path: \"rewardIndex\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"rewardMint\";\n        },\n        {\n          name: \"tokenBadge\";\n          optional: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"rewardDuration\";\n          type: \"u64\";\n        },\n        {\n          name: \"funder\";\n          type: \"pubkey\";\n        }\n      ];\n    },\n    {\n      name: \"initializeTokenBadge\";\n      discriminator: [253, 77, 205, 95, 27, 224, 89, 223];\n      accounts: [\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"tokenBadge\";\n          writable: true;\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [116, 111, 107, 101, 110, 95, 98, 97, 100, 103, 101];\n              },\n              {\n                kind: \"account\";\n                path: \"tokenMint\";\n              }\n            ];\n          };\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"payer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"migratePosition\";\n      discriminator: [15, 132, 59, 50, 199, 6, 251, 46];\n      accounts: [\n        {\n          name: \"positionV2\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"positionV1\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"signerAndPayer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"rentReceiver\";\n          writable: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"rebalanceLiquidity\";\n      discriminator: [92, 4, 176, 193, 119, 185, 83, 9];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"owner\";\n          signer: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"rentPayer\";\n          writable: true;\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"systemProgram\";\n          address: \"11111111111111111111111111111111\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"params\";\n          type: {\n            defined: {\n              name: \"rebalanceLiquidityParams\";\n            };\n          };\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"removeAllLiquidity\";\n      discriminator: [10, 51, 61, 35, 112, 105, 24, 85];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"removeLiquidity\";\n      discriminator: [80, 85, 209, 72, 24, 206, 177, 108];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"binLiquidityRemoval\";\n          type: {\n            vec: {\n              defined: {\n                name: \"binLiquidityReduction\";\n              };\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"removeLiquidity2\";\n      discriminator: [230, 215, 82, 127, 241, 101, 227, 146];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"binLiquidityRemoval\";\n          type: {\n            vec: {\n              defined: {\n                name: \"binLiquidityReduction\";\n              };\n            };\n          };\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"removeLiquidityByRange\";\n      discriminator: [26, 82, 102, 152, 240, 74, 105, 26];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\n            \"position\",\n            \"binArrayBitmapExtension\",\n            \"binArrayLower\",\n            \"binArrayUpper\"\n          ];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"fromBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"toBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"bpsToRemove\";\n          type: \"u16\";\n        }\n      ];\n    },\n    {\n      name: \"removeLiquidityByRange2\";\n      discriminator: [204, 2, 195, 145, 53, 145, 145, 205];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"userTokenX\";\n          writable: true;\n        },\n        {\n          name: \"userTokenY\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"sender\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"fromBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"toBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"bpsToRemove\";\n          type: \"u16\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"resetBinArrayTombstoneFields\";\n      discriminator: [54, 90, 252, 63, 41, 206, 63, 63];\n      accounts: [\n        {\n          name: \"lbPair\";\n          relations: [\"binArray\"];\n        },\n        {\n          name: \"binArray\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"resetPoolTombstoneFields\";\n      discriminator: [246, 109, 19, 120, 108, 113, 68, 252];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"resetPositionTombstoneFields\";\n      discriminator: [206, 6, 51, 218, 211, 30, 159, 84];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"setActivationPoint\";\n      discriminator: [91, 249, 15, 165, 26, 129, 254, 125];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"activationPoint\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"setPairStatus\";\n      discriminator: [67, 248, 231, 137, 154, 149, 217, 174];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"status\";\n          type: \"u8\";\n        }\n      ];\n    },\n    {\n      name: \"setPairStatusPermissionless\";\n      discriminator: [78, 59, 152, 211, 70, 183, 46, 208];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"status\";\n          type: \"u8\";\n        }\n      ];\n    },\n    {\n      name: \"setPreActivationDuration\";\n      discriminator: [165, 61, 201, 244, 130, 159, 22, 100];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"preActivationDuration\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"setPreActivationSwapAddress\";\n      discriminator: [57, 139, 47, 123, 216, 80, 223, 10];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"preActivationSwapAddress\";\n          type: \"pubkey\";\n        }\n      ];\n    },\n    {\n      name: \"swap\";\n      discriminator: [248, 198, 158, 145, 225, 117, 135, 200];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"amountIn\";\n          type: \"u64\";\n        },\n        {\n          name: \"minAmountOut\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"swap2\";\n      discriminator: [65, 75, 63, 76, 235, 91, 91, 136];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"amountIn\";\n          type: \"u64\";\n        },\n        {\n          name: \"minAmountOut\";\n          type: \"u64\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"swapExactOut\";\n      discriminator: [250, 73, 101, 33, 38, 207, 75, 184];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"maxInAmount\";\n          type: \"u64\";\n        },\n        {\n          name: \"outAmount\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"swapExactOut2\";\n      discriminator: [43, 215, 247, 132, 137, 60, 243, 81];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"maxInAmount\";\n          type: \"u64\";\n        },\n        {\n          name: \"outAmount\";\n          type: \"u64\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"swapWithPriceImpact\";\n      discriminator: [56, 173, 230, 208, 173, 228, 156, 205];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"tokenYProgram\";\n          address: \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"amountIn\";\n          type: \"u64\";\n        },\n        {\n          name: \"activeId\";\n          type: {\n            option: \"i32\";\n          };\n        },\n        {\n          name: \"maxPriceImpactBps\";\n          type: \"u16\";\n        }\n      ];\n    },\n    {\n      name: \"swapWithPriceImpact2\";\n      discriminator: [74, 98, 192, 214, 177, 51, 75, 51];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArrayBitmapExtension\"];\n        },\n        {\n          name: \"binArrayBitmapExtension\";\n          optional: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"userTokenIn\";\n          writable: true;\n        },\n        {\n          name: \"userTokenOut\";\n          writable: true;\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"oracle\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"hostFeeIn\";\n          writable: true;\n          optional: true;\n        },\n        {\n          name: \"user\";\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"amountIn\";\n          type: \"u64\";\n        },\n        {\n          name: \"activeId\";\n          type: {\n            option: \"i32\";\n          };\n        },\n        {\n          name: \"maxPriceImpactBps\";\n          type: \"u16\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"updateBaseFeeParameters\";\n      discriminator: [75, 168, 223, 161, 16, 195, 3, 47];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"feeParameter\";\n          type: {\n            defined: {\n              name: \"baseFeeParameter\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"updateDynamicFeeParameters\";\n      discriminator: [92, 161, 46, 246, 255, 189, 22, 22];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"feeParameter\";\n          type: {\n            defined: {\n              name: \"dynamicFeeParameter\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"updateFeesAndReward2\";\n      discriminator: [32, 142, 184, 154, 103, 65, 184, 88];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"owner\";\n          signer: true;\n        }\n      ];\n      args: [\n        {\n          name: \"minBinId\";\n          type: \"i32\";\n        },\n        {\n          name: \"maxBinId\";\n          type: \"i32\";\n        }\n      ];\n    },\n    {\n      name: \"updateFeesAndRewards\";\n      discriminator: [154, 230, 250, 13, 236, 209, 75, 223];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"position\", \"binArrayLower\", \"binArrayUpper\"];\n        },\n        {\n          name: \"binArrayLower\";\n          writable: true;\n        },\n        {\n          name: \"binArrayUpper\";\n          writable: true;\n        },\n        {\n          name: \"owner\";\n          signer: true;\n        }\n      ];\n      args: [];\n    },\n    {\n      name: \"updatePositionOperator\";\n      discriminator: [202, 184, 103, 143, 180, 191, 116, 217];\n      accounts: [\n        {\n          name: \"position\";\n          writable: true;\n        },\n        {\n          name: \"owner\";\n          signer: true;\n          relations: [\"position\"];\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"operator\";\n          type: \"pubkey\";\n        }\n      ];\n    },\n    {\n      name: \"updateRewardDuration\";\n      discriminator: [138, 174, 196, 169, 213, 235, 254, 107];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArray\"];\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"binArray\";\n          writable: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"newDuration\";\n          type: \"u64\";\n        }\n      ];\n    },\n    {\n      name: \"updateRewardFunder\";\n      discriminator: [211, 28, 48, 32, 215, 160, 35, 23];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          signer: true;\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"newFunder\";\n          type: \"pubkey\";\n        }\n      ];\n    },\n    {\n      name: \"withdrawIneligibleReward\";\n      discriminator: [148, 206, 42, 195, 247, 49, 103, 8];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n          relations: [\"binArray\"];\n        },\n        {\n          name: \"rewardVault\";\n          writable: true;\n        },\n        {\n          name: \"rewardMint\";\n        },\n        {\n          name: \"funderTokenAccount\";\n          writable: true;\n        },\n        {\n          name: \"funder\";\n          signer: true;\n        },\n        {\n          name: \"binArray\";\n          writable: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"memoProgram\";\n          address: \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\";\n        },\n        {\n          name: \"eventAuthority\";\n          pda: {\n            seeds: [\n              {\n                kind: \"const\";\n                value: [\n                  95,\n                  95,\n                  101,\n                  118,\n                  101,\n                  110,\n                  116,\n                  95,\n                  97,\n                  117,\n                  116,\n                  104,\n                  111,\n                  114,\n                  105,\n                  116,\n                  121\n                ];\n              }\n            ];\n          };\n        },\n        {\n          name: \"program\";\n        }\n      ];\n      args: [\n        {\n          name: \"rewardIndex\";\n          type: \"u64\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"withdrawProtocolFee\";\n      discriminator: [158, 201, 158, 189, 33, 93, 162, 103];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"reserveX\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"reserveY\";\n          writable: true;\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenXMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"tokenYMint\";\n          relations: [\"lbPair\"];\n        },\n        {\n          name: \"receiverTokenX\";\n          writable: true;\n        },\n        {\n          name: \"receiverTokenY\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          docs: [\"operator\"];\n          signer: true;\n        },\n        {\n          name: \"tokenXProgram\";\n        },\n        {\n          name: \"tokenYProgram\";\n        }\n      ];\n      args: [\n        {\n          name: \"maxAmountX\";\n          type: \"u64\";\n        },\n        {\n          name: \"maxAmountY\";\n          type: \"u64\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    },\n    {\n      name: \"zapProtocolFee\";\n      discriminator: [213, 155, 187, 34, 56, 182, 91, 240];\n      accounts: [\n        {\n          name: \"lbPair\";\n          writable: true;\n        },\n        {\n          name: \"reserve\";\n          writable: true;\n        },\n        {\n          name: \"tokenMint\";\n        },\n        {\n          name: \"receiverToken\";\n          writable: true;\n        },\n        {\n          name: \"operator\";\n        },\n        {\n          name: \"signer\";\n          docs: [\"operator\"];\n          signer: true;\n        },\n        {\n          name: \"tokenProgram\";\n        },\n        {\n          name: \"sysvarInstructions\";\n          address: \"Sysvar1nstructions1111111111111111111111111\";\n        }\n      ];\n      args: [\n        {\n          name: \"maxAmount\";\n          type: \"u64\";\n        },\n        {\n          name: \"remainingAccountsInfo\";\n          type: {\n            defined: {\n              name: \"remainingAccountsInfo\";\n            };\n          };\n        }\n      ];\n    }\n  ];\n  accounts: [\n    {\n      name: \"binArray\";\n      discriminator: [92, 142, 92, 220, 5, 148, 70, 181];\n    },\n    {\n      name: \"binArrayBitmapExtension\";\n      discriminator: [80, 111, 124, 113, 55, 237, 18, 5];\n    },\n    {\n      name: \"claimFeeOperator\";\n      discriminator: [166, 48, 134, 86, 34, 200, 188, 150];\n    },\n    {\n      name: \"dummyZcAccount\";\n      discriminator: [94, 107, 238, 80, 208, 48, 180, 8];\n    },\n    {\n      name: \"lbPair\";\n      discriminator: [33, 11, 49, 98, 181, 101, 177, 13];\n    },\n    {\n      name: \"operator\";\n      discriminator: [219, 31, 188, 145, 69, 139, 204, 117];\n    },\n    {\n      name: \"oracle\";\n      discriminator: [139, 194, 131, 179, 140, 179, 229, 244];\n    },\n    {\n      name: \"position\";\n      discriminator: [170, 188, 143, 228, 122, 64, 247, 208];\n    },\n    {\n      name: \"positionV2\";\n      discriminator: [117, 176, 212, 199, 245, 180, 133, 182];\n    },\n    {\n      name: \"presetParameter\";\n      discriminator: [242, 62, 244, 34, 181, 112, 58, 170];\n    },\n    {\n      name: \"presetParameter2\";\n      discriminator: [171, 236, 148, 115, 162, 113, 222, 174];\n    },\n    {\n      name: \"tokenBadge\";\n      discriminator: [116, 219, 204, 229, 249, 116, 255, 150];\n    }\n  ];\n  events: [\n    {\n      name: \"addLiquidity\";\n      discriminator: [31, 94, 125, 90, 227, 52, 61, 186];\n    },\n    {\n      name: \"claimFee\";\n      discriminator: [75, 122, 154, 48, 140, 74, 123, 163];\n    },\n    {\n      name: \"claimFee2\";\n      discriminator: [232, 171, 242, 97, 58, 77, 35, 45];\n    },\n    {\n      name: \"claimReward\";\n      discriminator: [148, 116, 134, 204, 22, 171, 85, 95];\n    },\n    {\n      name: \"claimReward2\";\n      discriminator: [27, 143, 244, 33, 80, 43, 110, 146];\n    },\n    {\n      name: \"compositionFee\";\n      discriminator: [128, 151, 123, 106, 17, 102, 113, 142];\n    },\n    {\n      name: \"decreasePositionLength\";\n      discriminator: [52, 118, 235, 85, 172, 169, 15, 128];\n    },\n    {\n      name: \"dynamicFeeParameterUpdate\";\n      discriminator: [88, 88, 178, 135, 194, 146, 91, 243];\n    },\n    {\n      name: \"feeParameterUpdate\";\n      discriminator: [48, 76, 241, 117, 144, 215, 242, 44];\n    },\n    {\n      name: \"fundReward\";\n      discriminator: [246, 228, 58, 130, 145, 170, 79, 204];\n    },\n    {\n      name: \"goToABin\";\n      discriminator: [59, 138, 76, 68, 138, 131, 176, 67];\n    },\n    {\n      name: \"increaseObservation\";\n      discriminator: [99, 249, 17, 121, 166, 156, 207, 215];\n    },\n    {\n      name: \"increasePositionLength\";\n      discriminator: [157, 239, 42, 204, 30, 56, 223, 46];\n    },\n    {\n      name: \"initializeReward\";\n      discriminator: [211, 153, 88, 62, 149, 60, 177, 70];\n    },\n    {\n      name: \"lbPairCreate\";\n      discriminator: [185, 74, 252, 125, 27, 215, 188, 111];\n    },\n    {\n      name: \"positionClose\";\n      discriminator: [255, 196, 16, 107, 28, 202, 53, 128];\n    },\n    {\n      name: \"positionCreate\";\n      discriminator: [144, 142, 252, 84, 157, 53, 37, 121];\n    },\n    {\n      name: \"rebalancing\";\n      discriminator: [0, 109, 117, 179, 61, 91, 199, 200];\n    },\n    {\n      name: \"removeLiquidity\";\n      discriminator: [116, 244, 97, 232, 103, 31, 152, 58];\n    },\n    {\n      name: \"swap\";\n      discriminator: [81, 108, 227, 190, 205, 208, 10, 196];\n    },\n    {\n      name: \"updatePositionLockReleasePoint\";\n      discriminator: [133, 214, 66, 224, 64, 12, 7, 191];\n    },\n    {\n      name: \"updatePositionOperator\";\n      discriminator: [39, 115, 48, 204, 246, 47, 66, 57];\n    },\n    {\n      name: \"updateRewardDuration\";\n      discriminator: [223, 245, 224, 153, 49, 29, 163, 172];\n    },\n    {\n      name: \"updateRewardFunder\";\n      discriminator: [224, 178, 174, 74, 252, 165, 85, 180];\n    },\n    {\n      name: \"withdrawIneligibleReward\";\n      discriminator: [231, 189, 65, 149, 102, 215, 154, 244];\n    }\n  ];\n  errors: [\n    {\n      code: 6000;\n      name: \"invalidStartBinIndex\";\n      msg: \"Invalid start bin index\";\n    },\n    {\n      code: 6001;\n      name: \"invalidBinId\";\n      msg: \"Invalid bin id\";\n    },\n    {\n      code: 6002;\n      name: \"invalidInput\";\n      msg: \"Invalid input data\";\n    },\n    {\n      code: 6003;\n      name: \"exceededAmountSlippageTolerance\";\n      msg: \"Exceeded amount slippage tolerance\";\n    },\n    {\n      code: 6004;\n      name: \"exceededBinSlippageTolerance\";\n      msg: \"Exceeded bin slippage tolerance\";\n    },\n    {\n      code: 6005;\n      name: \"compositionFactorFlawed\";\n      msg: \"Composition factor flawed\";\n    },\n    {\n      code: 6006;\n      name: \"nonPresetBinStep\";\n      msg: \"Non preset bin step\";\n    },\n    {\n      code: 6007;\n      name: \"zeroLiquidity\";\n      msg: \"Zero liquidity\";\n    },\n    {\n      code: 6008;\n      name: \"invalidPosition\";\n      msg: \"Invalid position\";\n    },\n    {\n      code: 6009;\n      name: \"binArrayNotFound\";\n      msg: \"Bin array not found\";\n    },\n    {\n      code: 6010;\n      name: \"invalidTokenMint\";\n      msg: \"Invalid token mint\";\n    },\n    {\n      code: 6011;\n      name: \"invalidAccountForSingleDeposit\";\n      msg: \"Invalid account for single deposit\";\n    },\n    {\n      code: 6012;\n      name: \"pairInsufficientLiquidity\";\n      msg: \"Pair insufficient liquidity\";\n    },\n    {\n      code: 6013;\n      name: \"invalidFeeOwner\";\n      msg: \"Invalid fee owner\";\n    },\n    {\n      code: 6014;\n      name: \"invalidFeeWithdrawAmount\";\n      msg: \"Invalid fee withdraw amount\";\n    },\n    {\n      code: 6015;\n      name: \"invalidAdmin\";\n      msg: \"Invalid admin\";\n    },\n    {\n      code: 6016;\n      name: \"identicalFeeOwner\";\n      msg: \"Identical fee owner\";\n    },\n    {\n      code: 6017;\n      name: \"invalidBps\";\n      msg: \"Invalid basis point\";\n    },\n    {\n      code: 6018;\n      name: \"mathOverflow\";\n      msg: \"Math operation overflow\";\n    },\n    {\n      code: 6019;\n      name: \"typeCastFailed\";\n      msg: \"Type cast error\";\n    },\n    {\n      code: 6020;\n      name: \"invalidRewardIndex\";\n      msg: \"Invalid reward index\";\n    },\n    {\n      code: 6021;\n      name: \"invalidRewardDuration\";\n      msg: \"Invalid reward duration\";\n    },\n    {\n      code: 6022;\n      name: \"rewardInitialized\";\n      msg: \"Reward already initialized\";\n    },\n    {\n      code: 6023;\n      name: \"rewardUninitialized\";\n      msg: \"Reward not initialized\";\n    },\n    {\n      code: 6024;\n      name: \"identicalFunder\";\n      msg: \"Identical funder\";\n    },\n    {\n      code: 6025;\n      name: \"rewardCampaignInProgress\";\n      msg: \"Reward campaign in progress\";\n    },\n    {\n      code: 6026;\n      name: \"identicalRewardDuration\";\n      msg: \"Reward duration is the same\";\n    },\n    {\n      code: 6027;\n      name: \"invalidBinArray\";\n      msg: \"Invalid bin array\";\n    },\n    {\n      code: 6028;\n      name: \"nonContinuousBinArrays\";\n      msg: \"Bin arrays must be continuous\";\n    },\n    {\n      code: 6029;\n      name: \"invalidRewardVault\";\n      msg: \"Invalid reward vault\";\n    },\n    {\n      code: 6030;\n      name: \"nonEmptyPosition\";\n      msg: \"Position is not empty\";\n    },\n    {\n      code: 6031;\n      name: \"unauthorizedAccess\";\n      msg: \"Unauthorized access\";\n    },\n    {\n      code: 6032;\n      name: \"invalidFeeParameter\";\n      msg: \"Invalid fee parameter\";\n    },\n    {\n      code: 6033;\n      name: \"missingOracle\";\n      msg: \"Missing oracle account\";\n    },\n    {\n      code: 6034;\n      name: \"insufficientSample\";\n      msg: \"Insufficient observation sample\";\n    },\n    {\n      code: 6035;\n      name: \"invalidLookupTimestamp\";\n      msg: \"Invalid lookup timestamp\";\n    },\n    {\n      code: 6036;\n      name: \"bitmapExtensionAccountIsNotProvided\";\n      msg: \"Bitmap extension account is not provided\";\n    },\n    {\n      code: 6037;\n      name: \"cannotFindNonZeroLiquidityBinArrayId\";\n      msg: \"Cannot find non-zero liquidity binArrayId\";\n    },\n    {\n      code: 6038;\n      name: \"binIdOutOfBound\";\n      msg: \"Bin id out of bound\";\n    },\n    {\n      code: 6039;\n      name: \"insufficientOutAmount\";\n      msg: \"Insufficient amount in for minimum out\";\n    },\n    {\n      code: 6040;\n      name: \"invalidPositionWidth\";\n      msg: \"Invalid position width\";\n    },\n    {\n      code: 6041;\n      name: \"excessiveFeeUpdate\";\n      msg: \"Excessive fee update\";\n    },\n    {\n      code: 6042;\n      name: \"poolDisabled\";\n      msg: \"Pool disabled\";\n    },\n    {\n      code: 6043;\n      name: \"invalidPoolType\";\n      msg: \"Invalid pool type\";\n    },\n    {\n      code: 6044;\n      name: \"exceedMaxWhitelist\";\n      msg: \"Whitelist for wallet is full\";\n    },\n    {\n      code: 6045;\n      name: \"invalidIndex\";\n      msg: \"Invalid index\";\n    },\n    {\n      code: 6046;\n      name: \"rewardNotEnded\";\n      msg: \"Reward not ended\";\n    },\n    {\n      code: 6047;\n      name: \"mustWithdrawnIneligibleReward\";\n      msg: \"Must withdraw ineligible reward\";\n    },\n    {\n      code: 6048;\n      name: \"unauthorizedAddress\";\n      msg: \"Unauthorized address\";\n    },\n    {\n      code: 6049;\n      name: \"operatorsAreTheSame\";\n      msg: \"Cannot update because operators are the same\";\n    },\n    {\n      code: 6050;\n      name: \"withdrawToWrongTokenAccount\";\n      msg: \"Withdraw to wrong token account\";\n    },\n    {\n      code: 6051;\n      name: \"wrongRentReceiver\";\n      msg: \"Wrong rent receiver\";\n    },\n    {\n      code: 6052;\n      name: \"alreadyPassActivationPoint\";\n      msg: \"Already activated\";\n    },\n    {\n      code: 6053;\n      name: \"exceedMaxSwappedAmount\";\n      msg: \"Swapped amount is exceeded max swapped amount\";\n    },\n    {\n      code: 6054;\n      name: \"invalidStrategyParameters\";\n      msg: \"Invalid strategy parameters\";\n    },\n    {\n      code: 6055;\n      name: \"liquidityLocked\";\n      msg: \"Liquidity locked\";\n    },\n    {\n      code: 6056;\n      name: \"binRangeIsNotEmpty\";\n      msg: \"Bin range is not empty\";\n    },\n    {\n      code: 6057;\n      name: \"notExactAmountOut\";\n      msg: \"Amount out is not matched with exact amount out\";\n    },\n    {\n      code: 6058;\n      name: \"invalidActivationType\";\n      msg: \"Invalid activation type\";\n    },\n    {\n      code: 6059;\n      name: \"invalidActivationDuration\";\n      msg: \"Invalid activation duration\";\n    },\n    {\n      code: 6060;\n      name: \"missingTokenAmountAsTokenLaunchProof\";\n      msg: \"Missing token amount as token launch owner proof\";\n    },\n    {\n      code: 6061;\n      name: \"invalidQuoteToken\";\n      msg: \"Quote token must be SOL or USDC\";\n    },\n    {\n      code: 6062;\n      name: \"invalidBinStep\";\n      msg: \"Invalid bin step\";\n    },\n    {\n      code: 6063;\n      name: \"invalidBaseFee\";\n      msg: \"Invalid base fee\";\n    },\n    {\n      code: 6064;\n      name: \"invalidPreActivationDuration\";\n      msg: \"Invalid pre-activation duration\";\n    },\n    {\n      code: 6065;\n      name: \"alreadyPassPreActivationSwapPoint\";\n      msg: \"Already pass pre-activation swap point\";\n    },\n    {\n      code: 6066;\n      name: \"invalidStatus\";\n      msg: \"Invalid status\";\n    },\n    {\n      code: 6067;\n      name: \"exceededMaxOracleLength\";\n      msg: \"Exceed max oracle length\";\n    },\n    {\n      code: 6068;\n      name: \"invalidMinimumLiquidity\";\n      msg: \"Invalid minimum liquidity\";\n    },\n    {\n      code: 6069;\n      name: \"notSupportMint\";\n      msg: \"Not support token_2022 mint extension\";\n    },\n    {\n      code: 6070;\n      name: \"unsupportedMintExtension\";\n      msg: \"Unsupported mint extension\";\n    },\n    {\n      code: 6071;\n      name: \"unsupportNativeMintToken2022\";\n      msg: \"Unsupported native mint token2022\";\n    },\n    {\n      code: 6072;\n      name: \"unmatchTokenMint\";\n      msg: \"Unmatch token mint\";\n    },\n    {\n      code: 6073;\n      name: \"unsupportedTokenMint\";\n      msg: \"Unsupported token mint\";\n    },\n    {\n      code: 6074;\n      name: \"insufficientRemainingAccounts\";\n      msg: \"Insufficient remaining accounts\";\n    },\n    {\n      code: 6075;\n      name: \"invalidRemainingAccountSlice\";\n      msg: \"Invalid remaining account slice\";\n    },\n    {\n      code: 6076;\n      name: \"duplicatedRemainingAccountTypes\";\n      msg: \"Duplicated remaining account types\";\n    },\n    {\n      code: 6077;\n      name: \"missingRemainingAccountForTransferHook\";\n      msg: \"Missing remaining account for transfer hook\";\n    },\n    {\n      code: 6078;\n      name: \"noTransferHookProgram\";\n      msg: \"Remaining account was passed for transfer hook but there's no hook program\";\n    },\n    {\n      code: 6079;\n      name: \"zeroFundedAmount\";\n      msg: \"Zero funded amount\";\n    },\n    {\n      code: 6080;\n      name: \"invalidSide\";\n      msg: \"Invalid side\";\n    },\n    {\n      code: 6081;\n      name: \"invalidResizeLength\";\n      msg: \"Invalid resize length\";\n    },\n    {\n      code: 6082;\n      name: \"notSupportAtTheMoment\";\n      msg: \"Not support at the moment\";\n    },\n    {\n      code: 6083;\n      name: \"invalidRebalanceParameters\";\n      msg: \"Invalid rebalance parameters\";\n    },\n    {\n      code: 6084;\n      name: \"invalidRewardAccounts\";\n      msg: \"Invalid reward accounts\";\n    },\n    {\n      code: 6085;\n      name: \"undeterminedError\";\n      msg: \"Undetermined error\";\n    },\n    {\n      code: 6086;\n      name: \"reallocExceedMaxLengthPerInstruction\";\n      msg: \"Realloc exceed max length per instruction\";\n    },\n    {\n      code: 6087;\n      name: \"invalidBaseFeeMantissa\";\n      msg: \"Mantissa cannot more than two significant digits\";\n    },\n    {\n      code: 6088;\n      name: \"invalidPositionOwner\";\n      msg: \"Invalid position owner\";\n    },\n    {\n      code: 6089;\n      name: \"invalidPoolAddress\";\n      msg: \"Invalid pool address\";\n    },\n    {\n      code: 6090;\n      name: \"invalidTokenBadgeType\";\n      msg: \"Invalid token badge type\";\n    },\n    {\n      code: 6091;\n      name: \"invalidTransferHookAuthority\";\n      msg: \"Invalid transfer hook authority\";\n    },\n    {\n      code: 6092;\n      name: \"amountXIsNegative\";\n      msg: \"Amount x is negative\";\n    },\n    {\n      code: 6093;\n      name: \"amountYIsNegative\";\n      msg: \"Amount y is negative\";\n    },\n    {\n      code: 6094;\n      name: \"invalidPoolCreator\";\n      msg: \"Invalid pool creator\";\n    },\n    {\n      code: 6095;\n      name: \"invalidFunctionType\";\n      msg: \"Invalid function type\";\n    },\n    {\n      code: 6096;\n      name: \"invalidPermission\";\n      msg: \"Invalid permission\";\n    },\n    {\n      code: 6097;\n      name: \"incorrectAta\";\n      msg: \"Incorrect ATA\";\n    },\n    {\n      code: 6098;\n      name: \"invalidWithdrawProtocolFeeZapAccounts\";\n      msg: \"Invalid withdraw protocol fee zap accounts\";\n    },\n    {\n      code: 6099;\n      name: \"mintRestrictedFromZap\";\n      msg: \"SOL,USDC protocol fee cannot be withdrawn via zap\";\n    },\n    {\n      code: 6100;\n      name: \"cpiDisabled\";\n      msg: \"CPI disabled\";\n    },\n    {\n      code: 6101;\n      name: \"missingZapOutInstruction\";\n      msg: \"Missing zap out instruction\";\n    },\n    {\n      code: 6102;\n      name: \"invalidZapAccounts\";\n      msg: \"Invalid zap accounts\";\n    },\n    {\n      code: 6103;\n      name: \"invalidZapOutParameters\";\n      msg: \"Invalid zap out parameters\";\n    }\n  ];\n  types: [\n    {\n      name: \"accountsType\";\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"transferHookX\";\n          },\n          {\n            name: \"transferHookY\";\n          },\n          {\n            name: \"transferHookReward\";\n          },\n          {\n            name: \"transferHookMultiReward\";\n            fields: [\"u8\"];\n          }\n        ];\n      };\n    },\n    {\n      name: \"activationType\";\n      docs: [\"Type of the activation\"];\n      repr: {\n        kind: \"rust\";\n      };\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"slot\";\n          },\n          {\n            name: \"timestamp\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"addLiquidity\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"from\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"amounts\";\n            type: {\n              array: [\"u64\", 2];\n            };\n          },\n          {\n            name: \"activeBinId\";\n            type: \"i32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"addLiquidityParams\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"minDeltaId\";\n            type: \"i32\";\n          },\n          {\n            name: \"maxDeltaId\";\n            type: \"i32\";\n          },\n          {\n            name: \"x0\";\n            type: \"u64\";\n          },\n          {\n            name: \"y0\";\n            type: \"u64\";\n          },\n          {\n            name: \"deltaX\";\n            type: \"u64\";\n          },\n          {\n            name: \"deltaY\";\n            type: \"u64\";\n          },\n          {\n            name: \"bitFlag\";\n            type: \"u8\";\n          },\n          {\n            name: \"favorXInActiveId\";\n            type: \"bool\";\n          },\n          {\n            name: \"padding\";\n            type: {\n              array: [\"u8\", 16];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"addLiquiditySingleSidePreciseParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"bins\";\n            type: {\n              vec: {\n                defined: {\n                  name: \"compressedBinDepositAmount\";\n                };\n              };\n            };\n          },\n          {\n            name: \"decompressMultiplier\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"addLiquiditySingleSidePreciseParameter2\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"bins\";\n            type: {\n              vec: {\n                defined: {\n                  name: \"compressedBinDepositAmount\";\n                };\n              };\n            };\n          },\n          {\n            name: \"decompressMultiplier\";\n            type: \"u64\";\n          },\n          {\n            name: \"maxAmount\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"baseFeeParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"protocolShare\";\n            docs: [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            docs: [\"Base factor for base fee rate\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            docs: [\"Base fee power factor\"];\n            type: \"u8\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"bin\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amountX\";\n            docs: [\n              \"Amount of token X in the bin. This already excluded protocol fees.\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"amountY\";\n            docs: [\n              \"Amount of token Y in the bin. This already excluded protocol fees.\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"price\";\n            docs: [\"Bin price\"];\n            type: \"u128\";\n          },\n          {\n            name: \"liquiditySupply\";\n            docs: [\n              \"Liquidities of the bin. This is the same as LP mint supply. q-number\"\n            ];\n            type: \"u128\";\n          },\n          {\n            name: \"functionBytes\";\n            docs: [\n              \"function bytes, could be used for liquidity mining or other functions in future\"\n            ];\n            type: {\n              array: [\"u128\", 2];\n            };\n          },\n          {\n            name: \"feeAmountXPerTokenStored\";\n            docs: [\"Swap fee amount of token X per liquidity deposited.\"];\n            type: \"u128\";\n          },\n          {\n            name: \"feeAmountYPerTokenStored\";\n            docs: [\"Swap fee amount of token Y per liquidity deposited.\"];\n            type: \"u128\";\n          },\n          {\n            name: \"padding0\";\n            docs: [\n              \"_padding_0, previous amount_x_in, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: \"u128\";\n          },\n          {\n            name: \"padding1\";\n            docs: [\n              \"_padding_1, previous amount_y_in, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: \"u128\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"binArray\";\n      docs: [\n        \"An account to contain a range of bin. For example: Bin 100 <-> 200.\",\n        \"For example:\",\n        \"BinArray index: 0 contains bin 0 <-> 599\",\n        \"index: 2 contains bin 600 <-> 1199, ...\"\n      ];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"index\";\n            type: \"i64\";\n          },\n          {\n            name: \"version\";\n            type: \"u8\";\n          },\n          {\n            name: \"padding1\";\n            type: {\n              array: [\"u8\", 7];\n            };\n          },\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"bins\";\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"bin\";\n                  };\n                },\n                70\n              ];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"binArrayBitmapExtension\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"positiveBinArrayBitmap\";\n            docs: [\n              \"Packed initialized bin array state for start_bin_index is positive\"\n            ];\n            type: {\n              array: [\n                {\n                  array: [\"u64\", 8];\n                },\n                12\n              ];\n            };\n          },\n          {\n            name: \"negativeBinArrayBitmap\";\n            docs: [\n              \"Packed initialized bin array state for start_bin_index is negative\"\n            ];\n            type: {\n              array: [\n                {\n                  array: [\"u64\", 8];\n                },\n                12\n              ];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"binLiquidityDistribution\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binId\";\n            docs: [\"Define the bin ID wish to deposit to.\"];\n            type: \"i32\";\n          },\n          {\n            name: \"distributionX\";\n            docs: [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"distributionY\";\n            docs: [\n              \"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin.\"\n            ];\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"binLiquidityDistributionByWeight\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binId\";\n            docs: [\"Define the bin ID wish to deposit to.\"];\n            type: \"i32\";\n          },\n          {\n            name: \"weight\";\n            docs: [\"weight of liquidity distributed for this bin id\"];\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"binLiquidityReduction\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binId\";\n            type: \"i32\";\n          },\n          {\n            name: \"bpsToRemove\";\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"claimFee\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"feeX\";\n            type: \"u64\";\n          },\n          {\n            name: \"feeY\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"claimFee2\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"feeX\";\n            type: \"u64\";\n          },\n          {\n            name: \"feeY\";\n            type: \"u64\";\n          },\n          {\n            name: \"activeBinId\";\n            type: \"i32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"claimFeeOperator\";\n      docs: [\"Parameter that set by the protocol\"];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"operator\";\n            docs: [\"operator\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Reserve\"];\n            type: {\n              array: [\"u8\", 128];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"claimReward\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"totalReward\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"claimReward2\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"totalReward\";\n            type: \"u64\";\n          },\n          {\n            name: \"activeBinId\";\n            type: \"i32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"compositionFee\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"from\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"binId\";\n            type: \"i16\";\n          },\n          {\n            name: \"tokenXFeeAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"tokenYFeeAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"protocolTokenXFeeAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"protocolTokenYFeeAmount\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"compressedBinDepositAmount\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binId\";\n            type: \"i32\";\n          },\n          {\n            name: \"amount\";\n            type: \"u32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"customizableParams\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"activeId\";\n            docs: [\"Pool price\"];\n            type: \"i32\";\n          },\n          {\n            name: \"binStep\";\n            docs: [\"Bin step\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            docs: [\"Base factor\"];\n            type: \"u16\";\n          },\n          {\n            name: \"activationType\";\n            docs: [\n              \"Activation type. 0 = Slot, 1 = Time. Check ActivationType enum\"\n            ];\n            type: \"u8\";\n          },\n          {\n            name: \"hasAlphaVault\";\n            docs: [\"Whether the pool has an alpha vault\"];\n            type: \"bool\";\n          },\n          {\n            name: \"activationPoint\";\n            docs: [\"Decide when does the pool start trade. None = Now\"];\n            type: {\n              option: \"u64\";\n            };\n          },\n          {\n            name: \"creatorPoolOnOffControl\";\n            docs: [\n              \"Pool creator have permission to enable/disable pool with restricted program validation. Only applicable for customizable permissionless pool.\"\n            ];\n            type: \"bool\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            docs: [\"Base fee power factor\"];\n            type: \"u8\";\n          },\n          {\n            name: \"functionType\";\n            docs: [\"function type\"];\n            type: \"u8\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Padding, for future use\"];\n            type: {\n              array: [\"u8\", 61];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"decreasePositionLength\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"lengthToRemove\";\n            type: \"u16\";\n          },\n          {\n            name: \"side\";\n            type: \"u8\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"dummyIx\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"pairStatus\";\n            type: {\n              defined: {\n                name: \"pairStatus\";\n              };\n            };\n          },\n          {\n            name: \"pairType\";\n            type: {\n              defined: {\n                name: \"pairType\";\n              };\n            };\n          },\n          {\n            name: \"activationType\";\n            type: {\n              defined: {\n                name: \"activationType\";\n              };\n            };\n          },\n          {\n            name: \"tokenProgramFlag\";\n            type: {\n              defined: {\n                name: \"tokenProgramFlags\";\n              };\n            };\n          },\n          {\n            name: \"resizeSide\";\n            type: {\n              defined: {\n                name: \"resizeSide\";\n              };\n            };\n          },\n          {\n            name: \"rounding\";\n            type: {\n              defined: {\n                name: \"rounding\";\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"dummyZcAccount\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"positionBinData\";\n            type: {\n              defined: {\n                name: \"positionBinData\";\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"dynamicFeeParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"dynamicFeeParameterUpdate\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"feeInfo\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"feeXPerTokenComplete\";\n            type: \"u128\";\n          },\n          {\n            name: \"feeYPerTokenComplete\";\n            type: \"u128\";\n          },\n          {\n            name: \"feeXPending\";\n            type: \"u64\";\n          },\n          {\n            name: \"feeYPending\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"feeParameterUpdate\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"protocolShare\";\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"fundReward\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"funder\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"amount\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"goToABin\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"fromBinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"toBinId\";\n            type: \"i32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"increaseObservation\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"oracle\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"newObservationLength\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"increasePositionLength\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"lengthToAdd\";\n            type: \"u16\";\n          },\n          {\n            name: \"side\";\n            type: \"u8\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"initPermissionPairIx\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"activeId\";\n            type: \"i32\";\n          },\n          {\n            name: \"binStep\";\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            type: \"u16\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            type: \"u8\";\n          },\n          {\n            name: \"activationType\";\n            type: \"u8\";\n          },\n          {\n            name: \"protocolShare\";\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"initPresetParametersIx\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"index\";\n            type: \"u16\";\n          },\n          {\n            name: \"binStep\";\n            docs: [\"Bin step. Represent the price increment / decrement.\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            docs: [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"protocolShare\";\n            docs: [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            docs: [\"Base fee power factor\"];\n            type: \"u8\";\n          },\n          {\n            name: \"functionType\";\n            docs: [\"function type\"];\n            type: \"u8\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"initializeLbPair2Params\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"activeId\";\n            docs: [\"Pool price\"];\n            type: \"i32\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Padding, for future use\"];\n            type: {\n              array: [\"u8\", 96];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"initializeReward\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardMint\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"funder\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"rewardDuration\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"lbPair\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"parameters\";\n            type: {\n              defined: {\n                name: \"staticParameters\";\n              };\n            };\n          },\n          {\n            name: \"vParameters\";\n            type: {\n              defined: {\n                name: \"variableParameters\";\n              };\n            };\n          },\n          {\n            name: \"bumpSeed\";\n            type: {\n              array: [\"u8\", 1];\n            };\n          },\n          {\n            name: \"binStepSeed\";\n            docs: [\"Bin step signer seed\"];\n            type: {\n              array: [\"u8\", 2];\n            };\n          },\n          {\n            name: \"pairType\";\n            docs: [\"Type of the pair\"];\n            type: \"u8\";\n          },\n          {\n            name: \"activeId\";\n            docs: [\"Active bin id\"];\n            type: \"i32\";\n          },\n          {\n            name: \"binStep\";\n            docs: [\"Bin step. Represent the price increment / decrement.\"];\n            type: \"u16\";\n          },\n          {\n            name: \"status\";\n            docs: [\"Status of the pair. Check PairStatus enum.\"];\n            type: \"u8\";\n          },\n          {\n            name: \"requireBaseFactorSeed\";\n            docs: [\"Require base factor seed\"];\n            type: \"u8\";\n          },\n          {\n            name: \"baseFactorSeed\";\n            docs: [\"Base factor seed\"];\n            type: {\n              array: [\"u8\", 2];\n            };\n          },\n          {\n            name: \"activationType\";\n            docs: [\"Activation type\"];\n            type: \"u8\";\n          },\n          {\n            name: \"creatorPoolOnOffControl\";\n            docs: [\n              \"Allow pool creator to enable/disable pool with restricted validation. Only applicable for customizable permissionless pair type.\"\n            ];\n            type: \"u8\";\n          },\n          {\n            name: \"tokenXMint\";\n            docs: [\"Token X mint\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"tokenYMint\";\n            docs: [\"Token Y mint\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"reserveX\";\n            docs: [\"LB token X vault\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"reserveY\";\n            docs: [\"LB token Y vault\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"protocolFee\";\n            docs: [\"Uncollected protocol fee\"];\n            type: {\n              defined: {\n                name: \"protocolFee\";\n              };\n            };\n          },\n          {\n            name: \"padding1\";\n            docs: [\n              \"_padding_1, previous Fee owner, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: {\n              array: [\"u8\", 32];\n            };\n          },\n          {\n            name: \"rewardInfos\";\n            docs: [\"Farming reward information\"];\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"rewardInfo\";\n                  };\n                },\n                2\n              ];\n            };\n          },\n          {\n            name: \"oracle\";\n            docs: [\"Oracle pubkey\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"binArrayBitmap\";\n            docs: [\"Packed initialized bin array state\"];\n            type: {\n              array: [\"u64\", 16];\n            };\n          },\n          {\n            name: \"lastUpdatedAt\";\n            docs: [\"Last time the pool fee parameter was updated\"];\n            type: \"i64\";\n          },\n          {\n            name: \"padding2\";\n            docs: [\n              \"_padding_2, previous whitelisted_wallet, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: {\n              array: [\"u8\", 32];\n            };\n          },\n          {\n            name: \"preActivationSwapAddress\";\n            docs: [\n              \"Address allowed to swap when the current point is greater than or equal to the pre-activation point. The pre-activation point is calculated as `activation_point - pre_activation_duration`.\"\n            ];\n            type: \"pubkey\";\n          },\n          {\n            name: \"baseKey\";\n            docs: [\"Base keypair. Only required for permission pair\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"activationPoint\";\n            docs: [\n              \"Time point to enable the pair. Only applicable for permission pair.\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"preActivationDuration\";\n            docs: [\n              \"Duration before activation activation_point. Used to calculate pre-activation time point for pre_activation_swap_address\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"padding3\";\n            docs: [\n              \"_padding 3 is reclaimed free space from swap_cap_deactivate_point and swap_cap_amount before, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: {\n              array: [\"u8\", 8];\n            };\n          },\n          {\n            name: \"padding4\";\n            docs: [\n              \"_padding_4, previous lock_duration, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"creator\";\n            docs: [\"Pool creator\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"tokenMintXProgramFlag\";\n            docs: [\"tokenMintXProgramFlag\"];\n            type: \"u8\";\n          },\n          {\n            name: \"tokenMintYProgramFlag\";\n            docs: [\"tokenMintYProgramFlag\"];\n            type: \"u8\";\n          },\n          {\n            name: \"version\";\n            docs: [\"version to know whether we have reset tombstone fields\"];\n            type: \"u8\";\n          },\n          {\n            name: \"reserved\";\n            docs: [\"Reserved space for future use\"];\n            type: {\n              array: [\"u8\", 21];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"lbPairCreate\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"binStep\";\n            type: \"u16\";\n          },\n          {\n            name: \"tokenX\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"tokenY\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"liquidityOneSideParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amount\";\n            docs: [\"Amount of X token or Y token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"activeId\";\n            docs: [\"Active bin that integrator observe off-chain\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxActiveBinSlippage\";\n            docs: [\"max active bin slippage allowed\"];\n            type: \"i32\";\n          },\n          {\n            name: \"binLiquidityDist\";\n            docs: [\"Liquidity distribution to each bins\"];\n            type: {\n              vec: {\n                defined: {\n                  name: \"binLiquidityDistributionByWeight\";\n                };\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"liquidityParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amountX\";\n            docs: [\"Amount of X token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"amountY\";\n            docs: [\"Amount of Y token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"binLiquidityDist\";\n            docs: [\"Liquidity distribution to each bins\"];\n            type: {\n              vec: {\n                defined: {\n                  name: \"binLiquidityDistribution\";\n                };\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"liquidityParameterByStrategy\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amountX\";\n            docs: [\"Amount of X token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"amountY\";\n            docs: [\"Amount of Y token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"activeId\";\n            docs: [\"Active bin that integrator observe off-chain\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxActiveBinSlippage\";\n            docs: [\"max active bin slippage allowed\"];\n            type: \"i32\";\n          },\n          {\n            name: \"strategyParameters\";\n            docs: [\"strategy parameters\"];\n            type: {\n              defined: {\n                name: \"strategyParameters\";\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"liquidityParameterByStrategyOneSide\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amount\";\n            docs: [\"Amount of X token or Y token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"activeId\";\n            docs: [\"Active bin that integrator observe off-chain\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxActiveBinSlippage\";\n            docs: [\"max active bin slippage allowed\"];\n            type: \"i32\";\n          },\n          {\n            name: \"strategyParameters\";\n            docs: [\"strategy parameters\"];\n            type: {\n              defined: {\n                name: \"strategyParameters\";\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"liquidityParameterByWeight\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amountX\";\n            docs: [\"Amount of X token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"amountY\";\n            docs: [\"Amount of Y token to deposit\"];\n            type: \"u64\";\n          },\n          {\n            name: \"activeId\";\n            docs: [\"Active bin that integrator observe off-chain\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxActiveBinSlippage\";\n            docs: [\"max active bin slippage allowed\"];\n            type: \"i32\";\n          },\n          {\n            name: \"binLiquidityDist\";\n            docs: [\"Liquidity distribution to each bins\"];\n            type: {\n              vec: {\n                defined: {\n                  name: \"binLiquidityDistributionByWeight\";\n                };\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"operator\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"signer\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"permission\";\n            type: \"u128\";\n          },\n          {\n            name: \"padding\";\n            type: {\n              array: [\"u64\", 2];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"oracle\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"idx\";\n            docs: [\"Index of latest observation\"];\n            type: \"u64\";\n          },\n          {\n            name: \"activeSize\";\n            docs: [\n              \"Size of active sample. Active sample is initialized observation.\"\n            ];\n            type: \"u64\";\n          },\n          {\n            name: \"length\";\n            docs: [\"Number of observations\"];\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"pairStatus\";\n      docs: [\n        \"Pair status. 0 = Enabled, 1 = Disabled. Putting 0 as enabled for backward compatibility.\"\n      ];\n      repr: {\n        kind: \"rust\";\n      };\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"enabled\";\n          },\n          {\n            name: \"disabled\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"pairType\";\n      docs: [\n        \"Type of the Pair. 0 = Permissionless, 1 = Permission, 2 = CustomizablePermissionless. Putting 0 as permissionless for backward compatibility.\"\n      ];\n      repr: {\n        kind: \"rust\";\n      };\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"permissionless\";\n          },\n          {\n            name: \"permission\";\n          },\n          {\n            name: \"customizablePermissionless\";\n          },\n          {\n            name: \"permissionlessV2\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"position\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            docs: [\"The LB pair of this position\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            docs: [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ];\n            type: \"pubkey\";\n          },\n          {\n            name: \"liquidityShares\";\n            docs: [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ];\n            type: {\n              array: [\"u64\", 70];\n            };\n          },\n          {\n            name: \"rewardInfos\";\n            docs: [\"Farming reward information\"];\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"userRewardInfo\";\n                  };\n                },\n                70\n              ];\n            };\n          },\n          {\n            name: \"feeInfos\";\n            docs: [\"Swap fee to claim information\"];\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"feeInfo\";\n                  };\n                },\n                70\n              ];\n            };\n          },\n          {\n            name: \"lowerBinId\";\n            docs: [\"Lower bin ID\"];\n            type: \"i32\";\n          },\n          {\n            name: \"upperBinId\";\n            docs: [\"Upper bin ID\"];\n            type: \"i32\";\n          },\n          {\n            name: \"lastUpdatedAt\";\n            docs: [\"Last updated timestamp\"];\n            type: \"i64\";\n          },\n          {\n            name: \"totalClaimedFeeXAmount\";\n            docs: [\"Total claimed token fee X\"];\n            type: \"u64\";\n          },\n          {\n            name: \"totalClaimedFeeYAmount\";\n            docs: [\"Total claimed token fee Y\"];\n            type: \"u64\";\n          },\n          {\n            name: \"totalClaimedRewards\";\n            docs: [\"Total claimed rewards\"];\n            type: {\n              array: [\"u64\", 2];\n            };\n          },\n          {\n            name: \"reserved\";\n            docs: [\"Reserved space for future use\"];\n            type: {\n              array: [\"u8\", 160];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"positionBinData\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"liquidityShare\";\n            type: \"u128\";\n          },\n          {\n            name: \"rewardInfo\";\n            type: {\n              defined: {\n                name: \"userRewardInfo\";\n              };\n            };\n          },\n          {\n            name: \"feeInfo\";\n            type: {\n              defined: {\n                name: \"feeInfo\";\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"positionClose\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"positionCreate\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"positionV2\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            docs: [\"The LB pair of this position\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            docs: [\n              \"Owner of the position. Client rely on this to to fetch their positions.\"\n            ];\n            type: \"pubkey\";\n          },\n          {\n            name: \"liquidityShares\";\n            docs: [\n              \"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept.\"\n            ];\n            type: {\n              array: [\"u128\", 70];\n            };\n          },\n          {\n            name: \"rewardInfos\";\n            docs: [\"Farming reward information\"];\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"userRewardInfo\";\n                  };\n                },\n                70\n              ];\n            };\n          },\n          {\n            name: \"feeInfos\";\n            docs: [\"Swap fee to claim information\"];\n            type: {\n              array: [\n                {\n                  defined: {\n                    name: \"feeInfo\";\n                  };\n                },\n                70\n              ];\n            };\n          },\n          {\n            name: \"lowerBinId\";\n            docs: [\"Lower bin ID\"];\n            type: \"i32\";\n          },\n          {\n            name: \"upperBinId\";\n            docs: [\"Upper bin ID\"];\n            type: \"i32\";\n          },\n          {\n            name: \"lastUpdatedAt\";\n            docs: [\"Last updated timestamp\"];\n            type: \"i64\";\n          },\n          {\n            name: \"totalClaimedFeeXAmount\";\n            docs: [\"Total claimed token fee X\"];\n            type: \"u64\";\n          },\n          {\n            name: \"totalClaimedFeeYAmount\";\n            docs: [\"Total claimed token fee Y\"];\n            type: \"u64\";\n          },\n          {\n            name: \"totalClaimedRewards\";\n            docs: [\"Total claimed rewards\"];\n            type: {\n              array: [\"u64\", 2];\n            };\n          },\n          {\n            name: \"operator\";\n            docs: [\"Operator of position\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"lockReleasePoint\";\n            docs: [\"Time point which the locked liquidity can be withdraw\"];\n            type: \"u64\";\n          },\n          {\n            name: \"padding0\";\n            docs: [\n              \"_padding_0, previous subjected_to_bootstrap_liquidity_locking, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!\"\n            ];\n            type: \"u8\";\n          },\n          {\n            name: \"feeOwner\";\n            docs: [\n              \"Address is able to claim fee in this position, only valid for bootstrap_liquidity_position\"\n            ];\n            type: \"pubkey\";\n          },\n          {\n            name: \"version\";\n            docs: [\"version to know whether we have reset tombstone fields\"];\n            type: \"u8\";\n          },\n          {\n            name: \"reserved\";\n            docs: [\"Reserved space for future use\"];\n            type: {\n              array: [\"u8\", 86];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"presetParameter\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binStep\";\n            docs: [\"Bin step. Represent the price increment / decrement.\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            docs: [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"minBinId\";\n            docs: [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ];\n            type: \"i32\";\n          },\n          {\n            name: \"maxBinId\";\n            docs: [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ];\n            type: \"i32\";\n          },\n          {\n            name: \"protocolShare\";\n            docs: [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ];\n            type: \"u16\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"presetParameter2\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"binStep\";\n            docs: [\"Bin step. Represent the price increment / decrement.\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFactor\";\n            docs: [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"protocolShare\";\n            docs: [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"index\";\n            docs: [\"index\"];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            docs: [\"Base fee power factor\"];\n            type: \"u8\";\n          },\n          {\n            name: \"functionType\";\n            docs: [\n              \"function type, to check whether the pool should have LM farming or other functions in the future, refer FunctionType\"\n            ];\n            type: \"u8\";\n          },\n          {\n            name: \"padding1\";\n            docs: [\"Padding 1 for future use\"];\n            type: {\n              array: [\"u64\", 20];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"protocolFee\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"amountX\";\n            type: \"u64\";\n          },\n          {\n            name: \"amountY\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"rebalanceLiquidityParams\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"activeId\";\n            docs: [\"active id\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxActiveBinSlippage\";\n            docs: [\"max active bin slippage allowed\"];\n            type: \"u16\";\n          },\n          {\n            name: \"shouldClaimFee\";\n            docs: [\"a flag to indicate that whether fee should be harvested\"];\n            type: \"bool\";\n          },\n          {\n            name: \"shouldClaimReward\";\n            docs: [\n              \"a flag to indicate that whether rewards should be harvested\"\n            ];\n            type: \"bool\";\n          },\n          {\n            name: \"minWithdrawXAmount\";\n            docs: [\"threshold for withdraw token x\"];\n            type: \"u64\";\n          },\n          {\n            name: \"maxDepositXAmount\";\n            docs: [\"threshold for deposit token x\"];\n            type: \"u64\";\n          },\n          {\n            name: \"minWithdrawYAmount\";\n            docs: [\"threshold for withdraw token y\"];\n            type: \"u64\";\n          },\n          {\n            name: \"maxDepositYAmount\";\n            docs: [\"threshold for deposit token y\"];\n            type: \"u64\";\n          },\n          {\n            name: \"shrinkMode\";\n            docs: [\"shrink mode\"];\n            type: \"u8\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"padding 32 bytes for future usage\"];\n            type: {\n              array: [\"u8\", 31];\n            };\n          },\n          {\n            name: \"removes\";\n            docs: [\"removes\"];\n            type: {\n              vec: {\n                defined: {\n                  name: \"removeLiquidityParams\";\n                };\n              };\n            };\n          },\n          {\n            name: \"adds\";\n            docs: [\"adds\"];\n            type: {\n              vec: {\n                defined: {\n                  name: \"addLiquidityParams\";\n                };\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"rebalancing\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"owner\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"activeBinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"xWithdrawnAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"xAddedAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"yWithdrawnAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"yAddedAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"xFeeAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"yFeeAmount\";\n            type: \"u64\";\n          },\n          {\n            name: \"oldMinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"oldMaxId\";\n            type: \"i32\";\n          },\n          {\n            name: \"newMinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"newMaxId\";\n            type: \"i32\";\n          },\n          {\n            name: \"rewards\";\n            type: {\n              array: [\"u64\", 2];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"remainingAccountsInfo\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"slices\";\n            type: {\n              vec: {\n                defined: {\n                  name: \"remainingAccountsSlice\";\n                };\n              };\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"remainingAccountsSlice\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"accountsType\";\n            type: {\n              defined: {\n                name: \"accountsType\";\n              };\n            };\n          },\n          {\n            name: \"length\";\n            type: \"u8\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"removeLiquidity\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"from\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"amounts\";\n            type: {\n              array: [\"u64\", 2];\n            };\n          },\n          {\n            name: \"activeBinId\";\n            type: \"i32\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"removeLiquidityParams\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"minBinId\";\n            type: {\n              option: \"i32\";\n            };\n          },\n          {\n            name: \"maxBinId\";\n            type: {\n              option: \"i32\";\n            };\n          },\n          {\n            name: \"bps\";\n            type: \"u16\";\n          },\n          {\n            name: \"padding\";\n            type: {\n              array: [\"u8\", 16];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"resizeSide\";\n      docs: [\"Side of resize, 0 for lower and 1 for upper\"];\n      repr: {\n        kind: \"rust\";\n      };\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"lower\";\n          },\n          {\n            name: \"upper\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"rewardInfo\";\n      docs: [\"Stores the state relevant for tracking liquidity mining rewards\"];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"mint\";\n            docs: [\"Reward token mint.\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"vault\";\n            docs: [\"Reward vault token account.\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"funder\";\n            docs: [\"Authority account that allows to fund rewards\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardDuration\";\n            docs: [\"LM reward duration in seconds.\"];\n            type: \"u64\";\n          },\n          {\n            name: \"rewardDurationEnd\";\n            docs: [\"LM reward duration end time.\"];\n            type: \"u64\";\n          },\n          {\n            name: \"rewardRate\";\n            docs: [\"LM reward rate\"];\n            type: \"u128\";\n          },\n          {\n            name: \"lastUpdateTime\";\n            docs: [\"The last time reward states were updated.\"];\n            type: \"u64\";\n          },\n          {\n            name: \"cumulativeSecondsWithEmptyLiquidityReward\";\n            docs: [\n              \"Accumulated seconds where when farm distribute rewards, but the bin is empty. The reward will be accumulated for next reward time window.\"\n            ];\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"rounding\";\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"up\";\n          },\n          {\n            name: \"down\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"staticParameters\";\n      docs: [\"Parameter that set by the protocol\"];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"baseFactor\";\n            docs: [\n              \"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"filterPeriod\";\n            docs: [\n              \"Filter period determine high frequency trading time window.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"decayPeriod\";\n            docs: [\n              \"Decay period determine when the volatile fee start decay / decrease.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"reductionFactor\";\n            docs: [\n              \"Reduction factor controls the volatile fee rate decrement rate.\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"variableFeeControl\";\n            docs: [\n              \"Used to scale the variable fee component depending on the dynamic of the market\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"maxVolatilityAccumulator\";\n            docs: [\n              \"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate.\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"minBinId\";\n            docs: [\n              \"Min bin id supported by the pool based on the configured bin step.\"\n            ];\n            type: \"i32\";\n          },\n          {\n            name: \"maxBinId\";\n            docs: [\n              \"Max bin id supported by the pool based on the configured bin step.\"\n            ];\n            type: \"i32\";\n          },\n          {\n            name: \"protocolShare\";\n            docs: [\n              \"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee\"\n            ];\n            type: \"u16\";\n          },\n          {\n            name: \"baseFeePowerFactor\";\n            docs: [\"Base fee power factor\"];\n            type: \"u8\";\n          },\n          {\n            name: \"functionType\";\n            docs: [\"function type\"];\n            type: \"u8\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Padding for bytemuck safe alignment\"];\n            type: {\n              array: [\"u8\", 4];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"strategyParameters\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"minBinId\";\n            docs: [\"min bin id\"];\n            type: \"i32\";\n          },\n          {\n            name: \"maxBinId\";\n            docs: [\"max bin id\"];\n            type: \"i32\";\n          },\n          {\n            name: \"strategyType\";\n            docs: [\"strategy type\"];\n            type: {\n              defined: {\n                name: \"strategyType\";\n              };\n            };\n          },\n          {\n            name: \"parameteres\";\n            docs: [\"parameters\"];\n            type: {\n              array: [\"u8\", 64];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"strategyType\";\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"spotOneSide\";\n          },\n          {\n            name: \"curveOneSide\";\n          },\n          {\n            name: \"bidAskOneSide\";\n          },\n          {\n            name: \"spotBalanced\";\n          },\n          {\n            name: \"curveBalanced\";\n          },\n          {\n            name: \"bidAskBalanced\";\n          },\n          {\n            name: \"spotImBalanced\";\n          },\n          {\n            name: \"curveImBalanced\";\n          },\n          {\n            name: \"bidAskImBalanced\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"swap\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"from\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"startBinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"endBinId\";\n            type: \"i32\";\n          },\n          {\n            name: \"amountIn\";\n            type: \"u64\";\n          },\n          {\n            name: \"amountOut\";\n            type: \"u64\";\n          },\n          {\n            name: \"swapForY\";\n            type: \"bool\";\n          },\n          {\n            name: \"fee\";\n            type: \"u64\";\n          },\n          {\n            name: \"protocolFee\";\n            type: \"u64\";\n          },\n          {\n            name: \"feeBps\";\n            type: \"u128\";\n          },\n          {\n            name: \"hostFee\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"tokenBadge\";\n      docs: [\"Parameter that set by the protocol\"];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"tokenMint\";\n            docs: [\"token mint\"];\n            type: \"pubkey\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Reserve\"];\n            type: {\n              array: [\"u8\", 128];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"tokenProgramFlags\";\n      repr: {\n        kind: \"rust\";\n      };\n      type: {\n        kind: \"enum\";\n        variants: [\n          {\n            name: \"tokenProgram\";\n          },\n          {\n            name: \"tokenProgram2022\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"updatePositionLockReleasePoint\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"currentPoint\";\n            type: \"u64\";\n          },\n          {\n            name: \"newLockReleasePoint\";\n            type: \"u64\";\n          },\n          {\n            name: \"oldLockReleasePoint\";\n            type: \"u64\";\n          },\n          {\n            name: \"sender\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"updatePositionOperator\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"position\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"oldOperator\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"newOperator\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"updateRewardDuration\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"oldRewardDuration\";\n            type: \"u64\";\n          },\n          {\n            name: \"newRewardDuration\";\n            type: \"u64\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"updateRewardFunder\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardIndex\";\n            type: \"u64\";\n          },\n          {\n            name: \"oldFunder\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"newFunder\";\n            type: \"pubkey\";\n          }\n        ];\n      };\n    },\n    {\n      name: \"userRewardInfo\";\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"rewardPerTokenCompletes\";\n            type: {\n              array: [\"u128\", 2];\n            };\n          },\n          {\n            name: \"rewardPendings\";\n            type: {\n              array: [\"u64\", 2];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"variableParameters\";\n      docs: [\"Parameters that changes based on dynamic of the market\"];\n      serialization: \"bytemuck\";\n      repr: {\n        kind: \"c\";\n      };\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"volatilityAccumulator\";\n            docs: [\n              \"Volatility accumulator measure the number of bin crossed since reference bin ID. Normally (without filter period taken into consideration), reference bin ID is the active bin of last swap.\",\n              \"It affects the variable fee rate\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"volatilityReference\";\n            docs: [\n              \"Volatility reference is decayed volatility accumulator. It is always <= volatility_accumulator\"\n            ];\n            type: \"u32\";\n          },\n          {\n            name: \"indexReference\";\n            docs: [\"Active bin id of last swap.\"];\n            type: \"i32\";\n          },\n          {\n            name: \"padding\";\n            docs: [\"Padding for bytemuck safe alignment\"];\n            type: {\n              array: [\"u8\", 4];\n            };\n          },\n          {\n            name: \"lastUpdateTimestamp\";\n            docs: [\"Last timestamp the variable parameters was updated\"];\n            type: \"i64\";\n          },\n          {\n            name: \"padding1\";\n            docs: [\"Padding for bytemuck safe alignment\"];\n            type: {\n              array: [\"u8\", 8];\n            };\n          }\n        ];\n      };\n    },\n    {\n      name: \"withdrawIneligibleReward\";\n      type: {\n        kind: \"struct\";\n        fields: [\n          {\n            name: \"lbPair\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"rewardMint\";\n            type: \"pubkey\";\n          },\n          {\n            name: \"amount\";\n            type: \"u64\";\n          }\n        ];\n      };\n    }\n  ];\n  constants: [\n    {\n      name: \"basisPointMax\";\n      type: \"i32\";\n      value: \"10000\";\n    },\n    {\n      name: \"binArray\";\n      type: \"bytes\";\n      value: \"[98, 105, 110, 95, 97, 114, 114, 97, 121]\";\n    },\n    {\n      name: \"binArrayBitmapSeed\";\n      type: \"bytes\";\n      value: \"[98, 105, 116, 109, 97, 112]\";\n    },\n    {\n      name: \"binArrayBitmapSize\";\n      type: \"i32\";\n      value: \"512\";\n    },\n    {\n      name: \"claimProtocolFeeOperator\";\n      type: \"bytes\";\n      value: \"[99, 102, 95, 111, 112, 101, 114, 97, 116, 111, 114]\";\n    },\n    {\n      name: \"defaultBinPerPosition\";\n      type: \"u64\";\n      value: \"70\";\n    },\n    {\n      name: \"extensionBinarrayBitmapSize\";\n      type: \"u64\";\n      value: \"12\";\n    },\n    {\n      name: \"feePrecision\";\n      type: \"u64\";\n      value: \"1000000000\";\n    },\n    {\n      name: \"hostFeeBps\";\n      docs: [\"Host fee. 20%\"];\n      type: \"u16\";\n      value: \"2000\";\n    },\n    {\n      name: \"ilmProtocolShare\";\n      type: \"u16\";\n      value: \"2000\";\n    },\n    {\n      name: \"maxBaseFee\";\n      docs: [\"Maximum base fee, base_fee / 10^9 = fee_in_percentage\"];\n      type: \"u128\";\n      value: \"100000000\";\n    },\n    {\n      name: \"maxBinIdPerBinStep\";\n      docs: [\n        \"Maximum bin ID per bin step. Computed based on 1 bps. Used for bin id bound estimation.\"\n      ];\n      type: \"i32\";\n      value: \"351639\";\n    },\n    {\n      name: \"maxBinPerArray\";\n      type: \"u64\";\n      value: \"70\";\n    },\n    {\n      name: \"maxBinStep\";\n      docs: [\"Maximum bin step\"];\n      type: \"u16\";\n      value: \"400\";\n    },\n    {\n      name: \"maxFeeRate\";\n      docs: [\"Maximum fee rate. 10%\"];\n      type: \"u64\";\n      value: \"100000000\";\n    },\n    {\n      name: \"maxProtocolShare\";\n      docs: [\"Maximum protocol share of the fee. 25%\"];\n      type: \"u16\";\n      value: \"2500\";\n    },\n    {\n      name: \"maxResizeLength\";\n      type: \"u64\";\n      value: \"91\";\n    },\n    {\n      name: \"maxRewardBinSplit\";\n      type: \"u64\";\n      value: \"15\";\n    },\n    {\n      name: \"maxRewardDuration\";\n      type: \"u64\";\n      value: \"31536000\";\n    },\n    {\n      name: \"minimumLiquidity\";\n      type: \"u128\";\n      value: \"1000000\";\n    },\n    {\n      name: \"minBaseFee\";\n      docs: [\"Minimum base fee\"];\n      type: \"u128\";\n      value: \"100000\";\n    },\n    {\n      name: \"minRewardDuration\";\n      type: \"u64\";\n      value: \"1\";\n    },\n    {\n      name: \"numRewards\";\n      type: \"u64\";\n      value: \"2\";\n    },\n    {\n      name: \"operatorPrefix\";\n      type: \"bytes\";\n      value: \"[111, 112, 101, 114, 97, 116, 111, 114]\";\n    },\n    {\n      name: \"oracle\";\n      type: \"bytes\";\n      value: \"[111, 114, 97, 99, 108, 101]\";\n    },\n    {\n      name: \"position\";\n      type: \"bytes\";\n      value: \"[112, 111, 115, 105, 116, 105, 111, 110]\";\n    },\n    {\n      name: \"positionMaxLength\";\n      type: \"u64\";\n      value: \"1400\";\n    },\n    {\n      name: \"presetParameter\";\n      type: \"bytes\";\n      value: \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114]\";\n    },\n    {\n      name: \"presetParameter2\";\n      type: \"bytes\";\n      value: \"[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114, 50]\";\n    },\n    {\n      name: \"protocolShare\";\n      type: \"u16\";\n      value: \"500\";\n    }\n  ];\n};\n"
  },
  {
    "path": "ts-client/src/dlmm/index.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport {\n  AccountLayout,\n  Mint,\n  NATIVE_MINT,\n  TOKEN_PROGRAM_ID,\n  createAssociatedTokenAccountIdempotentInstruction,\n  createTransferCheckedInstruction,\n  getAssociatedTokenAddressSync,\n  unpackAccount,\n  unpackMint,\n} from \"@solana/spl-token\";\nimport {\n  AccountMeta,\n  ComputeBudgetInstruction,\n  ComputeBudgetProgram,\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  PublicKey,\n  SYSVAR_CLOCK_PUBKEY,\n  SYSVAR_RENT_PUBKEY,\n  SystemProgram,\n  Transaction,\n  TransactionInstruction,\n} from \"@solana/web3.js\";\nimport Decimal from \"decimal.js\";\nimport {\n  ALT_ADDRESS,\n  BASIS_POINT_MAX,\n  BIN_ARRAY_BITMAP_FEE,\n  BIN_ARRAY_BITMAP_FEE_BN,\n  BIN_ARRAY_FEE,\n  BIN_ARRAY_FEE_BN,\n  DEFAULT_BIN_PER_POSITION,\n  FEE_PRECISION,\n  FunctionType,\n  MAX_ACTIVE_BIN_SLIPPAGE,\n  MAX_BINS_PER_POSITION,\n  MAX_BIN_ARRAY_SIZE,\n  MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX,\n  MAX_CLAIM_ALL_ALLOWED,\n  MAX_EXTRA_BIN_ARRAYS,\n  MAX_FEE_RATE,\n  MAX_RESIZE_LENGTH,\n  POSITION_FEE,\n  POSITION_FEE_BN,\n  POSITION_MAX_LENGTH,\n  PRECISION,\n  SCALE_OFFSET,\n  TOKEN_ACCOUNT_FEE_BN,\n  U64_MAX,\n} from \"./constants\";\nimport { DlmmSdkError } from \"./error\";\nimport {\n  Opt,\n  binIdToBinArrayIndex,\n  capSlippagePercentage,\n  chunkDepositWithRebalanceEndpoint,\n  chunkedGetMultipleAccountInfos,\n  chunkedGetProgramAccounts,\n  chunks,\n  computeFeeFromAmount,\n  createProgram,\n  decodeAccount,\n  deriveBinArray,\n  deriveBinArrayBitmapExtension,\n  deriveCustomizablePermissionlessLbPair,\n  deriveLbPair,\n  deriveLbPair2,\n  deriveLbPairWithPresetParamWithIndexKey,\n  deriveOracle,\n  derivePosition,\n  deriveReserve,\n  deriveTokenBadge,\n  enumerateBins,\n  findNextBinArrayIndexWithLiquidity,\n  findNextBinArrayWithLiquidity,\n  getAndCapMaxActiveBinSlippage,\n  getBinArrayLowerUpperBinId,\n  getBinCount,\n  getBinFromBinArray,\n  getEstimatedComputeUnitIxWithBuffer,\n  getOrCreateATAInstruction,\n  getOutAmount,\n  getPositionCountByBinCount,\n  getPriceOfBinByBinId,\n  getSlippageMaxAmount,\n  getSlippageMinAmount,\n  getTokenProgramId,\n  getTotalFee,\n  isBinIdWithinBinArray,\n  isOverflowDefaultBinArrayBitmap,\n  range,\n  swapExactInQuoteAtBin,\n  swapExactOutQuoteAtBin,\n  toStrategyParameters,\n  toWeightDistribution,\n  unwrapSOLInstruction,\n  wrapSOLInstruction,\n  wrapOracle,\n  IDynamicOracle,\n} from \"./helpers\";\nimport {\n  binArrayLbPairFilter,\n  positionLbPairFilter,\n  positionOwnerFilter,\n  positionV2Filter,\n  presetParameter2BaseFactorFilter,\n  presetParameter2BaseFeePowerFactor,\n  presetParameter2BinStepFilter,\n} from \"./helpers/accountFilters\";\nimport {\n  DEFAULT_ADD_LIQUIDITY_CU,\n  DEFAULT_INIT_BIN_ARRAY_CU,\n  DEFAULT_INIT_POSITION_CU,\n  getDefaultExtendPositionCU,\n  getSimulationComputeUnits,\n} from \"./helpers/computeUnit\";\nimport {\n  Rounding,\n  compressBinAmount,\n  computeBaseFactorFromFeeBps,\n  distributeAmountToCompressedBinsByRatio,\n  findOptimumDecompressMultiplier,\n  generateAmountForBinRange,\n  getPositionCount,\n  mulShr,\n} from \"./helpers/math\";\nimport {\n  IPosition,\n  chunkBinRange,\n  getBinArrayAccountMetasCoverage,\n  getBinArrayIndexesCoverage,\n  getExtendedPositionBinCount,\n  getPositionExpandRentExemption,\n  getPositionLowerUpperBinIdWithLiquidity,\n  isPositionNoFee,\n  isPositionNoReward,\n  wrapPosition,\n} from \"./helpers/positions\";\nimport {\n  RebalancePosition,\n  RebalanceWithDeposit,\n  RebalanceWithWithdraw,\n  buildLiquidityStrategyParameters,\n  getLiquidityStrategyParameterBuilder,\n  getRebalanceBinArrayIndexesAndBitmapCoverage,\n} from \"./helpers/rebalance\";\nimport { RebalanceStrategyBuilder } from \"./helpers/rebalance/strategy\";\nimport { BalancedStrategyBuilder } from \"./helpers/rebalance/strategy/balanced\";\nimport {\n  calculateTransferFeeExcludedAmount,\n  calculateTransferFeeIncludedAmount,\n  getExtraAccountMetasForTransferHook,\n  getMultipleMintsExtraAccountMetasForTransferHook,\n} from \"./helpers/token_2022\";\nimport {\n  ActionType,\n  ActivationType,\n  Bin,\n  BinAndAmount,\n  BinArray,\n  BinArrayAccount,\n  BinArrayBitmapExtension,\n  BinArrayBitmapExtensionAccount,\n  BinLiquidity,\n  BinLiquidityDistribution,\n  ClmmProgram,\n  Clock,\n  ClockLayout,\n  CompressedBinDepositAmounts,\n  EmissionRate,\n  FeeInfo,\n  InitCustomizablePermissionlessPairIx,\n  InitializeMultiplePositionAndAddLiquidityByStrategyResponse,\n  InitializeMultiplePositionAndAddLiquidityByStrategyResponse2,\n  LbPair,\n  LbPairAccount,\n  LbPosition,\n  LiquidityOneSideParameter,\n  LiquidityParameter,\n  LiquidityParameterByStrategy,\n  LiquidityParameterByWeight,\n  MEMO_PROGRAM_ID,\n  PairLockInfo,\n  PairStatus,\n  PairType,\n  PositionBinData,\n  PositionData,\n  PositionInfo,\n  PositionV2,\n  PositionVersion,\n  ProgramStrategyParameter,\n  REBALANCE_POSITION_PADDING,\n  RebalanceAddLiquidityParam,\n  RebalancePositionBinArrayRentalCostQuote,\n  RebalancePositionResponse,\n  RebalanceRemoveLiquidityParam,\n  RemainingAccountsInfoSlice,\n  ResizeSide,\n  SeedLiquidityResponse,\n  SeedLiquiditySingleBinResponse,\n  ShrinkMode,\n  StrategyParameters,\n  StrategyType,\n  SwapExactOutParams,\n  SwapParams,\n  SwapQuote,\n  SwapQuoteExactOut,\n  SwapWithPriceImpactParams,\n  TInitializePositionAndAddLiquidityParams,\n  TInitializePositionAndAddLiquidityParamsByStrategy,\n  TQuoteCreatePositionParams,\n  TokenReserve,\n  sParameters,\n  vParameters,\n  GetPositionsOpt,\n} from \"./types\";\n\nexport class DLMM {\n  constructor(\n    public pubkey: PublicKey,\n    public program: ClmmProgram,\n    public lbPair: LbPair,\n    public binArrayBitmapExtension: BinArrayBitmapExtensionAccount | null,\n    public tokenX: TokenReserve,\n    public tokenY: TokenReserve,\n    public rewards: Array<TokenReserve | null>,\n    public clock: Clock,\n    private opt?: Opt,\n  ) {}\n\n  /** Static public method */\n\n  /**\n   * The function `getLbPairs` retrieves a list of LB pair accounts using a connection and optional\n   * parameters.\n   * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`\n   * class, which represents the connection to the Solana blockchain network.\n   * @param {Opt} [opt] - The `opt` parameter is an optional object that contains additional options\n   * for the function. It can have the following properties:\n   * @returns The function `getLbPairs` returns a Promise that resolves to an array of\n   * `LbPairAccount` objects.\n   */\n  public static async getLbPairs(\n    connection: Connection,\n    opt?: Opt,\n  ): Promise<LbPairAccount[]> {\n    const program = createProgram(connection, opt);\n    return program.account.lbPair.all();\n  }\n\n  /**\n   * Retrieves the public key of a LB pair if it exists. This function expect the RPC have getProgramAccounts RPC method enabled.\n   * @param connection The connection to the Solana cluster.\n   * @param tokenX The mint address of token X.\n   * @param tokenY The mint address of token Y.\n   * @param binStep The bin step of the LB pair.\n   * @param baseFactor The base factor of the LB pair.\n   * @param baseFeePowerFactor The base fee power factor of the LB pair. It allow small bin step to have bigger fee rate.\n   * @param opt Optional parameters.\n   * @returns The public key of the LB pair if it exists, or null.\n   */\n  public static async getPairPubkeyIfExists(\n    connection: Connection,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    binStep: BN,\n    baseFactor: BN,\n    baseFeePowerFactor: BN,\n    opt?: Opt,\n  ): Promise<PublicKey | null> {\n    const program = createProgram(connection, opt);\n\n    const [lbPair2Key] = deriveLbPair2(\n      tokenX,\n      tokenY,\n      binStep,\n      baseFactor,\n      program.programId,\n    );\n    const account2 = await program.account.lbPair.fetchNullable(lbPair2Key);\n    if (\n      account2 &&\n      account2.parameters.baseFeePowerFactor == baseFeePowerFactor.toNumber()\n    ) {\n      return lbPair2Key;\n    }\n\n    const [lbPairKey] = deriveLbPair(\n      tokenX,\n      tokenY,\n      binStep,\n      program.programId,\n    );\n\n    const account = await program.account.lbPair.fetchNullable(lbPairKey);\n    if (\n      account &&\n      account.parameters.baseFactor === baseFactor.toNumber() &&\n      account.parameters.baseFeePowerFactor === baseFeePowerFactor.toNumber()\n    ) {\n      return lbPairKey;\n    }\n\n    const presetParametersWithIndex =\n      await program.account.presetParameter2.all([\n        presetParameter2BinStepFilter(binStep),\n        presetParameter2BaseFactorFilter(baseFactor),\n        presetParameter2BaseFeePowerFactor(baseFeePowerFactor),\n      ]);\n\n    if (presetParametersWithIndex.length > 0) {\n      const possibleLbPairKeys = presetParametersWithIndex.map((account) => {\n        return deriveLbPairWithPresetParamWithIndexKey(\n          account.publicKey,\n          tokenX,\n          tokenY,\n          program.programId,\n        )[0];\n      });\n\n      const accounts = await chunkedGetMultipleAccountInfos(\n        program.provider.connection,\n        possibleLbPairKeys,\n      );\n\n      for (let i = 0; i < possibleLbPairKeys.length; i++) {\n        const pairKey = possibleLbPairKeys[i];\n        const account = accounts[i];\n\n        if (account) {\n          return pairKey;\n        }\n      }\n    }\n\n    return null;\n  }\n\n  public static async getCustomizablePermissionlessLbPairIfExists(\n    connection: Connection,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    opt?: Opt,\n  ): Promise<PublicKey | null> {\n    const program = createProgram(connection, opt);\n\n    try {\n      const [lpPair] = deriveCustomizablePermissionlessLbPair(\n        tokenX,\n        tokenY,\n        program.programId,\n      );\n      const account = await program.account.lbPair.fetchNullable(lpPair);\n      if (account) return lpPair;\n\n      return null;\n    } catch (error) {\n      return null;\n    }\n  }\n\n  /**\n   * The `create` function is a static method that creates a new instance of the `DLMM` class\n   * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`\n   * class, which represents the connection to the Solana blockchain network.\n   * @param {PublicKey} dlmm - The PublicKey of LB Pair.\n   * @param {Opt} [opt] - The `opt` parameter is an optional object that can contain additional options\n   * for the `create` function. It has the following properties:\n   * @returns The `create` function returns a `Promise` that resolves to a `DLMM` object.\n   */\n  static async create(\n    connection: Connection,\n    dlmm: PublicKey,\n    opt?: Opt,\n  ): Promise<DLMM> {\n    const program = createProgram(connection, opt);\n\n    const binArrayBitMapExtensionPubkey = deriveBinArrayBitmapExtension(\n      dlmm,\n      program.programId,\n    )[0];\n    let accountsToFetch = [\n      dlmm,\n      binArrayBitMapExtensionPubkey,\n      SYSVAR_CLOCK_PUBKEY,\n    ];\n\n    const accountsInfo = await chunkedGetMultipleAccountInfos(\n      connection,\n      accountsToFetch,\n    );\n\n    const lbPairAccountInfoBuffer = accountsInfo[0]?.data;\n    if (!lbPairAccountInfoBuffer)\n      throw new Error(`LB Pair account ${dlmm.toBase58()} not found`);\n\n    const lbPairAccInfo = decodeAccount<LbPair>(\n      program,\n      \"lbPair\",\n      lbPairAccountInfoBuffer,\n    );\n\n    const binArrayBitMapAccountInfoBuffer = accountsInfo[1]?.data;\n\n    let binArrayBitMapExtensionAccInfo: BinArrayBitmapExtension | null = null;\n    if (binArrayBitMapAccountInfoBuffer) {\n      binArrayBitMapExtensionAccInfo = decodeAccount(\n        program,\n        \"binArrayBitmapExtension\",\n        binArrayBitMapAccountInfoBuffer,\n      );\n    }\n\n    const clockAccountInfoBuffer = accountsInfo[2]?.data;\n    if (!clockAccountInfoBuffer) throw new Error(`Clock account not found`);\n    const clock = ClockLayout.decode(clockAccountInfoBuffer) as Clock;\n\n    accountsToFetch = [\n      lbPairAccInfo.reserveX,\n      lbPairAccInfo.reserveY,\n      lbPairAccInfo.tokenXMint,\n      lbPairAccInfo.tokenYMint,\n      lbPairAccInfo.rewardInfos[0].vault,\n      lbPairAccInfo.rewardInfos[1].vault,\n      lbPairAccInfo.rewardInfos[0].mint,\n      lbPairAccInfo.rewardInfos[1].mint,\n    ];\n\n    const [\n      reserveXAccount,\n      reserveYAccount,\n      tokenXMintAccount,\n      tokenYMintAccount,\n      reward0VaultAccount,\n      reward1VaultAccount,\n      reward0MintAccount,\n      reward1MintAccount,\n    ] = await chunkedGetMultipleAccountInfos(\n      program.provider.connection,\n      accountsToFetch,\n    );\n\n    let binArrayBitmapExtension: BinArrayBitmapExtensionAccount | null;\n    if (binArrayBitMapExtensionAccInfo) {\n      binArrayBitmapExtension = {\n        account: binArrayBitMapExtensionAccInfo,\n        publicKey: binArrayBitMapExtensionPubkey,\n      };\n    }\n\n    const reserveXBalance = AccountLayout.decode(reserveXAccount.data);\n    const reserveYBalance = AccountLayout.decode(reserveYAccount.data);\n\n    const mintX = unpackMint(\n      lbPairAccInfo.tokenXMint,\n      tokenXMintAccount,\n      tokenXMintAccount.owner,\n    );\n\n    const mintY = unpackMint(\n      lbPairAccInfo.tokenYMint,\n      tokenYMintAccount,\n      tokenYMintAccount.owner,\n    );\n\n    const [\n      tokenXTransferHook,\n      tokenYTransferHook,\n      reward0TransferHook,\n      reward1TransferHook,\n    ] = await Promise.all([\n      getExtraAccountMetasForTransferHook(\n        connection,\n        lbPairAccInfo.tokenXMint,\n        tokenXMintAccount,\n      ),\n      getExtraAccountMetasForTransferHook(\n        connection,\n        lbPairAccInfo.tokenYMint,\n        tokenYMintAccount,\n      ),\n      reward0MintAccount\n        ? getExtraAccountMetasForTransferHook(\n            connection,\n            lbPairAccInfo.rewardInfos[0].mint,\n            reward0MintAccount,\n          )\n        : [],\n      reward1MintAccount\n        ? getExtraAccountMetasForTransferHook(\n            connection,\n            lbPairAccInfo.rewardInfos[1].mint,\n            reward1MintAccount,\n          )\n        : [],\n    ]);\n\n    const tokenX: TokenReserve = {\n      publicKey: lbPairAccInfo.tokenXMint,\n      reserve: lbPairAccInfo.reserveX,\n      amount: reserveXBalance.amount,\n      mint: mintX,\n      owner: tokenXMintAccount.owner,\n      transferHookAccountMetas: tokenXTransferHook,\n    };\n\n    const tokenY: TokenReserve = {\n      publicKey: lbPairAccInfo.tokenYMint,\n      reserve: lbPairAccInfo.reserveY,\n      amount: reserveYBalance.amount,\n      mint: mintY,\n      owner: tokenYMintAccount.owner,\n      transferHookAccountMetas: tokenYTransferHook,\n    };\n\n    const reward0: TokenReserve = !lbPairAccInfo.rewardInfos[0].mint.equals(\n      PublicKey.default,\n    )\n      ? {\n          publicKey: lbPairAccInfo.rewardInfos[0].mint,\n          reserve: lbPairAccInfo.rewardInfos[0].vault,\n          amount: AccountLayout.decode(reward0VaultAccount.data).amount,\n          mint: unpackMint(\n            lbPairAccInfo.rewardInfos[0].mint,\n            reward0MintAccount,\n            reward0MintAccount.owner,\n          ),\n          owner: reward0MintAccount.owner,\n          transferHookAccountMetas: reward0TransferHook,\n        }\n      : null;\n\n    const reward1: TokenReserve = !lbPairAccInfo.rewardInfos[1].mint.equals(\n      PublicKey.default,\n    )\n      ? {\n          publicKey: lbPairAccInfo.rewardInfos[1].mint,\n          reserve: lbPairAccInfo.rewardInfos[1].vault,\n          amount: AccountLayout.decode(reward1VaultAccount.data).amount,\n          mint: unpackMint(\n            lbPairAccInfo.rewardInfos[1].mint,\n            reward1MintAccount,\n            reward1MintAccount.owner,\n          ),\n          owner: reward1MintAccount.owner,\n          transferHookAccountMetas: reward1TransferHook,\n        }\n      : null;\n\n    return new DLMM(\n      dlmm,\n      program,\n      lbPairAccInfo,\n      binArrayBitmapExtension,\n      tokenX,\n      tokenY,\n      [reward0, reward1],\n      clock,\n      opt,\n    );\n  }\n\n  /**\n   * Similar to `create` function, but it accept multiple lbPairs to be initialized.\n   * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`\n   * class, which represents the connection to the Solana blockchain network.\n   * @param dlmmList - An Array of PublicKey of LB Pairs.\n   * @param {Opt} [opt] - An optional parameter of type `Opt`.\n   * @returns The function `createMultiple` returns a Promise that resolves to an array of `DLMM`\n   * objects.\n   */\n  static async createMultiple(\n    connection: Connection,\n    dlmmList: Array<PublicKey>,\n    opt?: Opt,\n  ): Promise<DLMM[]> {\n    const program = createProgram(connection, opt);\n\n    const binArrayBitMapExtensions = dlmmList.map(\n      (lbPair) => deriveBinArrayBitmapExtension(lbPair, program.programId)[0],\n    );\n    const accountsToFetch = [\n      ...dlmmList,\n      ...binArrayBitMapExtensions,\n      SYSVAR_CLOCK_PUBKEY,\n    ];\n\n    let accountsInfo = await chunkedGetMultipleAccountInfos(\n      connection,\n      accountsToFetch,\n    );\n\n    const clockAccount = accountsInfo.pop();\n    const clockAccountInfoBuffer = clockAccount?.data;\n    if (!clockAccountInfoBuffer) throw new Error(`Clock account not found`);\n    const clock = ClockLayout.decode(clockAccountInfoBuffer) as Clock;\n\n    const lbPairArraysMap = new Map<string, LbPair>();\n    for (let i = 0; i < dlmmList.length; i++) {\n      const lbPairPubKey = dlmmList[i];\n      const lbPairAccountInfoBuffer = accountsInfo[i]?.data;\n      if (!lbPairAccountInfoBuffer)\n        throw new Error(`LB Pair account ${lbPairPubKey.toBase58()} not found`);\n      const lbPairAccInfo = decodeAccount<LbPair>(\n        program,\n        \"lbPair\",\n        lbPairAccountInfoBuffer,\n      );\n      lbPairArraysMap.set(lbPairPubKey.toBase58(), lbPairAccInfo);\n    }\n\n    const binArrayBitMapExtensionsMap = new Map<\n      string,\n      BinArrayBitmapExtension\n    >();\n    for (let i = dlmmList.length; i < accountsInfo.length; i++) {\n      const index = i - dlmmList.length;\n      const lbPairPubkey = dlmmList[index];\n      const binArrayBitMapAccountInfoBuffer = accountsInfo[i]?.data;\n      if (binArrayBitMapAccountInfoBuffer) {\n        const binArrayBitMapExtensionAccInfo =\n          decodeAccount<BinArrayBitmapExtension>(\n            program,\n            \"binArrayBitmapExtension\",\n            binArrayBitMapAccountInfoBuffer,\n          );\n        binArrayBitMapExtensionsMap.set(\n          lbPairPubkey.toBase58(),\n          binArrayBitMapExtensionAccInfo,\n        );\n      }\n    }\n\n    const reservePublicKeys = Array.from(lbPairArraysMap.values())\n      .map(({ reserveX, reserveY }) => [reserveX, reserveY])\n      .flat();\n\n    const tokenMintPublicKeys = Array.from(lbPairArraysMap.values())\n      .map(({ tokenXMint, tokenYMint }) => [tokenXMint, tokenYMint])\n      .flat();\n\n    const rewardVaultPublicKeys = Array.from(lbPairArraysMap.values())\n      .map(({ rewardInfos }) => rewardInfos.map(({ vault }) => vault))\n      .flat();\n\n    const rewardMintPublicKeys = Array.from(lbPairArraysMap.values())\n      .map(({ rewardInfos }) => rewardInfos.map(({ mint }) => mint))\n      .flat();\n\n    accountsInfo = await chunkedGetMultipleAccountInfos(\n      program.provider.connection,\n      [\n        ...reservePublicKeys,\n        ...tokenMintPublicKeys,\n        ...rewardVaultPublicKeys,\n        ...rewardMintPublicKeys,\n      ],\n    );\n\n    const offsetToTokenMint = reservePublicKeys.length;\n    const offsetToRewardMint =\n      reservePublicKeys.length +\n      tokenMintPublicKeys.length +\n      rewardVaultPublicKeys.length;\n\n    const tokenMintAccounts = accountsInfo.slice(\n      offsetToTokenMint,\n      offsetToTokenMint + tokenMintPublicKeys.length,\n    );\n\n    const rewardMintAccounts = accountsInfo.slice(\n      offsetToRewardMint,\n      offsetToRewardMint + rewardMintPublicKeys.length,\n    );\n\n    const tokenMintsWithAccount = tokenMintPublicKeys\n      .map((key, idx) => {\n        return {\n          mintAddress: key,\n          mintAccountInfo: tokenMintAccounts[idx],\n        };\n      })\n      .filter(({ mintAddress }) => mintAddress !== PublicKey.default);\n\n    const rewardMintsWithAccount = rewardMintPublicKeys\n      .map((key, idx) => {\n        return {\n          mintAddress: key,\n          mintAccountInfo: rewardMintAccounts[idx],\n        };\n      })\n      .filter(({ mintAddress }) => mintAddress !== PublicKey.default);\n\n    const uniqueMintWithAccounts = Array.from(\n      new Set(tokenMintsWithAccount.concat(rewardMintsWithAccount)),\n    );\n\n    const mintHookAccountsMap =\n      await getMultipleMintsExtraAccountMetasForTransferHook(\n        connection,\n        uniqueMintWithAccounts,\n      );\n\n    const lbClmmImpl = dlmmList.map((lbPair, index) => {\n      const lbPairState = lbPairArraysMap.get(lbPair.toBase58());\n      if (!lbPairState)\n        throw new Error(`LB Pair ${lbPair.toBase58()} state not found`);\n\n      const binArrayBitmapExtensionState = binArrayBitMapExtensionsMap.get(\n        lbPair.toBase58(),\n      );\n      const binArrayBitmapExtensionPubkey = binArrayBitMapExtensions[index];\n\n      let binArrayBitmapExtension: BinArrayBitmapExtensionAccount | null = null;\n      if (binArrayBitmapExtensionState) {\n        binArrayBitmapExtension = {\n          account: binArrayBitmapExtensionState,\n          publicKey: binArrayBitmapExtensionPubkey,\n        };\n      }\n\n      const reserveXAccountInfo = accountsInfo[index * 2];\n      const reserveYAccountInfo = accountsInfo[index * 2 + 1];\n\n      let offsetToTokenMint = reservePublicKeys.length;\n\n      const tokenXMintAccountInfo = accountsInfo[offsetToTokenMint + index * 2];\n      const tokenYMintAccountInfo =\n        accountsInfo[offsetToTokenMint + index * 2 + 1];\n\n      const offsetToRewardVaultAccountInfos =\n        offsetToTokenMint + tokenMintPublicKeys.length;\n\n      const reward0VaultAccountInfo =\n        accountsInfo[offsetToRewardVaultAccountInfos + index * 2];\n      const reward1VaultAccountInfo =\n        accountsInfo[offsetToRewardVaultAccountInfos + index * 2 + 1];\n\n      const offsetToRewardMintAccountInfos =\n        offsetToRewardVaultAccountInfos + rewardVaultPublicKeys.length;\n\n      const reward0MintAccountInfo =\n        accountsInfo[offsetToRewardMintAccountInfos + index * 2];\n      const reward1MintAccountInfo =\n        accountsInfo[offsetToRewardMintAccountInfos + index * 2 + 1];\n\n      if (!reserveXAccountInfo || !reserveYAccountInfo)\n        throw new Error(\n          `Reserve account for LB Pair ${lbPair.toBase58()} not found`,\n        );\n\n      const reserveXBalance = AccountLayout.decode(reserveXAccountInfo.data);\n      const reserveYBalance = AccountLayout.decode(reserveYAccountInfo.data);\n\n      const mintX = unpackMint(\n        lbPairState.tokenXMint,\n        tokenXMintAccountInfo,\n        tokenXMintAccountInfo.owner,\n      );\n\n      const mintY = unpackMint(\n        lbPairState.tokenYMint,\n        tokenYMintAccountInfo,\n        tokenYMintAccountInfo.owner,\n      );\n\n      const tokenX: TokenReserve = {\n        publicKey: lbPairState.tokenXMint,\n        reserve: lbPairState.reserveX,\n        mint: mintX,\n        amount: reserveXBalance.amount,\n        owner: tokenXMintAccountInfo.owner,\n        transferHookAccountMetas:\n          mintHookAccountsMap.get(lbPairState.tokenXMint.toBase58()) ?? [],\n      };\n\n      const tokenY: TokenReserve = {\n        publicKey: lbPairState.tokenYMint,\n        reserve: lbPairState.reserveY,\n        amount: reserveYBalance.amount,\n        mint: mintY,\n        owner: tokenYMintAccountInfo.owner,\n        transferHookAccountMetas:\n          mintHookAccountsMap.get(lbPairState.tokenYMint.toBase58()) ?? [],\n      };\n\n      const reward0: TokenReserve = !lbPairState.rewardInfos[0].mint.equals(\n        PublicKey.default,\n      )\n        ? {\n            publicKey: lbPairState.rewardInfos[0].mint,\n            reserve: lbPairState.rewardInfos[0].vault,\n            amount: AccountLayout.decode(reward0VaultAccountInfo.data).amount,\n            mint: unpackMint(\n              lbPairState.rewardInfos[0].mint,\n              reward0MintAccountInfo,\n              reward0MintAccountInfo.owner,\n            ),\n            owner: reward0MintAccountInfo.owner,\n            transferHookAccountMetas:\n              mintHookAccountsMap.get(\n                lbPairState.rewardInfos[0].mint.toBase58(),\n              ) ?? [],\n          }\n        : null;\n\n      const reward1: TokenReserve = !lbPairState.rewardInfos[1].mint.equals(\n        PublicKey.default,\n      )\n        ? {\n            publicKey: lbPairState.rewardInfos[1].mint,\n            reserve: lbPairState.rewardInfos[1].vault,\n            amount: AccountLayout.decode(reward1VaultAccountInfo.data).amount,\n            mint: unpackMint(\n              lbPairState.rewardInfos[1].mint,\n              reward1MintAccountInfo,\n              reward1MintAccountInfo.owner,\n            ),\n            owner: reward1MintAccountInfo.owner,\n            transferHookAccountMetas:\n              mintHookAccountsMap.get(\n                lbPairState.rewardInfos[1].mint.toBase58(),\n              ) ?? [],\n          }\n        : null;\n\n      return new DLMM(\n        lbPair,\n        program,\n        lbPairState,\n        binArrayBitmapExtension,\n        tokenX,\n        tokenY,\n        [reward0, reward1],\n        clock,\n        opt,\n      );\n    });\n\n    return lbClmmImpl;\n  }\n\n  /**\n   * The `getAllPresetParameters` function retrieves all preset parameter accounts\n   * for the given DLMM program.\n   *\n   * @param {Connection} connection - The connection to the Solana cluster.\n   * @param {Opt} [opt] - The optional parameters for the function.\n   *\n   * @returns A promise that resolves to an object containing the preset parameter\n   * accounts, with the following properties:\n   * - `presetParameter`: The preset parameter accounts for the original `PresetParameter` struct.\n   * - `presetParameter2`: The preset parameter accounts for the `PresetParameter2` struct.\n   */\n  static async getAllPresetParameters(connection: Connection, opt?: Opt) {\n    const program = createProgram(connection, opt);\n\n    const [presetParameter, presetParameter2] = await Promise.all([\n      program.account.presetParameter.all(),\n      program.account.presetParameter2.all(),\n    ]);\n\n    return {\n      presetParameter,\n      presetParameter2,\n    };\n  }\n\n  /**\n   * The function `getAllLbPairPositionsByUser` retrieves all liquidity pool pair positions for a given\n   * user.\n   * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`\n   * class, which represents the connection to the Solana blockchain.\n   * @param {PublicKey} userPubKey - The user's wallet public key.\n   * @param {Opt} [opt] - An optional object that contains additional options for the function.\n   * @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching\n   * @returns The function `getAllLbPairPositionsByUser` returns a `Promise` that resolves to a `Map`\n   * object. The `Map` object contains key-value pairs, where the key is a string representing the LB\n   * Pair account, and the value is an object of PositionInfo\n   */\n  static async getAllLbPairPositionsByUser(\n    connection: Connection,\n    userPubKey: PublicKey,\n    opt?: Opt,\n    getPositionsOpt?: GetPositionsOpt,\n  ): Promise<Map<string, PositionInfo>> {\n    const program = createProgram(connection, opt);\n\n    const positionsV2 = await chunkedGetProgramAccounts(\n      program.provider.connection,\n      program.programId,\n      [positionV2Filter(), positionOwnerFilter(userPubKey)],\n      getPositionsOpt?.chunkSize,\n      getPositionsOpt?.onChunkFetched,\n      getPositionsOpt?.isParallelExecution,\n    );\n\n    const positionWrappers: IPosition[] = [\n      ...positionsV2.map((p) => wrapPosition(program, p.pubkey, p.account)),\n    ];\n\n    const binArrayPubkeySetV2 = new Set<string>();\n    const lbPairSetV2 = new Set<string>();\n\n    positionWrappers.forEach((p) => {\n      const binArrayKeys = p.getBinArrayKeysCoverage(program.programId);\n      binArrayKeys.forEach((binArrayKey) => {\n        binArrayPubkeySetV2.add(binArrayKey.toBase58());\n      });\n      lbPairSetV2.add(p.lbPair().toBase58());\n    });\n\n    const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(\n      (pubkey) => new PublicKey(pubkey),\n    );\n    const lbPairKeys = Array.from(lbPairSetV2).map(\n      (pubkey) => new PublicKey(pubkey),\n    );\n\n    const [clockAccInfo, ...binArraysAccInfo] =\n      await chunkedGetMultipleAccountInfos(connection, [\n        SYSVAR_CLOCK_PUBKEY,\n        ...binArrayPubkeyArrayV2,\n        ...lbPairKeys,\n      ]);\n\n    const positionBinArraysMapV2 = new Map();\n\n    for (let i = 0; i < binArrayPubkeyArrayV2.length; i++) {\n      const binArrayPubkey = binArrayPubkeyArrayV2[i];\n      const binArrayAccInfoBufferV2 = binArraysAccInfo[i];\n      if (binArrayAccInfoBufferV2) {\n        const binArrayAccInfo = decodeAccount<BinArray>(\n          program,\n          \"binArray\",\n          binArrayAccInfoBufferV2.data,\n        );\n        positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);\n      }\n    }\n\n    const lbPairMap = new Map<string, LbPair>();\n    for (\n      let i = binArrayPubkeyArrayV2.length;\n      i < binArraysAccInfo.length;\n      i++\n    ) {\n      const lbPairPubkey = lbPairKeys[i - binArrayPubkeyArrayV2.length];\n      const lbPairAccInfoBufferV2 = binArraysAccInfo[i];\n      if (!lbPairAccInfoBufferV2)\n        throw new Error(`LB Pair account ${lbPairPubkey.toBase58()} not found`);\n      const lbPairAccInfo = decodeAccount<LbPair>(\n        program,\n        \"lbPair\",\n        lbPairAccInfoBufferV2.data,\n      );\n      lbPairMap.set(lbPairPubkey.toBase58(), lbPairAccInfo);\n    }\n\n    const accountKeys = Array.from(lbPairMap.values())\n      .map(({ reserveX, reserveY, tokenXMint, tokenYMint, rewardInfos }) => [\n        reserveX,\n        reserveY,\n        tokenXMint,\n        tokenYMint,\n        rewardInfos[0].mint,\n        rewardInfos[1].mint,\n      ])\n      .flat();\n\n    const accountInfos = await chunkedGetMultipleAccountInfos(\n      program.provider.connection,\n      accountKeys,\n    );\n\n    const lbPairReserveMap = new Map<\n      string,\n      { reserveX: bigint; reserveY: bigint }\n    >();\n\n    const lbPairMintMap = new Map<\n      string,\n      {\n        mintX: Mint;\n        mintY: Mint;\n        rewardMint0: Mint | null;\n        rewardMint1: Mint | null;\n      }\n    >();\n\n    lbPairKeys.forEach((lbPair, idx) => {\n      const index = idx * 6;\n      const reserveXAccount = accountInfos[index];\n      const reserveYAccount = accountInfos[index + 1];\n\n      if (!reserveXAccount || !reserveYAccount)\n        throw new Error(\n          `Reserve account for LB Pair ${lbPair.toBase58()} not found`,\n        );\n\n      const reserveAccX = AccountLayout.decode(reserveXAccount.data);\n      const reserveAccY = AccountLayout.decode(reserveYAccount.data);\n\n      lbPairReserveMap.set(lbPair.toBase58(), {\n        reserveX: reserveAccX.amount,\n        reserveY: reserveAccY.amount,\n      });\n\n      const mintXAccount = accountInfos[index + 2];\n      const mintYAccount = accountInfos[index + 3];\n      if (!mintXAccount || !mintYAccount)\n        throw new Error(\n          `Mint account for LB Pair ${lbPair.toBase58()} not found`,\n        );\n\n      const mintX = unpackMint(\n        reserveAccX.mint,\n        mintXAccount,\n        mintXAccount.owner,\n      );\n\n      const mintY = unpackMint(\n        reserveAccY.mint,\n        mintYAccount,\n        mintYAccount.owner,\n      );\n\n      const rewardMint0Account = accountInfos[index + 4];\n      const rewardMint1Account = accountInfos[index + 5];\n\n      const lbPairState = lbPairMap.get(lbPair.toBase58());\n\n      let rewardMint0: Mint | null = null;\n      let rewardMint1: Mint | null = null;\n\n      if (!lbPairState.rewardInfos[0].mint.equals(PublicKey.default)) {\n        rewardMint0 = unpackMint(\n          lbPairState.rewardInfos[0].mint,\n          rewardMint0Account,\n          rewardMint0Account.owner,\n        );\n      }\n\n      if (!lbPairState.rewardInfos[1].mint.equals(PublicKey.default)) {\n        rewardMint1 = unpackMint(\n          lbPairState.rewardInfos[1].mint,\n          rewardMint1Account,\n          rewardMint1Account.owner,\n        );\n      }\n\n      lbPairMintMap.set(lbPair.toBase58(), {\n        mintX,\n        mintY,\n        rewardMint0,\n        rewardMint1,\n      });\n    });\n\n    const clock: Clock = ClockLayout.decode(clockAccInfo.data);\n\n    const positionsMap: Map<\n      string,\n      {\n        publicKey: PublicKey;\n        lbPair: LbPair;\n        tokenX: TokenReserve;\n        tokenY: TokenReserve;\n        lbPairPositionsData: Array<{\n          publicKey: PublicKey;\n          positionData: PositionData;\n          version: PositionVersion;\n        }>;\n      }\n    > = new Map();\n\n    for (const position of positionWrappers) {\n      const lbPair = position.lbPair();\n      const positionPubkey = position.address();\n      const version = position.version();\n\n      const lbPairAcc = lbPairMap.get(lbPair.toBase58());\n      const { mintX, mintY, rewardMint0, rewardMint1 } = lbPairMintMap.get(\n        lbPair.toBase58(),\n      );\n\n      const reserveXBalance =\n        lbPairReserveMap.get(lbPair.toBase58())?.reserveX ?? BigInt(0);\n      const reserveYBalance =\n        lbPairReserveMap.get(lbPair.toBase58())?.reserveY ?? BigInt(0);\n\n      const { tokenXProgram, tokenYProgram } = getTokenProgramId(lbPairAcc);\n\n      const tokenX: TokenReserve = {\n        publicKey: lbPairAcc.tokenXMint,\n        reserve: lbPairAcc.reserveX,\n        amount: reserveXBalance,\n        mint: mintX,\n        owner: tokenXProgram,\n        transferHookAccountMetas: [], // No need, the TokenReserve created just for processing position info, doesn't require any transaction\n      };\n\n      const tokenY: TokenReserve = {\n        publicKey: lbPairAcc.tokenYMint,\n        reserve: lbPairAcc.reserveY,\n        amount: reserveYBalance,\n        mint: mintY,\n        owner: tokenYProgram,\n        transferHookAccountMetas: [], // No need, the TokenReserve created just for processing position info, doesn't require any transaction\n      };\n\n      const positionData = await DLMM.processPosition(\n        program,\n        lbPairAcc,\n        clock,\n        position,\n        mintX,\n        mintY,\n        rewardMint0,\n        rewardMint1,\n        positionBinArraysMapV2,\n      );\n\n      if (positionData) {\n        positionsMap.set(lbPair.toBase58(), {\n          publicKey: lbPair,\n          lbPair: lbPairAcc,\n          tokenX,\n          tokenY,\n          lbPairPositionsData: [\n            ...(positionsMap.get(lbPair.toBase58())?.lbPairPositionsData ?? []),\n            {\n              publicKey: positionPubkey,\n              positionData,\n              version,\n            },\n          ],\n        });\n      }\n    }\n\n    return positionsMap;\n  }\n\n  public static getPricePerLamport(\n    tokenXDecimal: number,\n    tokenYDecimal: number,\n    price: number,\n  ): string {\n    return new Decimal(price)\n      .mul(new Decimal(10 ** (tokenYDecimal - tokenXDecimal)))\n      .toString();\n  }\n\n  public static getBinIdFromPrice(\n    price: string | number | Decimal,\n    binStep: number,\n    min: boolean,\n  ): number {\n    const binStepNum = new Decimal(binStep).div(new Decimal(BASIS_POINT_MAX));\n    const binId = new Decimal(price)\n      .log()\n      .dividedBy(new Decimal(1).add(binStepNum).log());\n    return (min ? binId.floor() : binId.ceil()).toNumber();\n  }\n\n  /**\n   * The function `getLbPairLockInfo` retrieves all pair positions that has locked liquidity.\n   * @param {number} [lockDurationOpt] - An optional value indicating the minimum position lock duration that the function should return.\n   * Depending on the lbPair activationType, the param should be a number of seconds or a number of slots.\n   * @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching\n   * @returns The function `getLbPairLockInfo` returns a `Promise` that resolves to a `PairLockInfo`\n   * object. The `PairLockInfo` object contains an array of `PositionLockInfo` objects.\n   */\n  public async getLbPairLockInfo(\n    lockDurationOpt?: number,\n    getPositionsOpt?: GetPositionsOpt,\n  ): Promise<PairLockInfo> {\n    const lockDuration = lockDurationOpt | 0;\n\n    const positionAccounts = await chunkedGetProgramAccounts(\n      this.program.provider.connection,\n      this.program.programId,\n      [positionLbPairFilter(this.pubkey)],\n      getPositionsOpt?.chunkSize,\n      getPositionsOpt?.onChunkFetched,\n      getPositionsOpt?.isParallelExecution,\n    );\n\n    const lbPairPositions = positionAccounts.map((acc) => {\n      return wrapPosition(this.program, acc.pubkey, acc.account);\n    });\n\n    // filter positions has lock_release_point > currentTimestamp + lockDurationSecs\n    const clockAccInfo =\n      await this.program.provider.connection.getAccountInfo(\n        SYSVAR_CLOCK_PUBKEY,\n      );\n    const clock = ClockLayout.decode(clockAccInfo.data) as Clock;\n\n    const currentPoint =\n      this.lbPair.activationType == ActivationType.Slot\n        ? clock.slot\n        : clock.unixTimestamp;\n\n    const minLockReleasePoint = currentPoint.add(new BN(lockDuration));\n\n    const positionsWithLock = lbPairPositions.filter((p) =>\n      p.lockReleasePoint().gt(minLockReleasePoint),\n    );\n\n    if (positionsWithLock.length == 0) {\n      return {\n        positions: [],\n      };\n    }\n\n    const binArrayPubkeySetV2 = new Set<string>();\n    positionsWithLock.forEach((position) => {\n      const binArrayKeys = position.getBinArrayKeysCoverage(\n        this.program.programId,\n      );\n\n      binArrayKeys.forEach((key) => {\n        binArrayPubkeySetV2.add(key.toBase58());\n      });\n    });\n\n    const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(\n      (pubkey) => new PublicKey(pubkey),\n    );\n\n    const binArraysAccInfo = await chunkedGetMultipleAccountInfos(\n      this.program.provider.connection,\n      binArrayPubkeyArrayV2,\n    );\n\n    const positionBinArraysMapV2 = new Map();\n\n    for (let i = 0; i < binArraysAccInfo.length; i++) {\n      const binArrayPubkey = binArrayPubkeyArrayV2[i];\n      const binArrayAccBufferV2 = binArraysAccInfo[i];\n      if (!binArrayAccBufferV2)\n        throw new Error(\n          `Bin Array account ${binArrayPubkey.toBase58()} not found`,\n        );\n      const binArrayAccInfo = decodeAccount<BinArray>(\n        this.program,\n        \"binArray\",\n        binArrayAccBufferV2.data,\n      );\n      positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);\n    }\n\n    const positionsLockInfo = await Promise.all(\n      positionsWithLock.map(async (position) => {\n        const positionData = await DLMM.processPosition(\n          this.program,\n          this.lbPair,\n          clock,\n          position,\n          this.tokenX.mint,\n          this.tokenY.mint,\n          this.rewards[0].mint,\n          this.rewards[1].mint,\n          positionBinArraysMapV2,\n        );\n\n        return {\n          positionAddress: position.address(),\n          owner: position.owner(),\n          lockReleasePoint: position.lockReleasePoint().toNumber(),\n          tokenXAmount: positionData.totalXAmount,\n          tokenYAmount: positionData.totalYAmount,\n        };\n      }),\n    );\n\n    return {\n      positions: positionsLockInfo,\n    };\n  }\n\n  /** Public methods */\n\n  /**\n   * Create a new customizable permissionless pair. Support both token and token 2022.\n   * @param connection A connection to the Solana cluster.\n   * @param binStep The bin step for the pair.\n   * @param tokenX The mint of the first token.\n   * @param tokenY The mint of the second token.\n   * @param activeId The ID of the initial active bin. Represent the starting price.\n   * @param feeBps The fee rate for swaps in the pair, in basis points.\n   * @param activationType The type of activation for the pair.\n   * @param hasAlphaVault Whether the pair has an alpha vault.\n   * @param creatorKey The public key of the creator of the pair.\n   * @param activationPoint The timestamp at which the pair will be activated.\n   * @param opt An options object.\n   * @returns A transaction that creates the pair.\n   */\n  public static async createCustomizablePermissionlessLbPair2(\n    connection: Connection,\n    binStep: BN,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    activeId: BN,\n    feeBps: BN,\n    activationType: ActivationType,\n    hasAlphaVault: boolean,\n    creatorKey: PublicKey,\n    activationPoint?: BN,\n    creatorPoolOnOffControl?: boolean,\n    opt?: Opt,\n  ): Promise<Transaction> {\n    const program = createProgram(connection, opt);\n\n    const [tokenBadgeX] = deriveTokenBadge(tokenX, program.programId);\n    const [tokenBadgeY] = deriveTokenBadge(tokenY, program.programId);\n\n    const [\n      tokenXAccount,\n      tokenYAccount,\n      tokenBadgeXAccount,\n      tokenBadgeYAccount,\n    ] = await connection.getMultipleAccountsInfo([\n      tokenX,\n      tokenY,\n      tokenBadgeX,\n      tokenBadgeY,\n    ]);\n\n    const [lbPair] = deriveCustomizablePermissionlessLbPair(\n      tokenX,\n      tokenY,\n      program.programId,\n    );\n\n    const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);\n    const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);\n    const [oracle] = deriveOracle(lbPair, program.programId);\n\n    const activeBinArrayIndex = binIdToBinArrayIndex(activeId);\n    const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(\n      activeBinArrayIndex,\n    )\n      ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0]\n      : null;\n\n    const [baseFactor, baseFeePowerFactor] = computeBaseFactorFromFeeBps(\n      binStep,\n      feeBps,\n    );\n\n    const ixData: InitCustomizablePermissionlessPairIx = {\n      activeId: activeId.toNumber(),\n      binStep: binStep.toNumber(),\n      baseFactor: baseFactor.toNumber(),\n      functionType: FunctionType.LiquidityMining,\n      activationType,\n      activationPoint: activationPoint ? activationPoint : null,\n      hasAlphaVault,\n      creatorPoolOnOffControl: creatorPoolOnOffControl\n        ? creatorPoolOnOffControl\n        : false,\n      baseFeePowerFactor: baseFeePowerFactor.toNumber(),\n      padding: Array(63).fill(0),\n    };\n\n    const preInstructions: TransactionInstruction[] = [];\n\n    const userTokenX = getAssociatedTokenAddressSync(\n      tokenX,\n      creatorKey,\n      true,\n      tokenXAccount.owner,\n    );\n\n    const createUserTokenXIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        creatorKey,\n        userTokenX,\n        creatorKey,\n        tokenX,\n        tokenXAccount.owner,\n      );\n\n    preInstructions.push(createUserTokenXIx);\n\n    const userTokenY = getAssociatedTokenAddressSync(\n      tokenY,\n      creatorKey,\n      true,\n      tokenYAccount.owner,\n    );\n\n    const createUserTokenYIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        creatorKey,\n        userTokenY,\n        creatorKey,\n        tokenY,\n        tokenYAccount.owner,\n      );\n\n    preInstructions.push(createUserTokenYIx);\n\n    const postInstructions: TransactionInstruction[] = [];\n\n    // if either mint (tokenX or tokenY) is SOL, wrap a small amount to initialize the wrapped SOL account(s) then unwrap after the pool creation\n    if (\n      (tokenX.equals(NATIVE_MINT) || tokenY.equals(NATIVE_MINT)) &&\n      !opt?.skipSolWrappingOperation\n    ) {\n      const wrapAmount = BigInt(1); // 1 lamport\n\n      if (tokenX.equals(NATIVE_MINT)) {\n        const wrapSOLIxX = wrapSOLInstruction(\n          creatorKey,\n          userTokenX,\n          wrapAmount,\n        );\n        preInstructions.push(...wrapSOLIxX);\n      }\n      if (tokenY.equals(NATIVE_MINT)) {\n        const wrapSOLIxY = wrapSOLInstruction(\n          creatorKey,\n          userTokenY,\n          wrapAmount,\n        );\n        preInstructions.push(...wrapSOLIxY);\n      }\n\n      const unwrapSOLIx = await unwrapSOLInstruction(creatorKey);\n      if (unwrapSOLIx) {\n        postInstructions.push(unwrapSOLIx);\n      }\n    }\n\n    return program.methods\n      .initializeCustomizablePermissionlessLbPair2(ixData)\n      .accountsPartial({\n        tokenBadgeX: tokenBadgeXAccount ? tokenBadgeX : program.programId,\n        tokenBadgeY: tokenBadgeYAccount ? tokenBadgeY : program.programId,\n        lbPair,\n        reserveX,\n        reserveY,\n        binArrayBitmapExtension,\n        tokenMintX: tokenX,\n        tokenMintY: tokenY,\n        oracle,\n        systemProgram: SystemProgram.programId,\n        userTokenX,\n        userTokenY,\n        funder: creatorKey,\n        tokenProgramX: tokenXAccount.owner,\n        tokenProgramY: tokenYAccount.owner,\n      })\n      .preInstructions(preInstructions)\n      .postInstructions(postInstructions)\n      .transaction();\n  }\n\n  /**\n   * Create a new customizable permissionless pair. Support only token program.\n   * @param connection A connection to the Solana cluster.\n   * @param binStep The bin step for the pair.\n   * @param tokenX The mint of the first token.\n   * @param tokenY The mint of the second token.\n   * @param activeId The ID of the initial active bin. Represent the starting price.\n   * @param feeBps The fee rate for swaps in the pair, in basis points.\n   * @param activationType The type of activation for the pair.\n   * @param hasAlphaVault Whether the pair has an alpha vault.\n   * @param creatorKey The public key of the creator of the pair.\n   * @param activationPoint The timestamp at which the pair will be activated.\n   * @param opt An options object.\n   * @returns A transaction that creates the pair.\n   */\n  public static async createCustomizablePermissionlessLbPair(\n    connection: Connection,\n    binStep: BN,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    activeId: BN,\n    feeBps: BN,\n    activationType: ActivationType,\n    hasAlphaVault: boolean,\n    creatorKey: PublicKey,\n    activationPoint?: BN,\n    creatorPoolOnOffControl?: boolean,\n    opt?: Opt,\n  ): Promise<Transaction> {\n    const program = createProgram(connection, opt);\n\n    const [lbPair] = deriveCustomizablePermissionlessLbPair(\n      tokenX,\n      tokenY,\n      program.programId,\n    );\n\n    const [tokenXAccount, tokenYAccount] =\n      await connection.getMultipleAccountsInfo([tokenX, tokenY]);\n\n    const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);\n    const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);\n    const [oracle] = deriveOracle(lbPair, program.programId);\n\n    const activeBinArrayIndex = binIdToBinArrayIndex(activeId);\n    const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(\n      activeBinArrayIndex,\n    )\n      ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0]\n      : null;\n\n    const [baseFactor, baseFeePowerFactor] = computeBaseFactorFromFeeBps(\n      binStep,\n      feeBps,\n    );\n\n    if (!baseFeePowerFactor.isZero()) {\n      throw \"base factor for the give fee bps overflow u16\";\n    }\n\n    const ixData: InitCustomizablePermissionlessPairIx = {\n      activeId: activeId.toNumber(),\n      binStep: binStep.toNumber(),\n      baseFactor: baseFactor.toNumber(),\n      functionType: FunctionType.LiquidityMining,\n      activationType,\n      activationPoint: activationPoint ? activationPoint : null,\n      hasAlphaVault,\n      baseFeePowerFactor: 0,\n      creatorPoolOnOffControl: creatorPoolOnOffControl\n        ? creatorPoolOnOffControl\n        : false,\n      padding: Array(63).fill(0),\n    };\n\n    const preInstructions: TransactionInstruction[] = [];\n\n    const userTokenX = getAssociatedTokenAddressSync(\n      tokenX,\n      creatorKey,\n      true,\n      tokenXAccount.owner,\n    );\n\n    const createUserTokenXIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        creatorKey,\n        userTokenX,\n        creatorKey,\n        tokenX,\n        tokenXAccount.owner,\n      );\n\n    preInstructions.push(createUserTokenXIx);\n\n    const userTokenY = getAssociatedTokenAddressSync(\n      tokenY,\n      creatorKey,\n      true,\n      tokenYAccount.owner,\n    );\n\n    const createUserTokenYIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        creatorKey,\n        userTokenY,\n        creatorKey,\n        tokenY,\n        tokenYAccount.owner,\n      );\n\n    preInstructions.push(createUserTokenYIx);\n\n    const postInstructions: TransactionInstruction[] = [];\n\n    // if either mint (tokenX or tokenY) is SOL, wrap a small amount to initialize the wrapped SOL account(s) then unwrap after the pool creation\n    if (\n      (tokenX.equals(NATIVE_MINT) || tokenY.equals(NATIVE_MINT)) &&\n      !opt?.skipSolWrappingOperation\n    ) {\n      const wrapAmount = BigInt(1); // 1 lamport\n\n      if (tokenX.equals(NATIVE_MINT)) {\n        const wrapSOLIxX = wrapSOLInstruction(\n          creatorKey,\n          userTokenX,\n          wrapAmount,\n        );\n        preInstructions.push(...wrapSOLIxX);\n      }\n      if (tokenY.equals(NATIVE_MINT)) {\n        const wrapSOLIxY = wrapSOLInstruction(\n          creatorKey,\n          userTokenY,\n          wrapAmount,\n        );\n        preInstructions.push(...wrapSOLIxY);\n      }\n\n      const unwrapSOLIx = await unwrapSOLInstruction(creatorKey);\n      if (unwrapSOLIx) {\n        postInstructions.push(unwrapSOLIx);\n      }\n    }\n\n    return program.methods\n      .initializeCustomizablePermissionlessLbPair(ixData)\n      .accountsPartial({\n        lbPair,\n        reserveX,\n        reserveY,\n        binArrayBitmapExtension,\n        tokenMintX: tokenX,\n        tokenMintY: tokenY,\n        oracle,\n        systemProgram: SystemProgram.programId,\n        userTokenX,\n        userTokenY,\n        funder: creatorKey,\n      })\n      .preInstructions(preInstructions)\n      .postInstructions(postInstructions)\n      .transaction();\n  }\n\n  /**\n   * Create a new liquidity pair. Support only token program.\n   * @param connection A connection to the Solana cluster.\n   * @param funder The public key of the funder of the pair.\n   * @param tokenX The mint of the first token.\n   * @param tokenY The mint of the second token.\n   * @param binStep The bin step for the pair.\n   * @param baseFactor The base factor for the pair.\n   * @param presetParameter The public key of the preset parameter account.\n   * @param activeId The ID of the initial active bin. Represent the starting price.\n   * @param opt An options object.\n   * @returns A transaction that creates the pair.\n   * @throws If the pair already exists.\n   */\n  public static async createLbPair(\n    connection: Connection,\n    funder: PublicKey,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    binStep: BN,\n    baseFactor: BN,\n    presetParameter: PublicKey,\n    activeId: BN,\n    opt?: Opt,\n  ): Promise<Transaction> {\n    const program = createProgram(connection, opt);\n\n    const existsPool = await this.getPairPubkeyIfExists(\n      connection,\n      tokenX,\n      tokenY,\n      binStep,\n      baseFactor,\n      new BN(0),\n    );\n\n    if (existsPool) {\n      throw new Error(\"Pool already exists\");\n    }\n\n    const [lbPair] = deriveLbPair2(\n      tokenX,\n      tokenY,\n      binStep,\n      baseFactor,\n      program.programId,\n    );\n\n    const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);\n    const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);\n    const [oracle] = deriveOracle(lbPair, program.programId);\n\n    const activeBinArrayIndex = binIdToBinArrayIndex(activeId);\n    const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(\n      activeBinArrayIndex,\n    )\n      ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0]\n      : null;\n\n    return program.methods\n      .initializeLbPair(activeId.toNumber(), binStep.toNumber())\n      .accountsPartial({\n        funder,\n        lbPair,\n        rent: SYSVAR_RENT_PUBKEY,\n        reserveX,\n        reserveY,\n        binArrayBitmapExtension,\n        tokenMintX: tokenX,\n        tokenMintY: tokenY,\n        tokenProgram: TOKEN_PROGRAM_ID,\n        oracle,\n        presetParameter,\n        systemProgram: SystemProgram.programId,\n      })\n      .transaction();\n  }\n\n  /**\n   * Create a new liquidity pair. Support both token and token2022 program.\n   * @param connection A connection to the Solana cluster.\n   * @param funder The public key of the funder of the pair.\n   * @param tokenX The mint of the first token.\n   * @param tokenY The mint of the second token.\n   * @param presetParameter The public key of the preset parameter account.\n   * @param activeId The ID of the initial active bin. Represent the starting price.\n   * @param opt An options object.\n   * @returns A transaction that creates the pair.\n   * @throws If the pair already exists.\n   */\n  public static async createLbPair2(\n    connection: Connection,\n    funder: PublicKey,\n    tokenX: PublicKey,\n    tokenY: PublicKey,\n    presetParameter: PublicKey,\n    activeId: BN,\n    opt?: Opt,\n  ): Promise<Transaction> {\n    const program = createProgram(connection, opt);\n\n    const [tokenBadgeX] = deriveTokenBadge(tokenX, program.programId);\n    const [tokenBadgeY] = deriveTokenBadge(tokenY, program.programId);\n\n    const [\n      tokenXAccount,\n      tokenYAccount,\n      tokenBadgeXAccount,\n      tokenBadgeYAccount,\n    ] = await connection.getMultipleAccountsInfo([\n      tokenX,\n      tokenY,\n      tokenBadgeX,\n      tokenBadgeY,\n    ]);\n\n    const presetParameterState =\n      await program.account.presetParameter2.fetch(presetParameter);\n\n    const existsPool = await this.getPairPubkeyIfExists(\n      connection,\n      tokenX,\n      tokenY,\n      new BN(presetParameterState.binStep),\n      new BN(presetParameterState.baseFactor),\n      new BN(presetParameterState.baseFeePowerFactor),\n      {\n        cluster: opt?.cluster,\n        programId: opt?.programId,\n      },\n    );\n\n    if (existsPool) {\n      throw new Error(\"Pool already exists\");\n    }\n\n    const [lbPair] = deriveLbPairWithPresetParamWithIndexKey(\n      presetParameter,\n      tokenX,\n      tokenY,\n      program.programId,\n    );\n\n    const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);\n    const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);\n    const [oracle] = deriveOracle(lbPair, program.programId);\n\n    const activeBinArrayIndex = binIdToBinArrayIndex(activeId);\n    const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(\n      activeBinArrayIndex,\n    )\n      ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0]\n      : null;\n\n    return program.methods\n      .initializeLbPair2({\n        activeId: activeId.toNumber(),\n        padding: Array(96).fill(0),\n      })\n      .accountsPartial({\n        funder,\n        lbPair,\n        reserveX,\n        reserveY,\n        binArrayBitmapExtension,\n        tokenMintX: tokenX,\n        tokenMintY: tokenY,\n        tokenBadgeX: tokenBadgeXAccount ? tokenBadgeX : program.programId,\n        tokenBadgeY: tokenBadgeYAccount ? tokenBadgeY : program.programId,\n        tokenProgramX: tokenXAccount.owner,\n        tokenProgramY: tokenYAccount.owner,\n        oracle,\n        presetParameter,\n        systemProgram: SystemProgram.programId,\n      })\n      .transaction();\n  }\n\n  /**\n   * The function `refetchStates` retrieves and updates various states and data related to bin arrays\n   * and lb pairs.\n   */\n  public async refetchStates(): Promise<void> {\n    const binArrayBitmapExtensionPubkey = deriveBinArrayBitmapExtension(\n      this.pubkey,\n      this.program.programId,\n    )[0];\n\n    const [\n      lbPairAccountInfo,\n      binArrayBitmapExtensionAccountInfo,\n      reserveXAccountInfo,\n      reserveYAccountInfo,\n      mintXAccountInfo,\n      mintYAccountInfo,\n      reward0VaultAccountInfo,\n      reward1VaultAccountInfo,\n      rewardMint0AccountInfo,\n      rewardMint1AccountInfo,\n      clockAccountInfo,\n    ] = await chunkedGetMultipleAccountInfos(this.program.provider.connection, [\n      this.pubkey,\n      binArrayBitmapExtensionPubkey,\n      this.lbPair.reserveX,\n      this.lbPair.reserveY,\n      this.lbPair.tokenXMint,\n      this.lbPair.tokenYMint,\n      this.lbPair.rewardInfos[0].vault,\n      this.lbPair.rewardInfos[1].vault,\n      this.lbPair.rewardInfos[0].mint,\n      this.lbPair.rewardInfos[1].mint,\n      SYSVAR_CLOCK_PUBKEY,\n    ]);\n\n    const lbPairState = decodeAccount<LbPair>(\n      this.program,\n      \"lbPair\",\n      lbPairAccountInfo.data,\n    );\n    if (binArrayBitmapExtensionAccountInfo) {\n      const binArrayBitmapExtensionState =\n        decodeAccount<BinArrayBitmapExtension>(\n          this.program,\n          \"binArrayBitmapExtension\",\n          binArrayBitmapExtensionAccountInfo.data,\n        );\n\n      if (binArrayBitmapExtensionState) {\n        this.binArrayBitmapExtension = {\n          account: binArrayBitmapExtensionState,\n          publicKey: binArrayBitmapExtensionPubkey,\n        };\n      }\n    }\n\n    const reserveXBalance = AccountLayout.decode(reserveXAccountInfo.data);\n    const reserveYBalance = AccountLayout.decode(reserveYAccountInfo.data);\n\n    const [\n      tokenXTransferHook,\n      tokenYTransferHook,\n      reward0TransferHook,\n      reward1TransferHook,\n    ] = await Promise.all([\n      getExtraAccountMetasForTransferHook(\n        this.program.provider.connection,\n        lbPairState.tokenXMint,\n        mintXAccountInfo,\n      ),\n      getExtraAccountMetasForTransferHook(\n        this.program.provider.connection,\n        lbPairState.tokenYMint,\n        mintYAccountInfo,\n      ),\n      rewardMint0AccountInfo\n        ? getExtraAccountMetasForTransferHook(\n            this.program.provider.connection,\n            lbPairState.rewardInfos[0].mint,\n            rewardMint0AccountInfo,\n          )\n        : [],\n      rewardMint1AccountInfo\n        ? getExtraAccountMetasForTransferHook(\n            this.program.provider.connection,\n            lbPairState.rewardInfos[1].mint,\n            rewardMint1AccountInfo,\n          )\n        : [],\n    ]);\n\n    const mintX = unpackMint(\n      this.tokenX.publicKey,\n      mintXAccountInfo,\n      mintXAccountInfo.owner,\n    );\n\n    const mintY = unpackMint(\n      this.tokenY.publicKey,\n      mintYAccountInfo,\n      mintYAccountInfo.owner,\n    );\n\n    this.tokenX = {\n      amount: reserveXBalance.amount,\n      mint: mintX,\n      publicKey: lbPairState.tokenXMint,\n      reserve: lbPairState.reserveX,\n      owner: mintXAccountInfo.owner,\n      transferHookAccountMetas: tokenXTransferHook,\n    };\n\n    this.tokenY = {\n      amount: reserveYBalance.amount,\n      mint: mintY,\n      publicKey: lbPairState.tokenYMint,\n      reserve: lbPairState.reserveY,\n      owner: mintYAccountInfo.owner,\n      transferHookAccountMetas: tokenYTransferHook,\n    };\n\n    this.rewards[0] = null;\n    this.rewards[1] = null;\n\n    if (!lbPairState.rewardInfos[0].mint.equals(PublicKey.default)) {\n      this.rewards[0] = {\n        publicKey: lbPairState.rewardInfos[0].mint,\n        reserve: lbPairState.rewardInfos[0].vault,\n        mint: unpackMint(\n          lbPairState.rewardInfos[0].mint,\n          rewardMint0AccountInfo,\n          rewardMint0AccountInfo.owner,\n        ),\n        amount: AccountLayout.decode(reward0VaultAccountInfo.data).amount,\n        owner: rewardMint0AccountInfo.owner,\n        transferHookAccountMetas: reward0TransferHook,\n      };\n    }\n\n    if (!lbPairState.rewardInfos[1].mint.equals(PublicKey.default)) {\n      this.rewards[1] = {\n        publicKey: lbPairState.rewardInfos[1].mint,\n        reserve: lbPairState.rewardInfos[1].vault,\n        mint: unpackMint(\n          lbPairState.rewardInfos[1].mint,\n          rewardMint1AccountInfo,\n          rewardMint1AccountInfo.owner,\n        ),\n        amount: AccountLayout.decode(reward1VaultAccountInfo.data).amount,\n        owner: rewardMint1AccountInfo.owner,\n        transferHookAccountMetas: reward1TransferHook,\n      };\n    }\n\n    const clock = ClockLayout.decode(clockAccountInfo.data) as Clock;\n    this.clock = clock;\n\n    this.lbPair = lbPairState;\n  }\n\n  /**\n   * Set the status of a permissionless LB pair to either enabled or disabled. This require pool field `creator_pool_on_off_control` to be true and type `CustomizablePermissionless`.\n   * Pool creator can enable/disable the pair anytime before the pool is opened / activated. Once the pool activation time is passed, the pool creator can only enable the pair.\n   * Useful for token launches which do not have fixed activation time.\n   * @param enable If true, the pair will be enabled. If false, the pair will be disabled.\n   * @param creator The public key of the pool creator.\n   * @returns a Promise that resolves to the transaction.\n   */\n  public async setPairStatusPermissionless(\n    enable: boolean,\n    creator: PublicKey,\n  ) {\n    const status: PairStatus = enable ? 0 : 1; // 0 = enable, 1 = disable\n\n    const tx = await this.program.methods\n      .setPairStatusPermissionless(status)\n      .accountsPartial({\n        lbPair: this.pubkey,\n        signer: creator,\n      })\n      .transaction();\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return new Transaction({\n      feePayer: this.lbPair.creator,\n      blockhash,\n      lastValidBlockHeight,\n    }).add(tx);\n  }\n\n  /**\n   * The function `getBinArrays` returns an array of `BinArrayAccount` objects\n   * @returns a Promise that resolves to an array of BinArrayAccount objects.\n   */\n  public async getBinArrays(): Promise<BinArrayAccount[]> {\n    return this.program.account.binArray.all([\n      binArrayLbPairFilter(this.pubkey),\n    ]);\n  }\n\n  /**\n   * The function `getBinArrayAroundActiveBin` retrieves a specified number of `BinArrayAccount`\n   * objects from the blockchain, based on the active bin and its surrounding bin arrays.\n   * @param\n   *    swapForY - The `swapForY` parameter is a boolean value that indicates whether the swap is using quote token as input.\n   *    [count=4] - The `count` parameter is the number of bin arrays to retrieve on left and right respectively. By default, it is set to 4.\n   * @returns an array of `BinArrayAccount` objects.\n   */\n  public async getBinArrayForSwap(\n    swapForY: boolean,\n    count = 4,\n  ): Promise<BinArrayAccount[]> {\n    await this.refetchStates();\n\n    const binArraysPubkey = new Set<string>();\n\n    let shouldStop = false;\n    let activeIdToLoop = this.lbPair.activeId;\n\n    while (!shouldStop) {\n      const binArrayIndex = findNextBinArrayIndexWithLiquidity(\n        swapForY,\n        new BN(activeIdToLoop),\n        this.lbPair,\n        this.binArrayBitmapExtension?.account ?? null,\n      );\n      if (binArrayIndex === null) shouldStop = true;\n      else {\n        const [binArrayPubKey] = deriveBinArray(\n          this.pubkey,\n          binArrayIndex,\n          this.program.programId,\n        );\n        binArraysPubkey.add(binArrayPubKey.toBase58());\n\n        const [lowerBinId, upperBinId] =\n          getBinArrayLowerUpperBinId(binArrayIndex);\n        activeIdToLoop = swapForY\n          ? lowerBinId.toNumber() - 1\n          : upperBinId.toNumber() + 1;\n      }\n\n      if (binArraysPubkey.size === count) shouldStop = true;\n    }\n\n    const accountsToFetch = Array.from(binArraysPubkey).map(\n      (pubkey) => new PublicKey(pubkey),\n    );\n\n    const binArraysAccInfoBuffer = await chunkedGetMultipleAccountInfos(\n      this.program.provider.connection,\n      accountsToFetch,\n    );\n\n    const binArrays: BinArrayAccount[] = await Promise.all(\n      binArraysAccInfoBuffer.map(async (accInfo, idx) => {\n        const account = decodeAccount<BinArray>(\n          this.program,\n          \"binArray\",\n          accInfo.data,\n        );\n        const publicKey = accountsToFetch[idx];\n        return {\n          account,\n          publicKey,\n        };\n      }),\n    );\n\n    return binArrays;\n  }\n\n  /**\n   * The function `calculateFeeInfo` calculates the base fee rate percentage and maximum fee rate percentage\n   * given the base factor, bin step, and optional base fee power factor.\n   * @param baseFactor - The base factor of the pair.\n   * @param binStep - The bin step of the pair.\n   * @param baseFeePowerFactor - Optional parameter to allow small bin step to have bigger fee rate. Default to 0.\n   * @returns an object of type `Omit<FeeInfo, \"protocolFeePercentage\">` with the following properties: baseFeeRatePercentage and maxFeeRatePercentage.\n   */\n  public static calculateFeeInfo(\n    baseFactor: number | string,\n    binStep: number | string,\n    baseFeePowerFactor?: number | string,\n  ): Omit<FeeInfo, \"protocolFeePercentage\"> {\n    const baseFeeRate = new BN(baseFactor)\n      .mul(new BN(binStep))\n      .mul(new BN(10))\n      .mul(new BN(10).pow(new BN(baseFeePowerFactor ?? 0)));\n    const baseFeeRatePercentage = new Decimal(baseFeeRate.toString())\n      .mul(new Decimal(100))\n      .div(new Decimal(FEE_PRECISION.toString()));\n    const maxFeeRatePercentage = new Decimal(MAX_FEE_RATE.toString())\n      .mul(new Decimal(100))\n      .div(new Decimal(FEE_PRECISION.toString()));\n\n    return {\n      baseFeeRatePercentage,\n      maxFeeRatePercentage,\n    };\n  }\n\n  /**\n   * The function `getFeeInfo` calculates and returns the base fee rate percentage, maximum fee rate\n   * percentage, and protocol fee percentage.\n   * @returns an object of type `FeeInfo` with the following properties: baseFeeRatePercentage, maxFeeRatePercentage, and protocolFeePercentage.\n   */\n  public getFeeInfo(): FeeInfo {\n    const { baseFactor, protocolShare } = this.lbPair.parameters;\n\n    const { baseFeeRatePercentage, maxFeeRatePercentage } =\n      DLMM.calculateFeeInfo(\n        baseFactor,\n        this.lbPair.binStep,\n        this.lbPair.parameters.baseFeePowerFactor,\n      );\n\n    const protocolFeePercentage = new Decimal(protocolShare.toString())\n      .mul(new Decimal(100))\n      .div(new Decimal(BASIS_POINT_MAX));\n\n    return {\n      baseFeeRatePercentage,\n      maxFeeRatePercentage,\n      protocolFeePercentage,\n    };\n  }\n\n  /**\n   * The function calculates and returns a dynamic fee\n   * @returns a Decimal value representing the dynamic fee.\n   */\n  public getDynamicFee(): Decimal {\n    let vParameterClone = Object.assign({}, this.lbPair.vParameters);\n    let activeId = new BN(this.lbPair.activeId);\n    const sParameters = this.lbPair.parameters;\n\n    const currentTimestamp = Date.now() / 1000;\n    DLMM.updateReference(\n      activeId.toNumber(),\n      vParameterClone,\n      sParameters,\n      currentTimestamp,\n    );\n    DLMM.updateVolatilityAccumulator(\n      vParameterClone,\n      sParameters,\n      activeId.toNumber(),\n    );\n\n    const totalFee = getTotalFee(\n      this.lbPair.binStep,\n      sParameters,\n      vParameterClone,\n    );\n    return new Decimal(totalFee.toString())\n      .div(new Decimal(FEE_PRECISION.toString()))\n      .mul(100);\n  }\n\n  /**\n   * The function `getEmissionRate` returns the emission rates for two rewards.\n   * @returns an object of type `EmissionRate`. The object has two properties: `rewardOne` and\n   * `rewardTwo`, both of which are of type `Decimal`.\n   */\n  public getEmissionRate(): EmissionRate {\n    const now = Date.now() / 1000;\n    const [rewardOneEmissionRate, rewardTwoEmissionRate] =\n      this.lbPair.rewardInfos.map(({ rewardRate, rewardDurationEnd }) =>\n        now > rewardDurationEnd.toNumber() ? undefined : rewardRate,\n      );\n\n    return {\n      rewardOne: rewardOneEmissionRate\n        ? new Decimal(rewardOneEmissionRate.toString()).div(PRECISION)\n        : undefined,\n      rewardTwo: rewardTwoEmissionRate\n        ? new Decimal(rewardTwoEmissionRate.toString()).div(PRECISION)\n        : undefined,\n    };\n  }\n\n  /**\n   * The function `getBinsAroundActiveBin` retrieves a specified number of bins to the left and right\n   * of the active bin and returns them along with the active bin ID.\n   * @param {number} numberOfBinsToTheLeft - The parameter `numberOfBinsToTheLeft` represents the\n   * number of bins to the left of the active bin that you want to retrieve. It determines how many\n   * bins you want to include in the result that are positioned to the left of the active bin.\n   * @param {number} numberOfBinsToTheRight - The parameter `numberOfBinsToTheRight` represents the\n   * number of bins to the right of the active bin that you want to retrieve.\n   * @returns an object with two properties: \"activeBin\" and \"bins\". The value of \"activeBin\" is the\n   * value of \"this.lbPair.activeId\", and the value of \"bins\" is the result of calling the \"getBins\"\n   * function with the specified parameters.\n   */\n  public async getBinsAroundActiveBin(\n    numberOfBinsToTheLeft: number,\n    numberOfBinsToTheRight: number,\n  ): Promise<{ activeBin: number; bins: BinLiquidity[] }> {\n    const lowerBinId = this.lbPair.activeId - numberOfBinsToTheLeft - 1;\n    const upperBinId = this.lbPair.activeId + numberOfBinsToTheRight + 1;\n\n    const bins = await this.getBins(\n      this.pubkey,\n      lowerBinId,\n      upperBinId,\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n    );\n\n    return { activeBin: this.lbPair.activeId, bins };\n  }\n\n  /**\n   * The function `getBinsBetweenMinAndMaxPrice` retrieves a list of bins within a specified price\n   * range.\n   * @param {number} minPrice - The minimum price value for filtering the bins.\n   * @param {number} maxPrice - The `maxPrice` parameter is the maximum price value that you want to\n   * use for filtering the bins.\n   * @returns an object with two properties: \"activeBin\" and \"bins\". The value of \"activeBin\" is the\n   * active bin ID of the lbPair, and the value of \"bins\" is an array of BinLiquidity objects.\n   */\n  public async getBinsBetweenMinAndMaxPrice(\n    minPrice: number,\n    maxPrice: number,\n  ): Promise<{ activeBin: number; bins: BinLiquidity[] }> {\n    const lowerBinId = this.getBinIdFromPrice(minPrice, true) - 1;\n    const upperBinId = this.getBinIdFromPrice(maxPrice, false) + 1;\n\n    const bins = await this.getBins(\n      this.pubkey,\n      lowerBinId,\n      upperBinId,\n      this.tokenX.mint.decimals,\n      this.tokenX.mint.decimals,\n    );\n\n    return { activeBin: this.lbPair.activeId, bins };\n  }\n\n  /**\n   * The function `getBinsBetweenLowerAndUpperBound` retrieves a list of bins between a lower and upper\n   * bin ID and returns the active bin ID and the list of bins.\n   * @param {number} lowerBinId - The lowerBinId parameter is a number that represents the ID of the\n   * lowest bin.\n   * @param {number} upperBinId - The upperBinID parameter is a number that represents the ID of the\n   * highest bin.\n   * @param {BinArray} [lowerBinArrays] - The `lowerBinArrays` parameter is an optional parameter of\n   * type `BinArray`. It represents an array of bins that are below the lower bin ID.\n   * @param {BinArray} [upperBinArrays] - The parameter `upperBinArrays` is an optional parameter of\n   * type `BinArray`. It represents an array of bins that are above the upper bin ID.\n   * @returns an object with two properties: \"activeBin\" and \"bins\". The value of \"activeBin\" is the\n   * active bin ID of the lbPair, and the value of \"bins\" is an array of BinLiquidity objects.\n   */\n  public async getBinsBetweenLowerAndUpperBound(\n    lowerBinId: number,\n    upperBinId: number,\n    lowerBinArray?: BinArray,\n    upperBinArray?: BinArray,\n  ): Promise<{ activeBin: number; bins: BinLiquidity[] }> {\n    const bins = await this.getBins(\n      this.pubkey,\n      lowerBinId,\n      upperBinId,\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n      lowerBinArray,\n      upperBinArray,\n    );\n\n    return { activeBin: this.lbPair.activeId, bins };\n  }\n\n  /**\n   * The function converts a real price of bin to a lamport value\n   * @param {number} price - The `price` parameter is a number representing the price of a token.\n   * @returns {string} price per Lamport of bin\n   */\n  public toPricePerLamport(price: number): string {\n    return DLMM.getPricePerLamport(\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n      price,\n    );\n  }\n\n  /**\n   * The function converts a price per lamport value to a real price of bin\n   * @param {number} pricePerLamport - The parameter `pricePerLamport` is a number representing the\n   * price per lamport.\n   * @returns {string} real price of bin\n   */\n  public fromPricePerLamport(pricePerLamport: number): string {\n    return new Decimal(pricePerLamport)\n      .div(\n        new Decimal(\n          10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals),\n        ),\n      )\n      .toString();\n  }\n\n  /**\n   * The function retrieves the active bin ID and its corresponding price.\n   * @returns an object with two properties: \"binId\" which is a number, and \"price\" which is a string.\n   */\n  public async getActiveBin(): Promise<BinLiquidity> {\n    const { activeId } = await this.program.account.lbPair.fetch(this.pubkey);\n    const [activeBinState] = await this.getBins(\n      this.pubkey,\n      activeId,\n      activeId,\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n    );\n    return activeBinState;\n  }\n\n  /**\n   * The function get bin ID based on a given price and a boolean flag indicating whether to\n   * round down or up.\n   * @param {number} price - The price parameter is a number that represents the price value.\n   * @param {boolean} min - The \"min\" parameter is a boolean value that determines whether to round\n   * down or round up the calculated binId. If \"min\" is true, the binId will be rounded down (floor),\n   * otherwise it will be rounded up (ceil).\n   * @returns {number} which is the binId calculated based on the given price and whether the minimum\n   * value should be used.\n   */\n  public getBinIdFromPrice(price: number, min: boolean): number {\n    return DLMM.getBinIdFromPrice(price, this.lbPair.binStep, min);\n  }\n\n  /**\n   * The function `getPositionsByUserAndLbPair` retrieves positions by user and LB pair, including\n   * active bin and user positions.\n   * @param {PublicKey} [userPubKey] - The `userPubKey` parameter is an optional parameter of type\n   * `PublicKey`. It represents the public key of a user. If no `userPubKey` is provided, the function\n   * will return an object with an empty `userPositions` array and the active bin information obtained\n   * from the `getActive\n   * @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching\n   * @returns The function `getPositionsByUserAndLbPair` returns a Promise that resolves to an object\n   * with two properties:\n   *    - \"activeBin\" which is an object with two properties: \"binId\" and \"price\". The value of \"binId\"\n   *     is the active bin ID of the lbPair, and the value of \"price\" is the price of the active bin.\n   *   - \"userPositions\" which is an array of Position objects.\n   */\n  public async getPositionsByUserAndLbPair(\n    userPubKey?: PublicKey,\n    getPositionsOpt?: GetPositionsOpt,\n  ): Promise<{\n    activeBin: BinLiquidity;\n    userPositions: Array<LbPosition>;\n  }> {\n    const promiseResults = await Promise.all([\n      this.getActiveBin(),\n      userPubKey &&\n        chunkedGetProgramAccounts(\n          this.program.provider.connection,\n          this.program.programId,\n          [\n            positionV2Filter(),\n            positionOwnerFilter(userPubKey),\n            positionLbPairFilter(this.pubkey),\n          ],\n          getPositionsOpt?.chunkSize,\n          getPositionsOpt?.onChunkFetched,\n          getPositionsOpt?.isParallelExecution,\n        ),\n    ]);\n\n    const [activeBin, positionsV2] = promiseResults;\n\n    if (!activeBin) {\n      throw new Error(\"Error fetching active bin\");\n    }\n\n    if (!userPubKey) {\n      return {\n        activeBin,\n        userPositions: [],\n      };\n    }\n\n    const positions = [\n      ...positionsV2.map((p) =>\n        wrapPosition(this.program, p.pubkey, p.account),\n      ),\n    ];\n\n    if (!positions) {\n      throw new Error(\"Error fetching positions\");\n    }\n\n    const binArrayPubkeySetV2 = new Set<string>();\n    positions.forEach((position) => {\n      const binArrayKeys = position.getBinArrayKeysCoverage(\n        this.program.programId,\n      );\n\n      binArrayKeys.forEach((key) => {\n        binArrayPubkeySetV2.add(key.toBase58());\n      });\n    });\n\n    const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(\n      (pubkey) => new PublicKey(pubkey),\n    );\n\n    const lbPairAndBinArrays = await chunkedGetMultipleAccountInfos(\n      this.program.provider.connection,\n      [this.pubkey, SYSVAR_CLOCK_PUBKEY, ...binArrayPubkeyArrayV2],\n    );\n\n    const [lbPairAccInfo, clockAccInfo, ...binArraysAccInfo] =\n      lbPairAndBinArrays;\n\n    const positionBinArraysMapV2 = new Map();\n    for (let i = 0; i < binArraysAccInfo.length; i++) {\n      const binArrayPubkey = binArrayPubkeyArrayV2[i];\n      const binArrayAccBufferV2 = binArraysAccInfo[i];\n      if (binArrayAccBufferV2) {\n        const binArrayAccInfo = decodeAccount<BinArray>(\n          this.program,\n          \"binArray\",\n          binArrayAccBufferV2.data,\n        );\n        positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);\n      }\n    }\n\n    if (!lbPairAccInfo)\n      throw new Error(`LB Pair account ${this.pubkey.toBase58()} not found`);\n\n    const clock: Clock = ClockLayout.decode(clockAccInfo.data);\n\n    const userPositions = await Promise.all(\n      positions.map(async (position) => {\n        return {\n          publicKey: position.address(),\n          positionData: await DLMM.processPosition(\n            this.program,\n            this.lbPair,\n            clock,\n            position,\n            this.tokenX.mint,\n            this.tokenY.mint,\n            this.rewards[0]?.mint,\n            this.rewards[1]?.mint,\n            positionBinArraysMapV2,\n          ),\n          version: position.version(),\n        };\n      }),\n    );\n\n    return {\n      activeBin,\n      userPositions,\n    };\n  }\n\n  /**\n   * Estimates the cost to extend a position by a specified number of bins. Max position length is 1400\n   *\n   * The function calculates the rent cost required to expand a position and the cost\n   * to create necessary bin arrays for the new position range.\n   *\n   * @param currentMinBinId - The current minimum bin ID of the position.\n   * @param currentMaxBinId - The current maximum bin ID of the position.\n   * @param binCountToExpand - The number of bins to expand the position by.\n   * @returns An object containing:\n   *   - positionExtendCost: The estimated rent cost in lamports for extending the position.\n   *   - binArrayCost: The estimated cost for creating necessary bin arrays.\n   */\n\n  public async quoteExtendPosition(\n    currentMinBinId: BN,\n    currentMaxBinId: BN,\n    binCountToExpand: BN,\n  ) {\n    const positionExtendCost = await getPositionExpandRentExemption(\n      currentMinBinId,\n      currentMaxBinId,\n      this.program.provider.connection,\n      binCountToExpand,\n    );\n\n    const lowerBinArrayIndex = binIdToBinArrayIndex(currentMinBinId);\n    const upperBinArrayIndex = binIdToBinArrayIndex(currentMaxBinId);\n\n    const binArraysCount = (\n      await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)\n    ).length;\n\n    const binArrayCost = new Decimal(binArraysCount).mul(\n      new Decimal(BIN_ARRAY_FEE),\n    );\n\n    return {\n      positionExtendCost: new Decimal(positionExtendCost).div(\n        new Decimal(LAMPORTS_PER_SOL),\n      ),\n      binArrayCost,\n    };\n  }\n\n  public async quoteCreatePosition({ strategy }: TQuoteCreatePositionParams) {\n    const { minBinId, maxBinId } = strategy;\n\n    const binCount = maxBinId - minBinId + 1;\n    let positionCount = Math.floor(binCount / MAX_BINS_PER_POSITION.toNumber());\n    if (binCount % MAX_BINS_PER_POSITION.toNumber() > 0) {\n      positionCount++;\n    }\n\n    let positionReallocCost = 0;\n\n    let lastUpperBinId = minBinId;\n    for (let i = 0; i < positionCount; i++) {\n      const lowerBinId = lastUpperBinId;\n      const upperBinId = Math.min(\n        maxBinId,\n        lowerBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1,\n      );\n\n      const maxUpperBinId = Math.min(\n        maxBinId,\n        upperBinId + MAX_BINS_PER_POSITION.toNumber() - 1,\n      );\n\n      const binToExpand = maxUpperBinId - upperBinId;\n      const { positionExtendCost } = await this.quoteExtendPosition(\n        new BN(lowerBinId),\n        new BN(upperBinId),\n        new BN(binToExpand),\n      );\n\n      positionReallocCost += positionExtendCost.toNumber();\n      lastUpperBinId = upperBinId;\n    }\n\n    const lowerBinArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const upperBinArrayIndex = BN.max(\n      binIdToBinArrayIndex(new BN(maxBinId)),\n      lowerBinArrayIndex.add(new BN(1)),\n    );\n\n    let bitmapExtensionCost = 0;\n    if (\n      isOverflowDefaultBinArrayBitmap(lowerBinArrayIndex) ||\n      isOverflowDefaultBinArrayBitmap(upperBinArrayIndex)\n    ) {\n      bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;\n    }\n\n    const binArraysCount = (\n      await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)\n    ).length;\n\n    const transactionCount = Math.ceil(\n      (maxBinId - minBinId + 1) / DEFAULT_BIN_PER_POSITION.toNumber(),\n    );\n\n    const binArrayCost = binArraysCount * BIN_ARRAY_FEE;\n\n    return {\n      positionCount,\n      positionCost: positionCount * POSITION_FEE,\n      positionReallocCost,\n      bitmapExtensionCost,\n      binArraysCount,\n      binArrayCost,\n      transactionCount,\n    };\n  }\n\n  /**\n   * Creates an empty position and initializes the corresponding bin arrays if needed.\n   * @param param0 The settings of the requested new position.\n   * @returns A promise that resolves into a transaction for creating the requested position.\n   */\n  public async createEmptyPosition({\n    positionPubKey,\n    minBinId,\n    maxBinId,\n    user,\n  }: {\n    positionPubKey: PublicKey;\n    minBinId: number;\n    maxBinId: number;\n    user: PublicKey;\n  }) {\n    const createPositionIx = await this.program.methods\n      .initializePosition(minBinId, maxBinId - minBinId + 1)\n      .accountsPartial({\n        payer: user,\n        position: positionPubKey,\n        lbPair: this.pubkey,\n        owner: user,\n        rent: SYSVAR_RENT_PUBKEY,\n      })\n      .instruction();\n\n    const binArrayIndexes = getBinArrayIndexesCoverage(\n      new BN(minBinId),\n      new BN(maxBinId),\n    );\n\n    const createBinArrayIxs = await this.createBinArraysIfNeeded(\n      binArrayIndexes,\n      user,\n    );\n\n    const instructions = [createPositionIx, ...createBinArrayIxs];\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      instructions,\n      user,\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(setCUIx, ...instructions);\n  }\n\n  /**\n   * The function `getPosition` retrieves position information for a given public key and processes it\n   * using various data to return a `LbPosition` object.\n   * @param {PublicKey} positionPubKey - The `getPosition` function you provided is an asynchronous\n   * function that fetches position information based on a given public key. Here's a breakdown of the\n   * parameters used in the function:\n   * @returns The `getPosition` function returns a Promise that resolves to an object of type\n   * `LbPosition`. The object contains the following properties:\n   * - `publicKey`: The public key of the position account\n   * - `positionData`: Position Object\n   * - `version`: The version of the position (in this case, `Position.V2`)\n   */\n  public async getPosition(positionPubKey: PublicKey): Promise<LbPosition> {\n    const positionAccountInfo =\n      await this.program.provider.connection.getAccountInfo(positionPubKey);\n\n    if (!positionAccountInfo) {\n      throw new Error(\n        `Position account ${positionPubKey.toBase58()} not found`,\n      );\n    }\n\n    let position: IPosition = wrapPosition(\n      this.program,\n      positionPubKey,\n      positionAccountInfo,\n    );\n\n    const binArrayKeys = position.getBinArrayKeysCoverage(\n      this.program.programId,\n    );\n\n    const [clockAccInfo, ...binArrayAccountsInfo] =\n      await chunkedGetMultipleAccountInfos(this.program.provider.connection, [\n        SYSVAR_CLOCK_PUBKEY,\n        ...binArrayKeys,\n      ]);\n\n    const clock: Clock = ClockLayout.decode(clockAccInfo.data);\n\n    const binArrayMap = new Map<String, BinArray>();\n\n    for (let i = 0; i < binArrayAccountsInfo.length; i++) {\n      if (binArrayAccountsInfo[i]) {\n        const binArrayState = decodeAccount<BinArray>(\n          this.program,\n          \"binArray\",\n          binArrayAccountsInfo[i].data,\n        );\n\n        binArrayMap.set(binArrayKeys[i].toBase58(), binArrayState);\n      }\n    }\n\n    return {\n      publicKey: positionPubKey,\n      positionData: await DLMM.processPosition(\n        this.program,\n        this.lbPair,\n        clock,\n        position,\n        this.tokenX.mint,\n        this.tokenY.mint,\n        this.rewards[0]?.mint,\n        this.rewards[1]?.mint,\n        binArrayMap,\n      ),\n      version: position.version(),\n    };\n  }\n\n  /**\n   * Creates multiple positions and adds liquidity by strategy. It allow parallel execution of transactions.\n   * @param positionKeypairGenerator A function that generates a specified number of keypairs.\n   * @param totalXAmount The total amount of token X to be added.\n   * @param totalYAmount The total amount of token Y to be added.\n   * @param strategy The strategy for adding liquidity.\n   * @param owner The owner of the position.\n   * @param payer The payer of the transaction.\n   * @param slippagePercentage The slippage percentage for adding liquidity.\n   * @returns An object with two properties: `initPositionIxs` and `addLiquidityIxs`.\n   */\n  public async initializeMultiplePositionAndAddLiquidityByStrategy2(\n    positionKeypairGenerator: (count: number) => Promise<Keypair[]>,\n    totalXAmount: BN,\n    totalYAmount: BN,\n    strategy: StrategyParameters,\n    owner: PublicKey,\n    payer: PublicKey,\n    slippagePercentage: number,\n    altAddress?: PublicKey,\n  ): Promise<InitializeMultiplePositionAndAddLiquidityByStrategyResponse2> {\n    const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(\n      slippagePercentage,\n      this.lbPair.binStep,\n      MAX_ACTIVE_BIN_SLIPPAGE,\n    );\n\n    const { minBinId, maxBinId } = strategy;\n\n    const binCount = getBinCount(minBinId, maxBinId);\n\n    const defaultAltAddressString =\n      altAddress ?? ALT_ADDRESS[this.opt?.cluster];\n\n    if (defaultAltAddressString) {\n      altAddress = new PublicKey(defaultAltAddressString);\n    }\n\n    const maxResizeIxAllowed = altAddress ? 5 : 3; // 525:343 bins will not exceed transaction limit. This is based on worst case where tokens are SOL + token 2022 with hook (1 account)\n\n    const maxBinPerParallelizedPosition =\n      DEFAULT_BIN_PER_POSITION.toNumber() +\n      MAX_RESIZE_LENGTH.toNumber() * maxResizeIxAllowed;\n\n    const positionCount = Math.ceil(binCount / maxBinPerParallelizedPosition);\n\n    const positionKeypairs = await positionKeypairGenerator(positionCount);\n\n    const liquidityStrategyParameters = buildLiquidityStrategyParameters(\n      totalXAmount,\n      totalYAmount,\n      new BN(minBinId - this.lbPair.activeId),\n      new BN(maxBinId - this.lbPair.activeId),\n      new BN(this.lbPair.binStep),\n      strategy.singleSidedX,\n      new BN(this.lbPair.activeId),\n      getLiquidityStrategyParameterBuilder(strategy.strategyType),\n    );\n\n    let startBinId = minBinId;\n\n    const response: InitializeMultiplePositionAndAddLiquidityByStrategyResponse2 =\n      { instructionsByPositions: [], lookupTableAddress: altAddress };\n\n    for (const position of positionKeypairs) {\n      const txsIxs: TransactionInstruction[][] = [];\n\n      const endBinId = Math.min(\n        startBinId + maxBinPerParallelizedPosition - 1,\n        maxBinId,\n      );\n\n      const finalPositionWidth = endBinId - startBinId + 1;\n\n      const initialPositionWidth =\n        finalPositionWidth > DEFAULT_BIN_PER_POSITION.toNumber()\n          ? DEFAULT_BIN_PER_POSITION.toNumber()\n          : finalPositionWidth;\n\n      const initPositionIx = await this.program.methods\n        .initializePosition2(startBinId, initialPositionWidth)\n        .accountsPartial({\n          position: position.publicKey,\n          lbPair: this.pubkey,\n          owner,\n          payer,\n        })\n        .instruction();\n\n      const extendPositionIxs: TransactionInstruction[] = [];\n\n      let currentEndBinId = startBinId + initialPositionWidth - 1;\n      while (true) {\n        if (currentEndBinId == endBinId) break;\n\n        currentEndBinId = Math.min(\n          currentEndBinId + MAX_RESIZE_LENGTH.toNumber(),\n          endBinId,\n        );\n\n        const increaseLengthIx = await this.program.methods\n          .increasePositionLength2(currentEndBinId)\n          .accountsPartial({\n            lbPair: this.pubkey,\n            position: position.publicKey,\n            funder: payer,\n            owner,\n          })\n          .instruction();\n\n        extendPositionIxs.push(increaseLengthIx);\n      }\n\n      const addLiquidityIxs = await chunkDepositWithRebalanceEndpoint(\n        this,\n        strategy,\n        slippagePercentage,\n        maxActiveBinSlippage,\n        position.publicKey,\n        startBinId,\n        endBinId,\n        liquidityStrategyParameters,\n        owner,\n        payer,\n        true,\n        this.opt?.skipSolWrappingOperation,\n      );\n\n      for (const instructions of addLiquidityIxs) {\n        const txIxs: TransactionInstruction[] = [];\n        txIxs.push(initPositionIx);\n        txIxs.push(...extendPositionIxs);\n        txIxs.push(...instructions);\n\n        const setCuIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          txIxs,\n          payer,\n          0.1,\n          altAddress,\n        );\n\n        txIxs.unshift(setCuIx);\n        txsIxs.push(txIxs);\n      }\n\n      response.instructionsByPositions.push({\n        positionKeypair: position,\n        transactionInstructions: txsIxs,\n      });\n\n      startBinId = endBinId + 1;\n    }\n\n    return response;\n  }\n\n  /**\n   * Creates multiple positions and adds liquidity by strategy without chainsaw issues.\n   * @param positionKeypairGenerator A function that generates a specified number of keypairs.\n   * @param totalXAmount The total amount of token X to be added.\n   * @param totalYAmount The total amount of token Y to be added.\n   * @param strategy The strategy for adding liquidity.\n   * @param owner The owner of the position.\n   * @param payer The payer of the transaction.\n   * @param slippagePercentage The slippage percentage for adding liquidity.\n   * @returns An object with two properties: `initPositionIxs` and `addLiquidityIxs`.\n   */\n  public async initializeMultiplePositionAndAddLiquidityByStrategy(\n    positionKeypairGenerator: (count: number) => Promise<Keypair[]>,\n    totalXAmount: BN,\n    totalYAmount: BN,\n    strategy: StrategyParameters,\n    owner: PublicKey,\n    payer: PublicKey,\n    slippagePercentage: number,\n  ): Promise<InitializeMultiplePositionAndAddLiquidityByStrategyResponse> {\n    const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(\n      slippagePercentage,\n      this.lbPair.binStep,\n      MAX_ACTIVE_BIN_SLIPPAGE,\n    );\n\n    const { minBinId, maxBinId } = strategy;\n    const binCount = getBinCount(minBinId, maxBinId);\n    const positionCount = getPositionCountByBinCount(binCount);\n\n    const positionKeypairs = await positionKeypairGenerator(positionCount);\n\n    const liquidityStrategyParameters = buildLiquidityStrategyParameters(\n      totalXAmount,\n      totalYAmount,\n      new BN(minBinId - this.lbPair.activeId),\n      new BN(maxBinId - this.lbPair.activeId),\n      new BN(this.lbPair.binStep),\n      strategy.singleSidedX,\n      new BN(this.lbPair.activeId),\n      getLiquidityStrategyParameterBuilder(strategy.strategyType),\n    );\n\n    const instructionsByPositions = [];\n    let startBinId = minBinId;\n\n    const initializeAtaIxs: TransactionInstruction[] = [];\n\n    if (!this.tokenX.publicKey.equals(NATIVE_MINT)) {\n      const ownerAtaX = getAssociatedTokenAddressSync(\n        this.tokenX.publicKey,\n        owner,\n        true,\n        this.tokenX.owner,\n      );\n      initializeAtaIxs.push(\n        createAssociatedTokenAccountIdempotentInstruction(\n          owner,\n          ownerAtaX,\n          owner,\n          this.tokenX.publicKey,\n          this.tokenX.owner,\n        ),\n      );\n    }\n\n    if (!this.tokenY.publicKey.equals(NATIVE_MINT)) {\n      const ownerAtaY = getAssociatedTokenAddressSync(\n        this.tokenY.publicKey,\n        owner,\n        true,\n        this.tokenY.owner,\n      );\n      initializeAtaIxs.push(\n        createAssociatedTokenAccountIdempotentInstruction(\n          owner,\n          ownerAtaY,\n          owner,\n          this.tokenY.publicKey,\n          this.tokenY.owner,\n        ),\n      );\n    }\n\n    for (const position of positionKeypairs) {\n      const endBinId = Math.min(\n        startBinId + MAX_BINS_PER_POSITION.toNumber() - 1,\n        maxBinId,\n      );\n\n      const binCount = getBinCount(startBinId, endBinId);\n      const positionWidth = Math.min(\n        binCount,\n        DEFAULT_BIN_PER_POSITION.toNumber(),\n      );\n\n      const initPositionIx = await this.program.methods\n        .initializePosition(startBinId, positionWidth)\n        .accountsPartial({\n          position: position.publicKey,\n          lbPair: this.pubkey,\n          owner,\n          payer,\n          rent: SYSVAR_RENT_PUBKEY,\n        })\n        .instruction();\n\n      const chunkedAddLiquidityIx = await chunkDepositWithRebalanceEndpoint(\n        this,\n        strategy,\n        slippagePercentage,\n        maxActiveBinSlippage,\n        position.publicKey,\n        startBinId,\n        endBinId,\n        liquidityStrategyParameters,\n        owner,\n        payer,\n        false,\n        this.opt?.skipSolWrappingOperation,\n      );\n\n      instructionsByPositions.push({\n        positionKeypair: position,\n        initializePositionIx: initPositionIx,\n        initializeAtaIxs,\n        addLiquidityIxs: chunkedAddLiquidityIx,\n      });\n\n      startBinId = endBinId + 1;\n    }\n\n    return {\n      instructionsByPositions,\n    };\n  }\n\n  /**\n   * Adds liquidity to an existing position using a specified strategy, allowing for chunkable transactions.\n   * If adding liquidity to bin out of position range, it will automatically expand. The limitation is 70 bins.\n   *\n   * @param {TInitializePositionAndAddLiquidityParamsByStrategy} params - The parameters required for adding liquidity.\n   * @param {PublicKey} params.positionPubKey - The public key of the position to which liquidity is being added.\n   * @param {BN} params.totalXAmount - The total amount of token X to be added as liquidity.\n   * @param {BN} params.totalYAmount - The total amount of token Y to be added as liquidity.\n   * @param {StrategyParameters} params.strategy - The strategy parameters for adding liquidity.\n   * @param {PublicKey} params.user - The public key of the user adding liquidity.\n   * @param {number} params.slippage - The slippage percentage allowed for the transaction.\n   *\n   * @returns {Promise<Transaction[]>} A promise that resolves to an array of transactions for adding liquidity.\n   */\n\n  public async addLiquidityByStrategyChunkable({\n    positionPubKey,\n    totalXAmount,\n    totalYAmount,\n    strategy,\n    user,\n    slippage,\n  }: TInitializePositionAndAddLiquidityParamsByStrategy): Promise<\n    Transaction[]\n  > {\n    const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(\n      slippage,\n      this.lbPair.binStep,\n      MAX_ACTIVE_BIN_SLIPPAGE,\n    );\n\n    const { minBinId, maxBinId } = strategy;\n\n    const liquidityStrategyParameters = buildLiquidityStrategyParameters(\n      totalXAmount,\n      totalYAmount,\n      new BN(minBinId - this.lbPair.activeId),\n      new BN(maxBinId - this.lbPair.activeId),\n      new BN(this.lbPair.binStep),\n      strategy.singleSidedX,\n      new BN(this.lbPair.activeId),\n      getLiquidityStrategyParameterBuilder(strategy.strategyType),\n    );\n\n    const chunkedAddLiquidityIx = await chunkDepositWithRebalanceEndpoint(\n      this,\n      strategy,\n      slippage,\n      maxActiveBinSlippage,\n      positionPubKey,\n      minBinId,\n      maxBinId,\n      liquidityStrategyParameters,\n      user,\n      user,\n      true,\n      this.opt?.skipSolWrappingOperation,\n    );\n\n    const latestBlockhashInfo =\n      await this.program.provider.connection.getLatestBlockhash();\n\n    return chunkedAddLiquidityIx.map((ixs) => {\n      return new Transaction({\n        ...latestBlockhashInfo,\n        feePayer: user,\n      }).add(...ixs);\n    });\n  }\n\n  /**\n   * The function `initializePositionAndAddLiquidityByStrategy` function is used to initializes a position and adds liquidity\n   * @param {TInitializePositionAndAddLiquidityParamsByStrategy}\n   *    - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)\n   *    - `totalXAmount`: The total amount of token X to be added to the liquidity pool.\n   *    - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.\n   *    - `strategy`: The strategy parameters to be used for the liquidity pool (Can use `calculateStrategyParameter` to calculate).\n   *    - `user`: The public key of the user account.\n   *    - `slippage`: The slippage percentage to be used for the liquidity pool.\n   * @returns {Promise<Transaction>} The function `initializePositionAndAddLiquidityByStrategy` returns a `Promise` that\n   * resolves to either a single `Transaction` object.\n   */\n  public async initializePositionAndAddLiquidityByStrategy({\n    positionPubKey,\n    totalXAmount,\n    totalYAmount,\n    strategy,\n    user,\n    slippage,\n  }: TInitializePositionAndAddLiquidityParamsByStrategy) {\n    const { maxBinId, minBinId } = strategy;\n\n    const maxActiveBinSlippage = slippage\n      ? Math.ceil(slippage / (this.lbPair.binStep / 100))\n      : MAX_ACTIVE_BIN_SLIPPAGE;\n\n    const preInstructions: TransactionInstruction[] = [];\n    const initializePositionIx = await this.program.methods\n      .initializePosition(minBinId, maxBinId - minBinId + 1)\n      .accountsPartial({\n        payer: user,\n        position: positionPubKey,\n        lbPair: this.pubkey,\n        owner: user,\n        rent: SYSVAR_RENT_PUBKEY,\n      })\n      .instruction();\n    preInstructions.push(initializePositionIx);\n\n    const binArrayIndexes = getBinArrayIndexesCoverage(\n      new BN(minBinId),\n      new BN(maxBinId),\n    );\n\n    const binArrayAccountMetas = getBinArrayAccountMetasCoverage(\n      new BN(minBinId),\n      new BN(maxBinId),\n      this.pubkey,\n      this.program.programId,\n    );\n\n    const createBinArrayIxs = await this.createBinArraysIfNeeded(\n      binArrayIndexes,\n      user,\n    );\n    preInstructions.push(...createBinArrayIxs);\n\n    const [\n      { ataPubKey: userTokenX, ix: createPayerTokenXIx },\n      { ataPubKey: userTokenY, ix: createPayerTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        user,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        user,\n        this.tokenY.owner,\n      ),\n    ]);\n    createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);\n    createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);\n\n    if (\n      this.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !totalXAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenX,\n        BigInt(totalXAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    if (\n      this.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !totalYAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenY,\n        BigInt(totalYAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    const postInstructions: Array<TransactionInstruction> = [];\n    if (\n      [\n        this.tokenX.publicKey.toBase58(),\n        this.tokenY.publicKey.toBase58(),\n      ].includes(NATIVE_MINT.toBase58()) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const minBinArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const maxBinArrayIndex = binIdToBinArrayIndex(new BN(maxBinId));\n\n    const useExtension =\n      isOverflowDefaultBinArrayBitmap(minBinArrayIndex) ||\n      isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);\n\n    const binArrayBitmapExtension = useExtension\n      ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0]\n      : null;\n\n    const activeId = this.lbPair.activeId;\n\n    const strategyParameters: LiquidityParameterByStrategy[\"strategyParameters\"] =\n      toStrategyParameters(strategy) as ProgramStrategyParameter;\n\n    const liquidityParams: LiquidityParameterByStrategy = {\n      amountX: totalXAmount,\n      amountY: totalYAmount,\n      activeId,\n      maxActiveBinSlippage,\n      strategyParameters,\n    };\n\n    const addLiquidityAccounts = {\n      position: positionPubKey,\n      lbPair: this.pubkey,\n      userTokenX,\n      userTokenY,\n      reserveX: this.lbPair.reserveX,\n      reserveY: this.lbPair.reserveY,\n      tokenXMint: this.lbPair.tokenXMint,\n      tokenYMint: this.lbPair.tokenYMint,\n      binArrayBitmapExtension,\n      sender: user,\n      tokenXProgram: this.tokenX.owner,\n      tokenYProgram: this.tokenY.owner,\n      memoProgram: MEMO_PROGRAM_ID,\n    };\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const programMethod = this.program.methods.addLiquidityByStrategy2(\n      liquidityParams,\n      {\n        slices,\n      },\n    );\n\n    const addLiquidityIx = await programMethod\n      .accountsPartial(addLiquidityAccounts)\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(binArrayAccountMetas)\n      .instruction();\n\n    const instructions = [\n      ...preInstructions,\n      addLiquidityIx,\n      ...postInstructions,\n    ];\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      instructions,\n      user,\n    );\n\n    instructions.unshift(setCUIx);\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...instructions);\n  }\n\n  /**\n   * @deprecated Use `initializePositionAndAddLiquidityByStrategy` instead which support both token and token2022.\n   * The function `initializePositionAndAddLiquidityByWeight` function is used to initializes a position and adds liquidity\n   * @param {TInitializePositionAndAddLiquidityParams}\n   *    - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)\n   *    - `totalXAmount`: The total amount of token X to be added to the liquidity pool.\n   *    - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.\n   *    - `xYAmountDistribution`: An array of objects of type `XYAmountDistribution` that represents (can use `calculateSpotDistribution`, `calculateBidAskDistribution` & `calculateNormalDistribution`)\n   *    - `user`: The public key of the user account.\n   *    - `slippage`: The slippage percentage to be used for the liquidity pool.\n   * @returns {Promise<Transaction|Transaction[]>} The function `initializePositionAndAddLiquidityByWeight` returns a `Promise` that\n   * resolves to either a single `Transaction` object (if less than 26bin involved) or an array of `Transaction` objects.\n   */\n  public async initializePositionAndAddLiquidityByWeight({\n    positionPubKey,\n    totalXAmount,\n    totalYAmount,\n    xYAmountDistribution,\n    user,\n    slippage,\n  }: TInitializePositionAndAddLiquidityParams): Promise<\n    Transaction | Transaction[]\n  > {\n    const { lowerBinId, upperBinId, binIds } =\n      this.processXYAmountDistribution(xYAmountDistribution);\n\n    const maxActiveBinSlippage = slippage\n      ? Math.ceil(slippage / (this.lbPair.binStep / 100))\n      : MAX_ACTIVE_BIN_SLIPPAGE;\n\n    if (upperBinId >= lowerBinId + DEFAULT_BIN_PER_POSITION.toNumber()) {\n      throw new Error(\n        `Position must be within a range of 1 to ${DEFAULT_BIN_PER_POSITION.toNumber()} bins.`,\n      );\n    }\n\n    const preInstructions: Array<TransactionInstruction> = [];\n    const initializePositionIx = await this.program.methods\n      .initializePosition(lowerBinId, upperBinId - lowerBinId + 1)\n      .accountsPartial({\n        payer: user,\n        position: positionPubKey,\n        lbPair: this.pubkey,\n        owner: user,\n        rent: SYSVAR_RENT_PUBKEY,\n      })\n      .instruction();\n    preInstructions.push(initializePositionIx);\n\n    const lowerBinArrayIndex = binIdToBinArrayIndex(new BN(lowerBinId));\n    const [binArrayLower] = deriveBinArray(\n      this.pubkey,\n      lowerBinArrayIndex,\n      this.program.programId,\n    );\n\n    const upperBinArrayIndex = BN.max(\n      lowerBinArrayIndex.add(new BN(1)),\n      binIdToBinArrayIndex(new BN(upperBinId)),\n    );\n    const [binArrayUpper] = deriveBinArray(\n      this.pubkey,\n      upperBinArrayIndex,\n      this.program.programId,\n    );\n\n    const createBinArrayIxs = await this.createBinArraysIfNeeded(\n      [lowerBinArrayIndex, upperBinArrayIndex],\n      user,\n    );\n    preInstructions.push(...createBinArrayIxs);\n\n    const [\n      { ataPubKey: userTokenX, ix: createPayerTokenXIx },\n      { ataPubKey: userTokenY, ix: createPayerTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        user,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        user,\n        this.tokenY.owner,\n      ),\n    ]);\n    createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);\n    createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);\n\n    if (\n      this.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !totalXAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenX,\n        BigInt(totalXAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    if (\n      this.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !totalYAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenY,\n        BigInt(totalYAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    const postInstructions: Array<TransactionInstruction> = [];\n    if (\n      [\n        this.tokenX.publicKey.toBase58(),\n        this.tokenY.publicKey.toBase58(),\n      ].includes(NATIVE_MINT.toBase58()) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const minBinId = Math.min(...binIds);\n    const maxBinId = Math.max(...binIds);\n\n    const minBinArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const maxBinArrayIndex = binIdToBinArrayIndex(new BN(maxBinId));\n\n    const useExtension =\n      isOverflowDefaultBinArrayBitmap(minBinArrayIndex) ||\n      isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);\n\n    const binArrayBitmapExtension = useExtension\n      ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0]\n      : null;\n\n    const activeId = this.lbPair.activeId;\n\n    const binLiquidityDist: LiquidityParameterByWeight[\"binLiquidityDist\"] =\n      toWeightDistribution(\n        totalXAmount,\n        totalYAmount,\n        xYAmountDistribution.map((item) => ({\n          binId: item.binId,\n          xAmountBpsOfTotal: item.xAmountBpsOfTotal,\n          yAmountBpsOfTotal: item.yAmountBpsOfTotal,\n        })),\n        this.lbPair.binStep,\n      );\n\n    if (binLiquidityDist.length === 0) {\n      throw new Error(\"No liquidity to add\");\n    }\n\n    const liquidityParams: LiquidityParameterByWeight = {\n      amountX: totalXAmount,\n      amountY: totalYAmount,\n      binLiquidityDist,\n      activeId,\n      maxActiveBinSlippage,\n    };\n\n    const addLiquidityAccounts = {\n      position: positionPubKey,\n      lbPair: this.pubkey,\n      userTokenX,\n      userTokenY,\n      reserveX: this.lbPair.reserveX,\n      reserveY: this.lbPair.reserveY,\n      tokenXMint: this.lbPair.tokenXMint,\n      tokenYMint: this.lbPair.tokenYMint,\n      binArrayLower,\n      binArrayUpper,\n      binArrayBitmapExtension,\n      sender: user,\n      tokenXProgram: TOKEN_PROGRAM_ID,\n      tokenYProgram: TOKEN_PROGRAM_ID,\n    };\n\n    const oneSideLiquidityParams: LiquidityOneSideParameter = {\n      amount: totalXAmount.isZero() ? totalYAmount : totalXAmount,\n      activeId,\n      maxActiveBinSlippage,\n      binLiquidityDist,\n    };\n\n    const oneSideAddLiquidityAccounts = {\n      binArrayLower,\n      binArrayUpper,\n      lbPair: this.pubkey,\n      binArrayBitmapExtension: null,\n      sender: user,\n      position: positionPubKey,\n      reserve: totalXAmount.isZero()\n        ? this.lbPair.reserveY\n        : this.lbPair.reserveX,\n      tokenMint: totalXAmount.isZero()\n        ? this.lbPair.tokenYMint\n        : this.lbPair.tokenXMint,\n      tokenProgram: TOKEN_PROGRAM_ID,\n      userToken: totalXAmount.isZero() ? userTokenY : userTokenX,\n    };\n\n    const isOneSideDeposit = totalXAmount.isZero() || totalYAmount.isZero();\n    const programMethod = isOneSideDeposit\n      ? this.program.methods.addLiquidityOneSide(oneSideLiquidityParams)\n      : this.program.methods.addLiquidityByWeight(liquidityParams);\n\n    if (xYAmountDistribution.length < MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX) {\n      const addLiqIx = await programMethod\n        .accountsPartial(\n          isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts,\n        )\n        .instruction();\n\n      const instructions = [...preInstructions, addLiqIx, ...postInstructions];\n\n      const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n        this.program.provider.connection,\n        instructions,\n        user,\n      );\n\n      instructions.unshift(setCUIx);\n\n      const { blockhash, lastValidBlockHeight } =\n        await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n      return new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...instructions);\n    }\n\n    const addLiqIx = await programMethod\n      .accountsPartial(\n        isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts,\n      )\n      .instruction();\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      [addLiqIx],\n      user,\n      DEFAULT_ADD_LIQUIDITY_CU, // The function return multiple transactions that dependent on each other, simulation will fail\n    );\n\n    const mainInstructions = [setCUIx, addLiqIx];\n\n    const transactions: Transaction[] = [];\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    if (preInstructions.length) {\n      const preInstructionsTx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...preInstructions);\n      transactions.push(preInstructionsTx);\n    }\n\n    const mainTx = new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...mainInstructions);\n    transactions.push(mainTx);\n\n    if (postInstructions.length) {\n      const postInstructionsTx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...postInstructions);\n      transactions.push(postInstructionsTx);\n    }\n\n    return transactions;\n  }\n\n  /**\n   * The `addLiquidityByStrategy` function is used to add liquidity to existing position\n   * @param {TInitializePositionAndAddLiquidityParamsByStrategy}\n   *    - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)\n   *    - `totalXAmount`: The total amount of token X to be added to the liquidity pool.\n   *    - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.\n   *    - `strategy`: The strategy parameters to be used for the liquidity pool (Can use `calculateStrategyParameter` to calculate).\n   *    - `user`: The public key of the user account.\n   *    - `slippage`: The slippage percentage to be used for the liquidity pool.\n   * @returns {Promise<Transaction>} The function `addLiquidityByWeight` returns a `Promise` that resolves to either a single\n   * `Transaction` object\n   */\n  public async addLiquidityByStrategy({\n    positionPubKey,\n    totalXAmount,\n    totalYAmount,\n    strategy,\n    user,\n    slippage,\n  }: TInitializePositionAndAddLiquidityParamsByStrategy): Promise<Transaction> {\n    const { maxBinId, minBinId } = strategy;\n\n    const maxActiveBinSlippage = slippage\n      ? Math.ceil(slippage / (this.lbPair.binStep / 100))\n      : MAX_ACTIVE_BIN_SLIPPAGE;\n\n    const preInstructions: TransactionInstruction[] = [];\n\n    const minBinArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const maxBinArrayIndex = binIdToBinArrayIndex(new BN(maxBinId));\n\n    const useExtension =\n      isOverflowDefaultBinArrayBitmap(minBinArrayIndex) ||\n      isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);\n\n    const binArrayBitmapExtension = useExtension\n      ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0]\n      : null;\n\n    const strategyParameters: LiquidityParameterByStrategy[\"strategyParameters\"] =\n      toStrategyParameters(strategy) as ProgramStrategyParameter;\n\n    const binArrayIndexes = getBinArrayIndexesCoverage(\n      new BN(minBinId),\n      new BN(maxBinId),\n    );\n\n    const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(\n      new BN(minBinId),\n      new BN(maxBinId),\n      this.pubkey,\n      this.program.programId,\n    );\n\n    const createBinArrayIxs = await this.createBinArraysIfNeeded(\n      binArrayIndexes,\n      user,\n    );\n    preInstructions.push(...createBinArrayIxs);\n\n    const [\n      { ataPubKey: userTokenX, ix: createPayerTokenXIx },\n      { ataPubKey: userTokenY, ix: createPayerTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        user,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        user,\n        this.tokenY.owner,\n      ),\n    ]);\n\n    createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);\n    createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);\n\n    if (\n      this.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !totalXAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenX,\n        BigInt(totalXAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    if (\n      this.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !totalYAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenY,\n        BigInt(totalYAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    const postInstructions: Array<TransactionInstruction> = [];\n    if (\n      [\n        this.tokenX.publicKey.toBase58(),\n        this.tokenY.publicKey.toBase58(),\n      ].includes(NATIVE_MINT.toBase58()) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const liquidityParams: LiquidityParameterByStrategy = {\n      amountX: totalXAmount,\n      amountY: totalYAmount,\n      activeId: this.lbPair.activeId,\n      maxActiveBinSlippage,\n      strategyParameters,\n    };\n\n    const addLiquidityAccounts = {\n      position: positionPubKey,\n      lbPair: this.pubkey,\n      userTokenX,\n      userTokenY,\n      reserveX: this.lbPair.reserveX,\n      reserveY: this.lbPair.reserveY,\n      tokenXMint: this.lbPair.tokenXMint,\n      tokenYMint: this.lbPair.tokenYMint,\n      binArrayBitmapExtension,\n      sender: user,\n      tokenXProgram: this.tokenX.owner,\n      tokenYProgram: this.tokenY.owner,\n      memoProgram: MEMO_PROGRAM_ID,\n    };\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const programMethod = this.program.methods.addLiquidityByStrategy2(\n      liquidityParams,\n      {\n        slices,\n      },\n    );\n\n    const addLiquidityIx = await programMethod\n      .accounts(addLiquidityAccounts)\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(binArrayAccountsMeta)\n      .instruction();\n\n    const instructions = [\n      ...preInstructions,\n      addLiquidityIx,\n      ...postInstructions,\n    ];\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      instructions,\n      user,\n    );\n\n    instructions.unshift(setCUIx);\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...instructions);\n  }\n\n  /**\n   * @deprecated Use `addLiquidityByStrategy` instead which support both token and token2022.\n   * The `addLiquidityByWeight` function is used to add liquidity to existing position\n   * @param {TInitializePositionAndAddLiquidityParams}\n   *    - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)\n   *    - `totalXAmount`: The total amount of token X to be added to the liquidity pool.\n   *    - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.\n   *    - `xYAmountDistribution`: An array of objects of type `XYAmountDistribution` that represents (can use `calculateSpotDistribution`, `calculateBidAskDistribution` & `calculateNormalDistribution`)\n   *    - `user`: The public key of the user account.\n   *    - `slippage`: The slippage percentage to be used for the liquidity pool.\n   * @returns {Promise<Transaction|Transaction[]>} The function `addLiquidityByWeight` returns a `Promise` that resolves to either a single\n   * `Transaction` object (if less than 26bin involved) or an array of `Transaction` objects.\n   */\n  public async addLiquidityByWeight({\n    positionPubKey,\n    totalXAmount,\n    totalYAmount,\n    xYAmountDistribution,\n    user,\n    slippage,\n  }: TInitializePositionAndAddLiquidityParams): Promise<\n    Transaction | Transaction[]\n  > {\n    const maxActiveBinSlippage = slippage\n      ? Math.ceil(slippage / (this.lbPair.binStep / 100))\n      : MAX_ACTIVE_BIN_SLIPPAGE;\n\n    const positionAccount =\n      await this.program.account.positionV2.fetch(positionPubKey);\n    const { lowerBinId, upperBinId, binIds } =\n      this.processXYAmountDistribution(xYAmountDistribution);\n\n    if (lowerBinId < positionAccount.lowerBinId)\n      throw new Error(\n        `Lower Bin ID (${lowerBinId}) lower than Position Lower Bin Id (${positionAccount.lowerBinId})`,\n      );\n    if (upperBinId > positionAccount.upperBinId)\n      throw new Error(\n        `Upper Bin ID (${upperBinId}) higher than Position Upper Bin Id (${positionAccount.upperBinId})`,\n      );\n\n    const minBinId = Math.min(...binIds);\n    const maxBinId = Math.max(...binIds);\n\n    const minBinArrayIndex = binIdToBinArrayIndex(new BN(minBinId));\n    const maxBinArrayIndex = binIdToBinArrayIndex(new BN(maxBinId));\n\n    const useExtension =\n      isOverflowDefaultBinArrayBitmap(minBinArrayIndex) ||\n      isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);\n\n    const binArrayBitmapExtension = useExtension\n      ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0]\n      : null;\n\n    const activeId = this.lbPair.activeId;\n\n    const binLiquidityDist: LiquidityParameterByWeight[\"binLiquidityDist\"] =\n      toWeightDistribution(\n        totalXAmount,\n        totalYAmount,\n        xYAmountDistribution.map((item) => ({\n          binId: item.binId,\n          xAmountBpsOfTotal: item.xAmountBpsOfTotal,\n          yAmountBpsOfTotal: item.yAmountBpsOfTotal,\n        })),\n        this.lbPair.binStep,\n      );\n\n    if (binLiquidityDist.length === 0) {\n      throw new Error(\"No liquidity to add\");\n    }\n\n    const lowerBinArrayIndex = binIdToBinArrayIndex(\n      new BN(positionAccount.lowerBinId),\n    );\n    const [binArrayLower] = deriveBinArray(\n      this.pubkey,\n      lowerBinArrayIndex,\n      this.program.programId,\n    );\n\n    const upperBinArrayIndex = BN.max(\n      lowerBinArrayIndex.add(new BN(1)),\n      binIdToBinArrayIndex(new BN(positionAccount.upperBinId)),\n    );\n    const [binArrayUpper] = deriveBinArray(\n      this.pubkey,\n      upperBinArrayIndex,\n      this.program.programId,\n    );\n\n    const preInstructions: TransactionInstruction[] = [];\n    const createBinArrayIxs = await this.createBinArraysIfNeeded(\n      [lowerBinArrayIndex, upperBinArrayIndex],\n      user,\n    );\n    preInstructions.push(...createBinArrayIxs);\n\n    const [\n      { ataPubKey: userTokenX, ix: createPayerTokenXIx },\n      { ataPubKey: userTokenY, ix: createPayerTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        user,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        user,\n        this.tokenY.owner,\n      ),\n    ]);\n    createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);\n    createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);\n\n    if (\n      this.tokenX.publicKey.equals(NATIVE_MINT) &&\n      !totalXAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenX,\n        BigInt(totalXAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    if (\n      this.tokenY.publicKey.equals(NATIVE_MINT) &&\n      !totalYAmount.isZero() &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenY,\n        BigInt(totalYAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    const postInstructions: Array<TransactionInstruction> = [];\n    if (\n      [\n        this.tokenX.publicKey.toBase58(),\n        this.tokenY.publicKey.toBase58(),\n      ].includes(NATIVE_MINT.toBase58()) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const liquidityParams: LiquidityParameterByWeight = {\n      amountX: totalXAmount,\n      amountY: totalYAmount,\n      binLiquidityDist,\n      activeId,\n      maxActiveBinSlippage,\n    };\n\n    const addLiquidityAccounts = {\n      position: positionPubKey,\n      lbPair: this.pubkey,\n      userTokenX,\n      userTokenY,\n      reserveX: this.lbPair.reserveX,\n      reserveY: this.lbPair.reserveY,\n      tokenXMint: this.lbPair.tokenXMint,\n      tokenYMint: this.lbPair.tokenYMint,\n      binArrayLower,\n      binArrayUpper,\n      binArrayBitmapExtension,\n      sender: user,\n      tokenXProgram: TOKEN_PROGRAM_ID,\n      tokenYProgram: TOKEN_PROGRAM_ID,\n    };\n\n    const oneSideLiquidityParams: LiquidityOneSideParameter = {\n      amount: totalXAmount.isZero() ? totalYAmount : totalXAmount,\n      activeId,\n      maxActiveBinSlippage,\n      binLiquidityDist,\n    };\n\n    const oneSideAddLiquidityAccounts = {\n      binArrayLower,\n      binArrayUpper,\n      lbPair: this.pubkey,\n      binArrayBitmapExtension: null,\n      sender: user,\n      position: positionPubKey,\n      reserve: totalXAmount.isZero()\n        ? this.lbPair.reserveY\n        : this.lbPair.reserveX,\n      tokenMint: totalXAmount.isZero()\n        ? this.lbPair.tokenYMint\n        : this.lbPair.tokenXMint,\n      tokenProgram: TOKEN_PROGRAM_ID,\n      userToken: totalXAmount.isZero() ? userTokenY : userTokenX,\n    };\n\n    const isOneSideDeposit = totalXAmount.isZero() || totalYAmount.isZero();\n    const programMethod = isOneSideDeposit\n      ? this.program.methods.addLiquidityOneSide(oneSideLiquidityParams)\n      : this.program.methods.addLiquidityByWeight(liquidityParams);\n\n    if (xYAmountDistribution.length < MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX) {\n      const addLiqIx = await programMethod\n        .accountsPartial(\n          isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts,\n        )\n        .instruction();\n\n      const instructions = [...preInstructions, addLiqIx, ...postInstructions];\n\n      const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n        this.program.provider.connection,\n        instructions,\n        user,\n      );\n\n      instructions.unshift(setCUIx);\n\n      const { blockhash, lastValidBlockHeight } =\n        await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n      return new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...instructions);\n    }\n\n    const addLiqIx = await programMethod\n      .accountsPartial(\n        isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts,\n      )\n      .instruction();\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      [addLiqIx],\n      user,\n    );\n\n    const mainInstructions = [setCUIx, addLiqIx];\n\n    const transactions: Transaction[] = [];\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    if (preInstructions.length) {\n      const preInstructionsTx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...preInstructions);\n      transactions.push(preInstructionsTx);\n    }\n\n    const mainTx = new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...mainInstructions);\n    transactions.push(mainTx);\n\n    if (postInstructions.length) {\n      const postInstructionsTx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...postInstructions);\n      transactions.push(postInstructionsTx);\n    }\n\n    return transactions;\n  }\n\n  /**\n   * The `removeLiquidity` function is used to remove liquidity from a position,\n   * with the option to claim rewards and close the position.\n   * @param\n   *    - `user`: The public key of the user account.\n   *    - `position`: The public key of the position account.\n   *    - `fromBinId`: The ID of the starting bin to remove liquidity from. Must within position range.\n   *    - `toBinId`: The ID of the ending bin to remove liquidity from. Must within position range.\n   *    - `liquiditiesBpsToRemove`: An array of numbers (percentage) that represent the liquidity to remove from each bin.\n   *    - `shouldClaimAndClose`: A boolean flag that indicates whether to claim rewards and close the position.\n   *    - `skipUnwrapSOL`: A boolean flag that indicates whether to skip unwrapping SOL. Enable this when using zap-sdk to ensure accuracy in SOL zap out amount when SOL is in token\n   * @returns {Promise<Transaction[]>}\n   */\n  public async removeLiquidity({\n    user,\n    position,\n    fromBinId,\n    toBinId,\n    bps,\n    shouldClaimAndClose = false,\n    skipUnwrapSOL = false,\n  }: {\n    user: PublicKey;\n    position: PublicKey;\n    fromBinId: number;\n    toBinId: number;\n    bps: BN;\n    shouldClaimAndClose?: boolean;\n    skipUnwrapSOL?: boolean;\n  }): Promise<Transaction[]> {\n    const positionAccount =\n      await this.program.provider.connection.getAccountInfo(position);\n\n    const positionState = wrapPosition(this.program, position, positionAccount);\n\n    const lbPair = positionState.lbPair();\n    const owner = positionState.owner();\n    const feeOwner = positionState.feeOwner();\n    const liquidityShares = positionState.liquidityShares();\n    const feeInfos = positionState.feeInfos();\n    const rewardInfos = positionState.rewardInfos();\n\n    const binDataWithBinId = liquidityShares.map((share, i) => {\n      const feeInfo = feeInfos[i];\n      const rewardInfo = rewardInfos[i];\n      const hasFees =\n        feeInfo &&\n        (!feeInfo.feeXPending.isZero() || !feeInfo.feeYPending.isZero());\n      const hasRewards =\n        rewardInfo &&\n        rewardInfo.rewardPendings.some((pending) => !pending.isZero());\n      return {\n        share,\n        binId: positionState.lowerBinId().add(new BN(i)),\n        hasFeesOrRewards: hasFees || hasRewards,\n      };\n    });\n\n    const binIdsWithLiquidity = binDataWithBinId.filter((bin) => {\n      return !bin.share.isZero();\n    });\n\n    const binIdsWithLiquidityOrFees = binDataWithBinId.filter((bin) => {\n      return !bin.share.isZero() || bin.hasFeesOrRewards;\n    });\n\n    const hasLiquidity = binIdsWithLiquidity.length > 0;\n    if (!hasLiquidity && !shouldClaimAndClose) {\n      throw new Error(\"No liquidity to remove\");\n    }\n\n    const activeBins = shouldClaimAndClose\n      ? binIdsWithLiquidityOrFees\n      : binIdsWithLiquidity;\n\n    const lowerActiveBinId = activeBins[0].binId.toNumber();\n    const upperActiveBinId = activeBins[activeBins.length - 1].binId.toNumber();\n\n    // Avoid to attempt to load uninitialized bin array on the program\n    if (fromBinId < lowerActiveBinId) {\n      fromBinId = lowerActiveBinId;\n    }\n\n    if (toBinId > upperActiveBinId) {\n      toBinId = upperActiveBinId;\n    }\n\n    const walletToReceiveFee = feeOwner.equals(PublicKey.default)\n      ? user\n      : feeOwner;\n\n    const userTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      owner,\n      true,\n      this.tokenX.owner,\n    );\n\n    const userTokenY = getAssociatedTokenAddressSync(\n      this.lbPair.tokenYMint,\n      owner,\n      true,\n      this.tokenY.owner,\n    );\n\n    const feeOwnerTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      walletToReceiveFee,\n      true,\n      this.tokenX.owner,\n    );\n\n    const feeOwnerTokenY = getAssociatedTokenAddressSync(\n      this.lbPair.tokenYMint,\n      walletToReceiveFee,\n      true,\n      this.tokenY.owner,\n    );\n\n    const createUserTokenXIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        user,\n        userTokenX,\n        owner,\n        this.lbPair.tokenXMint,\n        this.tokenX.owner,\n      );\n\n    const createUserTokenYIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        user,\n        userTokenY,\n        owner,\n        this.lbPair.tokenYMint,\n        this.tokenY.owner,\n      );\n\n    const createFeeOwnerTokenXIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        user,\n        feeOwnerTokenX,\n        walletToReceiveFee,\n        this.lbPair.tokenXMint,\n        this.tokenX.owner,\n      );\n\n    const createFeeOwnerTokenYIx =\n      createAssociatedTokenAccountIdempotentInstruction(\n        user,\n        feeOwnerTokenY,\n        walletToReceiveFee,\n        this.lbPair.tokenYMint,\n        this.tokenY.owner,\n      );\n\n    const chunkedBinRange = chunkBinRange(fromBinId, toBinId);\n    const groupedInstructions: TransactionInstruction[][] = [];\n\n    for (const { lowerBinId, upperBinId } of chunkedBinRange) {\n      const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(\n        new BN(lowerBinId),\n        new BN(upperBinId),\n        this.pubkey,\n        this.program.programId,\n      );\n\n      const { slices, accounts: transferHookAccounts } =\n        this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n      const preInstructions: Array<TransactionInstruction> = [];\n      const postInstructions: Array<TransactionInstruction> = [];\n\n      if (shouldClaimAndClose) {\n        const claimSwapFeeIx = await this.program.methods\n          .claimFee2(lowerBinId, upperBinId, {\n            slices,\n          })\n          .accountsPartial({\n            lbPair: this.pubkey,\n            sender: user,\n            position,\n            reserveX: this.lbPair.reserveX,\n            reserveY: this.lbPair.reserveY,\n            tokenXMint: this.tokenX.publicKey,\n            tokenYMint: this.tokenY.publicKey,\n            userTokenX: feeOwnerTokenX,\n            userTokenY: feeOwnerTokenY,\n            tokenProgramX: this.tokenX.owner,\n            tokenProgramY: this.tokenY.owner,\n            memoProgram: MEMO_PROGRAM_ID,\n          })\n          .remainingAccounts(transferHookAccounts)\n          .remainingAccounts(binArrayAccountsMeta)\n          .instruction();\n\n        preInstructions.push(createFeeOwnerTokenXIx);\n        preInstructions.push(createFeeOwnerTokenYIx);\n        postInstructions.push(claimSwapFeeIx);\n\n        for (let i = 0; i < 2; i++) {\n          const rewardInfo = this.lbPair.rewardInfos[i];\n          if (!rewardInfo || rewardInfo.mint.equals(PublicKey.default))\n            continue;\n\n          const userRewardAccount = getAssociatedTokenAddressSync(\n            rewardInfo.mint,\n            user,\n            true,\n            this.rewards[i].owner,\n          );\n\n          const createUserRewardAccountIx =\n            createAssociatedTokenAccountIdempotentInstruction(\n              user,\n              userRewardAccount,\n              user,\n              rewardInfo.mint,\n              this.rewards[i].owner,\n            );\n\n          preInstructions.push(createUserRewardAccountIx);\n\n          const { slices, accounts: transferHookAccounts } =\n            this.getPotentialToken2022IxDataAndAccounts(ActionType.Reward, i);\n\n          const claimRewardIx = await this.program.methods\n            .claimReward2(new BN(i), lowerBinId, upperBinId, {\n              slices,\n            })\n            .accountsPartial({\n              lbPair: this.pubkey,\n              sender: user,\n              position,\n              rewardVault: rewardInfo.vault,\n              rewardMint: rewardInfo.mint,\n              tokenProgram: this.rewards[i].owner,\n              userTokenAccount: userRewardAccount,\n              memoProgram: MEMO_PROGRAM_ID,\n            })\n            .remainingAccounts(transferHookAccounts)\n            .remainingAccounts(binArrayAccountsMeta)\n            .instruction();\n\n          postInstructions.push(claimRewardIx);\n        }\n\n        const closePositionIx = await this.program.methods\n          .closePositionIfEmpty()\n          .accountsPartial({\n            rentReceiver: owner, // Must be position owner\n            position,\n            sender: user,\n          })\n          .instruction();\n\n        postInstructions.push(closePositionIx);\n      }\n\n      if (\n        [\n          this.tokenX.publicKey.toBase58(),\n          this.tokenY.publicKey.toBase58(),\n        ].includes(NATIVE_MINT.toBase58()) &&\n        (!skipUnwrapSOL || !this.opt?.skipSolWrappingOperation)\n      ) {\n        const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n        closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n      }\n\n      preInstructions.push(createUserTokenXIx);\n      preInstructions.push(createUserTokenYIx);\n\n      const binArrayBitmapExtension = this.binArrayBitmapExtension\n        ? this.binArrayBitmapExtension.publicKey\n        : this.program.programId;\n\n      const instructions = [...preInstructions];\n\n      if (hasLiquidity) {\n        const removeLiquidityTx = await this.program.methods\n          .removeLiquidityByRange2(lowerBinId, upperBinId, bps.toNumber(), {\n            slices,\n          })\n          .accountsPartial({\n            position,\n            lbPair,\n            userTokenX,\n            userTokenY,\n            reserveX: this.lbPair.reserveX,\n            reserveY: this.lbPair.reserveY,\n            tokenXMint: this.tokenX.publicKey,\n            tokenYMint: this.tokenY.publicKey,\n            binArrayBitmapExtension,\n            tokenXProgram: this.tokenX.owner,\n            tokenYProgram: this.tokenY.owner,\n            sender: user,\n            memoProgram: MEMO_PROGRAM_ID,\n          })\n          .remainingAccounts(transferHookAccounts)\n          .remainingAccounts(binArrayAccountsMeta)\n          .instruction();\n\n        instructions.push(removeLiquidityTx);\n      }\n\n      instructions.push(...postInstructions);\n\n      groupedInstructions.push(instructions);\n    }\n\n    const groupedInstructionsWithCUIx = await Promise.all(\n      groupedInstructions.map(async (ixs) => {\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          ixs,\n          user,\n          0.3, // Extra 30% buffer CU\n        );\n\n        return [setCUIx, ...ixs];\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return groupedInstructionsWithCUIx.map((ixs) => {\n      return new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: user,\n      }).add(...ixs);\n    });\n  }\n\n  /**\n   * The `closePositionIfEmpty` function closes a position if it is empty. Else, it does nothing.\n   */\n  public async closePositionIfEmpty({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction> {\n    const closePositionIfEmptyIx = await this.program.methods\n      .closePositionIfEmpty()\n      .accountsPartial({\n        rentReceiver: owner,\n        position: position.publicKey,\n        sender: owner,\n      })\n      .instruction();\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      [closePositionIfEmptyIx],\n      owner,\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: owner,\n    }).add(setCUIx, closePositionIfEmptyIx);\n  }\n\n  /**\n   * The `closePosition` function closes a position\n   * @param\n   *    - `owner`: The public key of the owner of the position.\n   *    - `position`: The public key of the position account.\n   * @returns {Promise<Transaction>}\n   */\n  public async closePosition({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction> {\n    const closePositionIx = await this.program.methods\n      .closePosition2()\n      .accountsPartial({\n        rentReceiver: owner,\n        position: position.publicKey,\n        sender: owner,\n      })\n      .instruction();\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      [closePositionIx],\n      owner,\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: owner,\n    }).add(setCUIx, closePositionIx);\n  }\n\n  /**\n   * The `swapQuoteExactOut` function returns a quote for a swap\n   * @param\n   *    - `outAmount`: Amount of lamport to swap out\n   *    - `swapForY`: Swap token X to Y when it is true, else reversed.\n   *    - `allowedSlippage`: Allowed slippage for the swap. Expressed in BPS. To convert from slippage percentage to BPS unit: SLIPPAGE_PERCENTAGE * 100\n   *    - `maxExtraBinArrays`: Maximum number of extra binArrays to return\n   * @returns {SwapQuote}\n   *    - `inAmount`: Amount of lamport to swap in\n   *    - `outAmount`: Amount of lamport to swap out\n   *    - `fee`: Fee amount\n   *    - `protocolFee`: Protocol fee amount\n   *    - `maxInAmount`: Maximum amount of lamport to swap in\n   *    - `binArraysPubkey`: Array of bin arrays involved in the swap\n   * @throws {DlmmSdkError}\n   *\n   */\n  public swapQuoteExactOut(\n    outAmount: BN,\n    swapForY: boolean,\n    allowedSlippage: BN,\n    binArrays: BinArrayAccount[],\n    maxExtraBinArrays: number = 0,\n  ): SwapQuoteExactOut {\n    const currentTimestamp = Date.now() / 1000;\n\n    const [inMint, outMint] = swapForY\n      ? [this.tokenX.mint, this.tokenY.mint]\n      : [this.tokenY.mint, this.tokenX.mint];\n\n    let outAmountLeft = calculateTransferFeeIncludedAmount(\n      outAmount,\n      outMint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    if (maxExtraBinArrays < 0 || maxExtraBinArrays > MAX_EXTRA_BIN_ARRAYS) {\n      throw new DlmmSdkError(\n        \"INVALID_MAX_EXTRA_BIN_ARRAYS\",\n        `maxExtraBinArrays must be a value between 0 and ${MAX_EXTRA_BIN_ARRAYS}`,\n      );\n    }\n\n    let vParameterClone = Object.assign({}, this.lbPair.vParameters);\n    let activeId = new BN(this.lbPair.activeId);\n\n    const binStep = this.lbPair.binStep;\n    const sParameters = this.lbPair.parameters;\n\n    DLMM.updateReference(\n      activeId.toNumber(),\n      vParameterClone,\n      sParameters,\n      currentTimestamp,\n    );\n\n    let startBinId = activeId;\n    let binArraysForSwap = new Map();\n    let actualInAmount: BN = new BN(0);\n    let feeAmount: BN = new BN(0);\n    let protocolFeeAmount: BN = new BN(0);\n\n    while (!outAmountLeft.isZero()) {\n      let binArrayAccountToSwap = findNextBinArrayWithLiquidity(\n        swapForY,\n        activeId,\n        this.lbPair,\n        this.binArrayBitmapExtension?.account ?? null,\n        binArrays,\n      );\n\n      if (binArrayAccountToSwap == null) {\n        throw new DlmmSdkError(\n          \"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY\",\n          \"Insufficient liquidity in binArrays\",\n        );\n      }\n\n      binArraysForSwap.set(binArrayAccountToSwap.publicKey, true);\n\n      DLMM.updateVolatilityAccumulator(\n        vParameterClone,\n        sParameters,\n        activeId.toNumber(),\n      );\n\n      if (\n        isBinIdWithinBinArray(activeId, binArrayAccountToSwap.account.index)\n      ) {\n        const bin = getBinFromBinArray(\n          activeId.toNumber(),\n          binArrayAccountToSwap.account,\n        );\n        const { amountIn, amountOut, fee, protocolFee } =\n          swapExactOutQuoteAtBin(\n            bin,\n            binStep,\n            sParameters,\n            vParameterClone,\n            outAmountLeft,\n            swapForY,\n          );\n\n        if (!amountOut.isZero()) {\n          outAmountLeft = outAmountLeft.sub(amountOut);\n          actualInAmount = actualInAmount.add(amountIn);\n          feeAmount = feeAmount.add(fee);\n          protocolFeeAmount = protocolFee.add(protocolFee);\n        }\n      }\n\n      if (!outAmountLeft.isZero()) {\n        if (swapForY) {\n          activeId = activeId.sub(new BN(1));\n        } else {\n          activeId = activeId.add(new BN(1));\n        }\n      }\n    }\n\n    const startPrice = getPriceOfBinByBinId(\n      startBinId.toNumber(),\n      this.lbPair.binStep,\n    );\n    const endPrice = getPriceOfBinByBinId(\n      activeId.toNumber(),\n      this.lbPair.binStep,\n    );\n\n    const priceImpact = startPrice\n      .sub(endPrice)\n      .abs()\n      .div(startPrice)\n      .mul(new Decimal(100));\n\n    actualInAmount = calculateTransferFeeIncludedAmount(\n      actualInAmount.add(feeAmount),\n      inMint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    const maxInAmount = actualInAmount\n      .mul(new BN(BASIS_POINT_MAX).add(allowedSlippage))\n      .div(new BN(BASIS_POINT_MAX));\n\n    if (maxExtraBinArrays > 0 && maxExtraBinArrays <= MAX_EXTRA_BIN_ARRAYS) {\n      const extraBinArrays: Array<PublicKey> = new Array<PublicKey>();\n\n      while (extraBinArrays.length < maxExtraBinArrays) {\n        let binArrayAccountToSwap = findNextBinArrayWithLiquidity(\n          swapForY,\n          activeId,\n          this.lbPair,\n          this.binArrayBitmapExtension?.account ?? null,\n          binArrays,\n        );\n\n        if (binArrayAccountToSwap == null) {\n          break;\n        }\n\n        const binArrayAccountToSwapExisted = binArraysForSwap.has(\n          binArrayAccountToSwap.publicKey,\n        );\n\n        if (binArrayAccountToSwapExisted) {\n          if (swapForY) {\n            activeId = activeId.sub(new BN(1));\n          } else {\n            activeId = activeId.add(new BN(1));\n          }\n        } else {\n          extraBinArrays.push(binArrayAccountToSwap.publicKey);\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            binArrayAccountToSwap.account.index,\n          );\n\n          if (swapForY) {\n            activeId = lowerBinId.sub(new BN(1));\n          } else {\n            activeId = upperBinId.add(new BN(1));\n          }\n        }\n      }\n\n      // save to binArraysForSwap result\n      extraBinArrays.forEach((binArrayPubkey) => {\n        binArraysForSwap.set(binArrayPubkey, true);\n      });\n    }\n\n    const binArraysPubkey = Array.from(binArraysForSwap.keys());\n\n    return {\n      inAmount: actualInAmount,\n      maxInAmount,\n      outAmount,\n      priceImpact,\n      fee: feeAmount,\n      protocolFee: protocolFeeAmount,\n      binArraysPubkey,\n    };\n  }\n\n  /**\n   * The `swapQuote` function returns a quote for a swap\n   * @param\n   *    - `inAmount`: Amount of lamport to swap in\n   *    - `swapForY`: Swap token X to Y when it is true, else reversed.\n   *    - `allowedSlippage`: Allowed slippage for the swap. Expressed in BPS. To convert from slippage percentage to BPS unit: SLIPPAGE_PERCENTAGE * 100\n   *    - `binArrays`: binArrays for swapQuote.\n   *    - `isPartialFill`: Flag to check whether the the swapQuote is partial fill, default = false.\n   *    - `maxExtraBinArrays`: Maximum number of extra binArrays to return\n   * @returns {SwapQuote}\n   *    - `consumedInAmount`: Amount of lamport to swap in\n   *    - `outAmount`: Amount of lamport to swap out\n   *    - `fee`: Fee amount\n   *    - `protocolFee`: Protocol fee amount\n   *    - `minOutAmount`: Minimum amount of lamport to swap out\n   *    - `priceImpact`: Price impact of the swap\n   *    - `binArraysPubkey`: Array of bin arrays involved in the swap\n   * @throws {DlmmSdkError}\n   */\n  public swapQuote(\n    inAmount: BN,\n    swapForY: boolean,\n    allowedSlippage: BN,\n    binArrays: BinArrayAccount[],\n    isPartialFill?: boolean,\n    maxExtraBinArrays: number = 0,\n  ): SwapQuote {\n    const currentTimestamp = Date.now() / 1000;\n\n    if (maxExtraBinArrays < 0 || maxExtraBinArrays > MAX_EXTRA_BIN_ARRAYS) {\n      throw new DlmmSdkError(\n        \"INVALID_MAX_EXTRA_BIN_ARRAYS\",\n        `maxExtraBinArrays must be a value between 0 and ${MAX_EXTRA_BIN_ARRAYS}`,\n      );\n    }\n\n    const [inMint, outMint] = swapForY\n      ? [this.tokenX.mint, this.tokenY.mint]\n      : [this.tokenY.mint, this.tokenX.mint];\n\n    let transferFeeExcludedAmountIn = calculateTransferFeeExcludedAmount(\n      inAmount,\n      inMint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    let inAmountLeft = transferFeeExcludedAmountIn;\n\n    let vParameterClone = Object.assign({}, this.lbPair.vParameters);\n    let activeId = new BN(this.lbPair.activeId);\n\n    const binStep = this.lbPair.binStep;\n    const sParameters = this.lbPair.parameters;\n\n    DLMM.updateReference(\n      activeId.toNumber(),\n      vParameterClone,\n      sParameters,\n      currentTimestamp,\n    );\n\n    let startBin: Bin | null = null;\n    let binArraysForSwap = new Map();\n    let totalOutAmount: BN = new BN(0);\n    let feeAmount: BN = new BN(0);\n    let protocolFeeAmount: BN = new BN(0);\n    let lastFilledActiveBinId = activeId;\n\n    while (!inAmountLeft.isZero()) {\n      let binArrayAccountToSwap = findNextBinArrayWithLiquidity(\n        swapForY,\n        activeId,\n        this.lbPair,\n        this.binArrayBitmapExtension?.account ?? null,\n        binArrays,\n      );\n\n      if (binArrayAccountToSwap == null) {\n        if (isPartialFill) {\n          break;\n        } else {\n          throw new DlmmSdkError(\n            \"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY\",\n            \"Insufficient liquidity in binArrays for swapQuote\",\n          );\n        }\n      }\n\n      binArraysForSwap.set(binArrayAccountToSwap.publicKey, true);\n\n      DLMM.updateVolatilityAccumulator(\n        vParameterClone,\n        sParameters,\n        activeId.toNumber(),\n      );\n\n      if (\n        isBinIdWithinBinArray(activeId, binArrayAccountToSwap.account.index)\n      ) {\n        const bin = getBinFromBinArray(\n          activeId.toNumber(),\n          binArrayAccountToSwap.account,\n        );\n        const { amountIn, amountOut, fee, protocolFee } = swapExactInQuoteAtBin(\n          bin,\n          binStep,\n          sParameters,\n          vParameterClone,\n          inAmountLeft,\n          swapForY,\n        );\n\n        if (!amountIn.isZero()) {\n          inAmountLeft = inAmountLeft.sub(amountIn);\n          totalOutAmount = totalOutAmount.add(amountOut);\n          feeAmount = feeAmount.add(fee);\n          protocolFeeAmount = protocolFee.add(protocolFee);\n\n          if (!startBin) {\n            startBin = bin;\n          }\n\n          lastFilledActiveBinId = activeId;\n        }\n      }\n\n      if (!inAmountLeft.isZero()) {\n        if (swapForY) {\n          activeId = activeId.sub(new BN(1));\n        } else {\n          activeId = activeId.add(new BN(1));\n        }\n      }\n    }\n\n    if (!startBin) {\n      // The pool insufficient liquidity\n      throw new DlmmSdkError(\n        \"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY\",\n        \"Insufficient liquidity\",\n      );\n    }\n\n    const actualInAmount = transferFeeExcludedAmountIn.sub(inAmountLeft);\n\n    let transferFeeIncludedInAmount = calculateTransferFeeIncludedAmount(\n      actualInAmount,\n      inMint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    transferFeeIncludedInAmount = transferFeeIncludedInAmount.gt(inAmount)\n      ? inAmount\n      : transferFeeIncludedInAmount;\n\n    const outAmountWithoutSlippage = getOutAmount(\n      startBin,\n      actualInAmount.sub(\n        computeFeeFromAmount(\n          binStep,\n          sParameters,\n          vParameterClone,\n          actualInAmount,\n        ),\n      ),\n      swapForY,\n    );\n\n    const priceImpact = new Decimal(totalOutAmount.toString())\n      .sub(new Decimal(outAmountWithoutSlippage.toString()))\n      .div(new Decimal(outAmountWithoutSlippage.toString()))\n      .mul(new Decimal(100))\n      .abs();\n\n    const endPrice = getPriceOfBinByBinId(\n      lastFilledActiveBinId.toNumber(),\n      this.lbPair.binStep,\n    );\n\n    if (maxExtraBinArrays > 0 && maxExtraBinArrays <= MAX_EXTRA_BIN_ARRAYS) {\n      const extraBinArrays: Array<PublicKey> = new Array<PublicKey>();\n\n      while (extraBinArrays.length < maxExtraBinArrays) {\n        let binArrayAccountToSwap = findNextBinArrayWithLiquidity(\n          swapForY,\n          activeId,\n          this.lbPair,\n          this.binArrayBitmapExtension?.account ?? null,\n          binArrays,\n        );\n\n        if (binArrayAccountToSwap == null) {\n          break;\n        }\n\n        const binArrayAccountToSwapExisted = binArraysForSwap.has(\n          binArrayAccountToSwap.publicKey,\n        );\n\n        if (binArrayAccountToSwapExisted) {\n          if (swapForY) {\n            activeId = activeId.sub(new BN(1));\n          } else {\n            activeId = activeId.add(new BN(1));\n          }\n        } else {\n          extraBinArrays.push(binArrayAccountToSwap.publicKey);\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            binArrayAccountToSwap.account.index,\n          );\n\n          if (swapForY) {\n            activeId = lowerBinId.sub(new BN(1));\n          } else {\n            activeId = upperBinId.add(new BN(1));\n          }\n        }\n      }\n\n      // save to binArraysForSwap result\n      extraBinArrays.forEach((binArrayPubkey) => {\n        binArraysForSwap.set(binArrayPubkey, true);\n      });\n    }\n\n    const binArraysPubkey = Array.from(binArraysForSwap.keys());\n    const transferFeeExcludedAmountOut = calculateTransferFeeExcludedAmount(\n      totalOutAmount,\n      outMint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    const minOutAmount = transferFeeExcludedAmountOut\n      .mul(new BN(BASIS_POINT_MAX).sub(allowedSlippage))\n      .div(new BN(BASIS_POINT_MAX));\n\n    return {\n      consumedInAmount: transferFeeIncludedInAmount,\n      outAmount: transferFeeExcludedAmountOut,\n      fee: feeAmount,\n      protocolFee: protocolFeeAmount,\n      minOutAmount,\n      priceImpact,\n      binArraysPubkey,\n      endPrice,\n    };\n  }\n\n  public async swapExactOut({\n    inToken,\n    outToken,\n    outAmount,\n    maxInAmount,\n    lbPair,\n    user,\n    binArraysPubkey,\n  }: SwapExactOutParams): Promise<Transaction> {\n    const preInstructions: TransactionInstruction[] = [];\n    const postInstructions: Array<TransactionInstruction> = [];\n\n    const [inTokenProgram, outTokenProgram] = inToken.equals(\n      this.lbPair.tokenXMint,\n    )\n      ? [this.tokenX.owner, this.tokenY.owner]\n      : [this.tokenY.owner, this.tokenX.owner];\n\n    const [\n      { ataPubKey: userTokenIn, ix: createInTokenAccountIx },\n      { ataPubKey: userTokenOut, ix: createOutTokenAccountIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        inToken,\n        user,\n        inTokenProgram,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        outToken,\n        user,\n        outTokenProgram,\n      ),\n    ]);\n    createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);\n    createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);\n\n    if (inToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenIn,\n        BigInt(maxInAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    if (outToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const binArrays: AccountMeta[] = binArraysPubkey.map((pubkey) => {\n      return {\n        isSigner: false,\n        isWritable: true,\n        pubkey,\n      };\n    });\n\n    const swapIx = await this.program.methods\n      .swapExactOut2(maxInAmount, outAmount, { slices })\n      .accountsPartial({\n        lbPair,\n        reserveX: this.lbPair.reserveX,\n        reserveY: this.lbPair.reserveY,\n        tokenXMint: this.lbPair.tokenXMint,\n        tokenYMint: this.lbPair.tokenYMint,\n        tokenXProgram: this.tokenX.owner,\n        tokenYProgram: this.tokenY.owner,\n        user,\n        userTokenIn,\n        userTokenOut,\n        binArrayBitmapExtension: this.binArrayBitmapExtension\n          ? this.binArrayBitmapExtension.publicKey\n          : null,\n        oracle: this.lbPair.oracle,\n        hostFeeIn: null,\n        memoProgram: MEMO_PROGRAM_ID,\n      })\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(binArrays)\n      .instruction();\n\n    const instructions = [...preInstructions, swapIx, ...postInstructions];\n\n    // const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n    //   this.program.provider.connection,\n    //   instructions,\n    //   user\n    // );\n\n    // instructions.unshift(setCUIx);\n\n    instructions.push(\n      ComputeBudgetProgram.setComputeUnitLimit({\n        units: 1_400_000,\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...instructions);\n  }\n\n  /**\n   * Returns a transaction to be signed and sent by user performing swap.\n   * @param {SwapWithPriceImpactParams}\n   *    - `inToken`: The public key of the token to be swapped in.\n   *    - `outToken`: The public key of the token to be swapped out.\n   *    - `inAmount`: The amount of token to be swapped in.\n   *    - `priceImpact`: Accepted price impact bps.\n   *    - `lbPair`: The public key of the liquidity pool.\n   *    - `user`: The public key of the user account.\n   *    - `binArraysPubkey`: Array of bin arrays involved in the swap\n   * @returns {Promise<Transaction>}\n   */\n  public async swapWithPriceImpact({\n    inToken,\n    outToken,\n    inAmount,\n    lbPair,\n    user,\n    priceImpact,\n    binArraysPubkey,\n  }: SwapWithPriceImpactParams): Promise<Transaction> {\n    const preInstructions: TransactionInstruction[] = [];\n    const postInstructions: Array<TransactionInstruction> = [];\n\n    const [\n      { ataPubKey: userTokenIn, ix: createInTokenAccountIx },\n      { ataPubKey: userTokenOut, ix: createOutTokenAccountIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        inToken,\n        user,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        outToken,\n        user,\n        this.tokenY.owner,\n      ),\n    ]);\n    createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);\n    createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);\n\n    if (inToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenIn,\n        BigInt(inAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    if (outToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    // TODO: needs some refinement in case binArray not yet initialized\n    const binArrays: AccountMeta[] = binArraysPubkey.map((pubkey) => {\n      return {\n        isSigner: false,\n        isWritable: true,\n        pubkey,\n      };\n    });\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const swapIx = await this.program.methods\n      .swapWithPriceImpact2(\n        inAmount,\n        this.lbPair.activeId,\n        priceImpact.toNumber(),\n        { slices },\n      )\n      .accountsPartial({\n        lbPair,\n        reserveX: this.lbPair.reserveX,\n        reserveY: this.lbPair.reserveY,\n        tokenXMint: this.lbPair.tokenXMint,\n        tokenYMint: this.lbPair.tokenYMint,\n        tokenXProgram: this.tokenX.owner,\n        tokenYProgram: this.tokenY.owner,\n        user,\n        userTokenIn,\n        userTokenOut,\n        binArrayBitmapExtension: this.binArrayBitmapExtension\n          ? this.binArrayBitmapExtension.publicKey\n          : null,\n        oracle: this.lbPair.oracle,\n        hostFeeIn: null,\n        memoProgram: MEMO_PROGRAM_ID,\n      })\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(binArrays)\n      .instruction();\n\n    const instructions = [...preInstructions, swapIx, ...postInstructions];\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      instructions,\n      user,\n    );\n\n    instructions.unshift(setCUIx);\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...instructions);\n  }\n\n  /**\n   * Returns a transaction to be signed and sent by user performing swap.\n   * @param {SwapParams}\n   *    - `inToken`: The public key of the token to be swapped in.\n   *    - `outToken`: The public key of the token to be swapped out.\n   *    - `inAmount`: The amount of token to be swapped in.\n   *    - `minOutAmount`: The minimum amount of token to be swapped out.\n   *    - `lbPair`: The public key of the liquidity pool.\n   *    - `user`: The public key of the user account.\n   *    - `binArraysPubkey`: Array of bin arrays involved in the swap\n   * @returns {Promise<Transaction>}\n   */\n  public async swap({\n    inToken,\n    outToken,\n    inAmount,\n    minOutAmount,\n    lbPair,\n    user,\n    binArraysPubkey,\n  }: SwapParams): Promise<Transaction> {\n    const preInstructions: TransactionInstruction[] = [];\n    const postInstructions: Array<TransactionInstruction> = [];\n\n    const [inTokenProgram, outTokenProgram] = inToken.equals(\n      this.lbPair.tokenXMint,\n    )\n      ? [this.tokenX.owner, this.tokenY.owner]\n      : [this.tokenY.owner, this.tokenX.owner];\n\n    const [\n      { ataPubKey: userTokenIn, ix: createInTokenAccountIx },\n      { ataPubKey: userTokenOut, ix: createOutTokenAccountIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        inToken,\n        user,\n        inTokenProgram,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        outToken,\n        user,\n        outTokenProgram,\n      ),\n    ]);\n    createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);\n    createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);\n\n    if (inToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const wrapSOLIx = wrapSOLInstruction(\n        user,\n        userTokenIn,\n        BigInt(inAmount.toString()),\n      );\n\n      preInstructions.push(...wrapSOLIx);\n\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    if (outToken.equals(NATIVE_MINT) && !this.opt?.skipSolWrappingOperation) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(user);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    // TODO: needs some refinement in case binArray not yet initialized\n    const binArrays: AccountMeta[] = binArraysPubkey.map((pubkey) => {\n      return {\n        isSigner: false,\n        isWritable: true,\n        pubkey,\n      };\n    });\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const swapIx = await this.program.methods\n      .swap2(inAmount, minOutAmount, { slices })\n      .accountsPartial({\n        lbPair,\n        reserveX: this.lbPair.reserveX,\n        reserveY: this.lbPair.reserveY,\n        tokenXMint: this.lbPair.tokenXMint,\n        tokenYMint: this.lbPair.tokenYMint,\n        tokenXProgram: this.tokenX.owner,\n        tokenYProgram: this.tokenY.owner,\n        user,\n        userTokenIn,\n        userTokenOut,\n        binArrayBitmapExtension: this.binArrayBitmapExtension\n          ? this.binArrayBitmapExtension.publicKey\n          : null,\n        oracle: this.lbPair.oracle,\n        hostFeeIn: null,\n        memoProgram: MEMO_PROGRAM_ID,\n      })\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(binArrays)\n      .instruction();\n\n    const instructions = [...preInstructions, swapIx, ...postInstructions];\n\n    const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      instructions,\n      user,\n    );\n\n    instructions.unshift(setCUIx);\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: user,\n    }).add(...instructions);\n  }\n\n  /**\n   * The claimLMReward function is used to claim rewards for a specific position owned by a specific owner.\n   * @param\n   *    - `owner`: The public key of the owner of the position.\n   *    - `position`: The public key of the position account.\n   * @returns {Promise<Transaction[]>} Claim LM reward transactions.\n   */\n  public async claimLMReward({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction[]> {\n    if (isPositionNoReward(position.positionData)) {\n      throw new Error(\"No LM reward to claim\");\n    }\n\n    const claimTransactions = await this.createClaimBuildMethod({\n      owner,\n      position,\n    });\n\n    if (!claimTransactions.length) return;\n\n    const claimTransactionWithCUIx = await Promise.all(\n      claimTransactions.map(async (tx) => {\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          tx.instructions,\n          owner,\n        );\n\n        return [setCUIx, ...tx.instructions];\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return claimTransactionWithCUIx.map((ixs) => {\n      return new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: owner,\n      }).add(...ixs);\n    });\n  }\n\n  /**\n   * The `claimAllLMRewards` function is used to claim all liquidity mining rewards for a given owner\n   * and their positions.\n   * @param\n   *    - `owner`: The public key of the owner of the positions.\n   *    - `positions`: An array of objects of type `PositionData` that represents the positions to claim rewards from.\n   * @returns {Promise<Transaction[]>} Array of claim LM reward and fees transactions.\n   */\n  public async claimAllLMRewards({\n    owner,\n    positions,\n  }: {\n    owner: PublicKey;\n    positions: LbPosition[];\n  }): Promise<Transaction[]> {\n    if (\n      positions.every((position) => isPositionNoReward(position.positionData))\n    ) {\n      throw new Error(\"No LM reward to claim\");\n    }\n\n    const claimAllTxs = (\n      await Promise.all(\n        positions\n          .filter(\n            ({ positionData: { rewardOne, rewardTwo } }) =>\n              !rewardOne.isZero() || !rewardTwo.isZero(),\n          )\n          .map(async (position, idx) => {\n            return await this.createClaimBuildMethod({\n              owner,\n              position,\n            });\n          }),\n      )\n    ).flat();\n\n    const chunkedClaimAllTx = chunks(claimAllTxs, MAX_CLAIM_ALL_ALLOWED);\n\n    if (chunkedClaimAllTx.length === 0) return [];\n\n    const chunkedClaimAllTxIx = await Promise.all(\n      chunkedClaimAllTx.map(async (txs) => {\n        const ixs = txs.map((t) => t.instructions).flat();\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          ixs,\n          owner,\n        );\n\n        return [setCUIx, ...ixs];\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return Promise.all(\n      chunkedClaimAllTxIx.map(async (claimAllTx) => {\n        return new Transaction({\n          feePayer: owner,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...claimAllTx);\n      }),\n    );\n  }\n\n  public async setActivationPoint(activationPoint: BN) {\n    const setActivationPointTx = await this.program.methods\n      .setActivationPoint(activationPoint)\n      .accountsPartial({\n        lbPair: this.pubkey,\n        signer: this.lbPair.creator,\n      })\n      .transaction();\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return new Transaction({\n      feePayer: this.lbPair.creator,\n      blockhash,\n      lastValidBlockHeight,\n    }).add(setActivationPointTx);\n  }\n\n  public async setPairStatus(enabled: boolean): Promise<Transaction> {\n    const pairStatus = enabled ? 0 : 1;\n    const tx = await this.program.methods\n      .setPairStatus(pairStatus)\n      .accountsPartial({\n        lbPair: this.pubkey,\n        signer: this.lbPair.creator,\n      })\n      .transaction();\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return new Transaction({\n      feePayer: this.lbPair.creator,\n      blockhash,\n      lastValidBlockHeight,\n    }).add(tx);\n  }\n\n  /**\n   * The function `claimSwapFee` is used to claim swap fees for a specific position owned by a specific owner.\n   * @param\n   *    - `owner`: The public key of the owner of the position.\n   *    - `position`: The public key of the position account.\n   *    - `binRange`: The bin range to claim swap fees for. If not provided, the function claim swap fees for full range.\n   * @returns {Promise<Transaction[]>} Claim swap fee transactions.\n   */\n  public async claimSwapFee({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction[]> {\n    if (isPositionNoFee(position.positionData)) {\n      throw new Error(\"No fee to claim\");\n    }\n\n    const claimFeeTxs = await this.createClaimSwapFeeMethod({\n      owner,\n      position,\n    });\n\n    const claimFeeTxsWithCUIx = await Promise.all(\n      claimFeeTxs.map(async (tx) => {\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          tx.instructions,\n          owner,\n        );\n\n        return [setCUIx, ...tx.instructions];\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return claimFeeTxsWithCUIx.map((ixs) => {\n      return new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n        feePayer: owner,\n      }).add(...ixs);\n    });\n  }\n\n  /**\n   * The `claimAllSwapFee` function to claim swap fees for multiple positions owned by a specific owner.\n   * @param\n   *    - `owner`: The public key of the owner of the positions.\n   *    - `positions`: An array of objects of type `PositionData` that represents the positions to claim swap fees from.\n   * @returns {Promise<Transaction[]>} Array of claim swap fee transactions.\n   */\n  public async claimAllSwapFee({\n    owner,\n    positions,\n  }: {\n    owner: PublicKey;\n    positions: LbPosition[];\n  }): Promise<Transaction[]> {\n    if (positions.every((position) => isPositionNoFee(position.positionData))) {\n      throw new Error(\"No fee to claim\");\n    }\n\n    const claimAllTxs = (\n      await Promise.all(\n        positions\n          .filter(\n            ({ positionData: { feeX, feeY } }) =>\n              !feeX.isZero() || !feeY.isZero(),\n          )\n          .map(async (position) => {\n            return await this.createClaimSwapFeeMethod({\n              owner,\n              position,\n            });\n          }),\n      )\n    ).flat();\n\n    const chunkedClaimAllTx = chunks(claimAllTxs, MAX_CLAIM_ALL_ALLOWED);\n\n    if (chunkedClaimAllTx.length === 0) return [];\n\n    const chunkedClaimAllTxIxs = await Promise.all(\n      chunkedClaimAllTx.map(async (tx) => {\n        const ixs = tx.map((t) => t.instructions).flat();\n\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          ixs,\n          owner,\n        );\n\n        return [setCUIx, ...ixs];\n      }),\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return Promise.all(\n      chunkedClaimAllTxIxs.map(async (claimAllTx) => {\n        return new Transaction({\n          feePayer: owner,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...claimAllTx);\n      }),\n    );\n  }\n\n  /**\n   * The function `claimAllRewardsByPosition` allows a user to claim all rewards for a specific\n   * position.\n   * @param\n   *    - `owner`: The public key of the owner of the position.\n   *    - `position`: The public key of the position account.\n   * @returns {Promise<Transaction[]>} Array of claim reward transactions.\n   */\n  public async claimAllRewardsByPosition({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction[]> {\n    if (\n      isPositionNoFee(position.positionData) &&\n      isPositionNoReward(position.positionData)\n    ) {\n      throw new Error(\"No fee/reward to claim\");\n    }\n\n    const claimAllSwapFeeTxs = await this.createClaimSwapFeeMethod({\n      owner,\n      position,\n    });\n\n    const claimAllLMTxs = await this.createClaimBuildMethod({\n      owner,\n      position,\n    });\n\n    const claimAllTxs = chunks(\n      [...claimAllSwapFeeTxs, ...claimAllLMTxs],\n      MAX_CLAIM_ALL_ALLOWED,\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return Promise.all(\n      claimAllTxs.map(async (txs) => {\n        const instructions = txs.flatMap((tx) => tx.instructions);\n\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          instructions,\n          owner,\n        );\n\n        const transaction = new Transaction({\n          feePayer: owner,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(setCUIx, ...instructions);\n\n        return transaction;\n      }),\n    );\n  }\n\n  /**\n   * The `seedLiquidity` function create multiple grouped instructions. The grouped instructions will be [init ata + send lamport for token provde], [initialize bin array + initialize position instructions] and [deposit instruction]. Each grouped instructions can be executed parallelly.\n   * @param\n   *    - `owner`: The public key of the positions owner.\n   *    - `seedAmount`: Lamport amount to be seeded to the pool.\n   *    - `minPrice`: Start price in UI format\n   *    - `maxPrice`: End price in UI format\n   *    - `base`: Base key\n   *    - `txPayer`: Account rental fee payer\n   *    - `feeOwner`: Fee owner key. Default to position owner\n   *    - `operator`: Operator key\n   *    - `lockReleasePoint`: Timelock. Point (slot/timestamp) the position can withdraw the liquidity,\n   *    - `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.\n   * @returns {Promise<SeedLiquidityResponse>}\n   */\n  public async seedLiquidity(\n    owner: PublicKey,\n    seedAmount: BN,\n    curvature: number,\n    minPrice: number,\n    maxPrice: number,\n    base: PublicKey,\n    payer: PublicKey,\n    feeOwner: PublicKey,\n    operator: PublicKey,\n    lockReleasePoint: BN,\n    shouldSeedPositionOwner: boolean = false,\n  ): Promise<SeedLiquidityResponse> {\n    let tokenOwnerProveAssociatedTokenAccountLamports = new BN(0);\n    let totalPositionCount = new BN(0);\n    let totalPositionLamports = new BN(0);\n    let totalBinArraysCount = new BN(0);\n    let totalBinArraysLamports = new BN(0);\n    let binArrayBitmapLamports = new BN(0);\n\n    const toLamportMultiplier = new Decimal(\n      10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals),\n    );\n\n    const minPricePerLamport = new Decimal(minPrice).mul(toLamportMultiplier);\n    const maxPricePerLamport = new Decimal(maxPrice).mul(toLamportMultiplier);\n\n    const minBinId = new BN(\n      DLMM.getBinIdFromPrice(minPricePerLamport, this.lbPair.binStep, false),\n    );\n\n    const maxBinId = new BN(\n      DLMM.getBinIdFromPrice(maxPricePerLamport, this.lbPair.binStep, true),\n    );\n\n    if (minBinId.toNumber() < this.lbPair.activeId) {\n      throw new Error(\"minPrice < current pair price\");\n    }\n\n    if (minBinId.toNumber() >= maxBinId.toNumber()) {\n      throw new Error(\"Price range too small\");\n    }\n\n    // Generate amount for each bin\n    const k = 1.0 / curvature;\n\n    const binDepositAmount = generateAmountForBinRange(\n      seedAmount,\n      this.lbPair.binStep,\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n      minBinId,\n      maxBinId,\n      k,\n    );\n\n    const decompressMultiplier = findOptimumDecompressMultiplier(\n      binDepositAmount,\n      new BN(this.tokenX.mint.decimals),\n    );\n\n    let { compressedBinAmount, compressionLoss } = compressBinAmount(\n      binDepositAmount,\n      decompressMultiplier,\n    );\n\n    // Distribute loss after compression back to bins based on bin ratio with total deposited amount\n    let {\n      newCompressedBinAmount: compressedBinDepositAmount,\n      loss: finalLoss,\n    } = distributeAmountToCompressedBinsByRatio(\n      compressedBinAmount,\n      compressionLoss,\n      decompressMultiplier,\n      new BN(2 ** 32 - 1), // u32\n    );\n\n    // This amount will be deposited to the last bin without compression\n    const positionCount = getPositionCount(minBinId, maxBinId.sub(new BN(1)));\n\n    const seederTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      operator,\n      false,\n      this.tokenX.owner,\n    );\n\n    const seederTokenY = getAssociatedTokenAddressSync(\n      this.lbPair.tokenYMint,\n      operator,\n      false,\n      this.tokenY.owner,\n    );\n\n    const ownerTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      owner,\n      false,\n      this.tokenX.owner,\n    );\n\n    const [binArrayBitmapExtension] = deriveBinArrayBitmapExtension(\n      this.pubkey,\n      this.program.programId,\n    );\n\n    const sendPositionOwnerTokenProveIxs = [];\n    const initializeBinArraysAndPositionIxs = [];\n    const addLiquidityIxs = [];\n    const appendedInitBinArrayIx = new Set();\n    let appendedInitBinArrayBitmap = false;\n\n    if (shouldSeedPositionOwner) {\n      const positionOwnerTokenX =\n        await this.program.provider.connection.getAccountInfo(ownerTokenX);\n\n      let requireTokenProve = false;\n\n      if (positionOwnerTokenX) {\n        const ownerTokenXState = unpackAccount(\n          ownerTokenX,\n          positionOwnerTokenX,\n          this.tokenX.owner,\n        );\n\n        requireTokenProve = ownerTokenXState.amount == 0n;\n      } else {\n        requireTokenProve = true;\n      }\n\n      if (requireTokenProve) {\n        if (!positionOwnerTokenX) {\n          tokenOwnerProveAssociatedTokenAccountLamports =\n            tokenOwnerProveAssociatedTokenAccountLamports.add(\n              TOKEN_ACCOUNT_FEE_BN,\n            );\n        }\n\n        const initPositionOwnerTokenX =\n          createAssociatedTokenAccountIdempotentInstruction(\n            payer,\n            ownerTokenX,\n            owner,\n            this.lbPair.tokenXMint,\n            this.tokenX.owner,\n          );\n\n        const proveAmount = calculateTransferFeeIncludedAmount(\n          new BN(1),\n          this.tokenX.mint,\n          this.clock.epoch.toNumber(),\n        ).amount;\n\n        sendPositionOwnerTokenProveIxs.push(initPositionOwnerTokenX);\n\n        const transferIx = createTransferCheckedInstruction(\n          seederTokenX,\n          this.lbPair.tokenXMint,\n          ownerTokenX,\n          operator,\n          BigInt(proveAmount.toString()),\n          this.tokenX.mint.decimals,\n          [],\n          this.tokenX.owner,\n        );\n        transferIx.keys.push(...this.tokenX.transferHookAccountMetas);\n        sendPositionOwnerTokenProveIxs.push(transferIx);\n      }\n    }\n\n    const slices: RemainingAccountsInfoSlice[] = [\n      {\n        accountsType: {\n          transferHookX: {},\n        },\n        length: this.tokenX.transferHookAccountMetas.length,\n      },\n    ];\n    const transferHookAccountMetas = this.tokenX.transferHookAccountMetas;\n\n    for (let i = 0; i < positionCount.toNumber(); i++) {\n      const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new BN(i)));\n      const upperBinId = lowerBinId\n        .add(DEFAULT_BIN_PER_POSITION)\n        .sub(new BN(1));\n\n      const binArrayAccountMetas = getBinArrayAccountMetasCoverage(\n        lowerBinId,\n        upperBinId,\n        this.pubkey,\n        this.program.programId,\n      );\n\n      const binArrayIndexes = getBinArrayIndexesCoverage(\n        lowerBinId,\n        upperBinId,\n      );\n\n      const [positionPda, _bump] = derivePosition(\n        this.pubkey,\n        base,\n        lowerBinId,\n        DEFAULT_BIN_PER_POSITION,\n        this.program.programId,\n      );\n\n      const accounts =\n        await this.program.provider.connection.getMultipleAccountsInfo([\n          ...binArrayAccountMetas.map((acc) => acc.pubkey),\n          positionPda,\n        ]);\n\n      let instructions: TransactionInstruction[] = [];\n\n      const binArrayAccounts = accounts.splice(0, binArrayAccountMetas.length);\n\n      for (let i = 0; i < binArrayAccountMetas.length; i++) {\n        const account = binArrayAccounts[i];\n        const pubkey = binArrayAccountMetas[i].pubkey.toBase58();\n        const index = binArrayIndexes[i];\n\n        if (!account && !appendedInitBinArrayIx.has(pubkey)) {\n          totalBinArraysCount = totalBinArraysCount.add(new BN(1));\n          totalBinArraysLamports = totalBinArraysLamports.add(BIN_ARRAY_FEE_BN);\n\n          instructions.push(\n            await this.program.methods\n              .initializeBinArray(index)\n              .accountsPartial({\n                lbPair: this.pubkey,\n                binArray: pubkey,\n                funder: payer,\n              })\n              .instruction(),\n          );\n        }\n      }\n\n      const positionAccount = accounts.pop();\n      if (!positionAccount) {\n        totalPositionCount = totalPositionCount.add(new BN(1));\n        totalPositionLamports = totalPositionLamports.add(POSITION_FEE_BN);\n\n        instructions.push(\n          await this.program.methods\n            .initializePositionByOperator(\n              lowerBinId.toNumber(),\n              DEFAULT_BIN_PER_POSITION.toNumber(),\n              feeOwner,\n              lockReleasePoint,\n            )\n            .accountsPartial({\n              lbPair: this.pubkey,\n              position: positionPda,\n              base,\n              owner,\n              operator,\n              operatorTokenX: seederTokenX,\n              ownerTokenX,\n              systemProgram: SystemProgram.programId,\n              payer,\n            })\n            .instruction(),\n        );\n      }\n\n      // Initialize bin arrays and initialize position account in 1 tx\n      if (instructions.length > 0) {\n        initializeBinArraysAndPositionIxs.push(instructions);\n        instructions = [];\n      }\n\n      const positionDeposited =\n        positionAccount &&\n        decodeAccount<PositionV2>(\n          this.program,\n          \"positionV2\",\n          positionAccount.data,\n        )\n          .liquidityShares.reduce((total, cur) => total.add(cur), new BN(0))\n          .gt(new BN(0));\n\n      if (!positionDeposited) {\n        let overflowDefaultBinArrayBitmap = false;\n        for (const binArrayIndex of binArrayIndexes) {\n          if (isOverflowDefaultBinArrayBitmap(binArrayIndex)) {\n            if (!this.binArrayBitmapExtension && !appendedInitBinArrayBitmap) {\n              initializeBinArraysAndPositionIxs.push(\n                await this.program.methods\n                  .initializeBinArrayBitmapExtension()\n                  .accountsPartial({\n                    binArrayBitmapExtension,\n                    funder: payer,\n                    lbPair: this.pubkey,\n                  })\n                  .instruction(),\n              );\n\n              appendedInitBinArrayBitmap = true;\n              binArrayBitmapLamports = binArrayBitmapLamports.add(\n                BIN_ARRAY_BITMAP_FEE_BN,\n              );\n            }\n\n            overflowDefaultBinArrayBitmap = true;\n          }\n        }\n\n        const cappedUpperBinId = Math.min(\n          upperBinId.toNumber(),\n          maxBinId.toNumber() - 1,\n        );\n\n        const bins: CompressedBinDepositAmounts = [];\n\n        for (let i = lowerBinId.toNumber(); i <= cappedUpperBinId; i++) {\n          bins.push({\n            binId: i,\n            amount: compressedBinDepositAmount.get(i).toNumber(),\n          });\n        }\n\n        instructions.push(\n          await this.program.methods\n            .addLiquidityOneSidePrecise2(\n              {\n                bins,\n                decompressMultiplier,\n                maxAmount: U64_MAX,\n              },\n              {\n                slices,\n              },\n            )\n            .accountsPartial({\n              position: positionPda,\n              lbPair: this.pubkey,\n              binArrayBitmapExtension: overflowDefaultBinArrayBitmap\n                ? binArrayBitmapExtension\n                : this.program.programId,\n              userToken: seederTokenX,\n              reserve: this.lbPair.reserveX,\n              tokenMint: this.lbPair.tokenXMint,\n              sender: operator,\n              tokenProgram: this.tokenX.owner,\n            })\n            .remainingAccounts([\n              ...transferHookAccountMetas,\n              ...binArrayAccountMetas,\n            ])\n            .instruction(),\n        );\n\n        // Last position\n        if (i + 1 >= positionCount.toNumber() && !finalLoss.isZero()) {\n          const finalLossIncludesTransferFee =\n            calculateTransferFeeIncludedAmount(\n              finalLoss,\n              this.tokenX.mint,\n              this.clock.epoch.toNumber(),\n            ).amount;\n\n          instructions.push(\n            await this.program.methods\n              .addLiquidity2(\n                {\n                  amountX: finalLossIncludesTransferFee,\n                  amountY: new BN(0),\n                  binLiquidityDist: [\n                    {\n                      binId: cappedUpperBinId,\n                      distributionX: BASIS_POINT_MAX,\n                      distributionY: BASIS_POINT_MAX,\n                    },\n                  ],\n                },\n                {\n                  slices,\n                },\n              )\n              .accountsPartial({\n                position: positionPda,\n                lbPair: this.pubkey,\n                binArrayBitmapExtension: overflowDefaultBinArrayBitmap\n                  ? binArrayBitmapExtension\n                  : this.program.programId,\n                userTokenX: seederTokenX,\n                userTokenY: seederTokenY,\n                reserveX: this.lbPair.reserveX,\n                reserveY: this.lbPair.reserveY,\n                tokenXMint: this.lbPair.tokenXMint,\n                tokenYMint: this.lbPair.tokenYMint,\n                tokenXProgram: this.tokenX.owner,\n                tokenYProgram: this.tokenY.owner,\n                sender: operator,\n              })\n              .remainingAccounts([\n                ...transferHookAccountMetas,\n                ...getBinArrayAccountMetasCoverage(\n                  new BN(cappedUpperBinId),\n                  new BN(cappedUpperBinId),\n                  this.pubkey,\n                  this.program.programId,\n                ),\n              ])\n              .instruction(),\n          );\n        }\n\n        addLiquidityIxs.push([\n          ComputeBudgetProgram.setComputeUnitLimit({\n            units: DEFAULT_ADD_LIQUIDITY_CU,\n          }),\n          ...instructions,\n        ]);\n      }\n    }\n\n    return {\n      sendPositionOwnerTokenProveIxs,\n      initializeBinArraysAndPositionIxs,\n      addLiquidityIxs,\n      costBreakdown: {\n        tokenOwnerProveAssociatedTokenAccountLamports,\n        totalBinArraysCount,\n        totalBinArraysLamports,\n        totalPositionCount,\n        totalPositionLamports,\n        binArrayBitmapLamports,\n      },\n    };\n  }\n\n  /**\n   * The `seedLiquiditySingleBin` function seed liquidity into a single bin.\n   * @param\n   *    - `payer`: The public key of the tx payer.\n   *    - `base`: Base key\n   *    - `seedAmount`: Token X lamport amount to be seeded to the pool.\n   *    - `price`: TokenX/TokenY Price in UI format\n   *    - `roundingUp`: Whether to round up the price\n   *    - `positionOwner`: The owner of the position\n   *    - `feeOwner`: Position fee owner\n   *    - `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.\n   *    - `lockReleasePoint`: The lock release point of the position.\n   *    - `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.\n   *\n   * The returned instructions need to be executed sequentially if it was separated into multiple transactions.\n   * @returns {Promise<SeedLiquiditySingleBinResponse>}\n   */\n  public async seedLiquiditySingleBin(\n    payer: PublicKey,\n    base: PublicKey,\n    seedAmount: BN,\n    price: number,\n    roundingUp: boolean,\n    positionOwner: PublicKey,\n    feeOwner: PublicKey,\n    operator: PublicKey,\n    lockReleasePoint: BN,\n    shouldSeedPositionOwner: boolean = false,\n  ): Promise<SeedLiquiditySingleBinResponse> {\n    let tokenOwnerProveAssociatedTokenAccountLamports = new BN(0);\n    let totalPositionCount = new BN(0);\n    let totalPositionLamports = new BN(0);\n    let totalBinArraysCount = new BN(0);\n    let totalBinArraysLamports = new BN(0);\n    let binArrayBitmapLamports = new BN(0);\n\n    const pricePerLamport = DLMM.getPricePerLamport(\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n      price,\n    );\n    const binIdNumber = DLMM.getBinIdFromPrice(\n      pricePerLamport,\n      this.lbPair.binStep,\n      !roundingUp,\n    );\n\n    const binId = new BN(binIdNumber);\n\n    const [positionPda] = derivePosition(\n      this.pubkey,\n      base,\n      binId,\n      new BN(1),\n      this.program.programId,\n    );\n\n    const binArrayIndex = binIdToBinArrayIndex(binId);\n    const [binArrayKey] = deriveBinArray(\n      this.pubkey,\n      binArrayIndex,\n      this.program.programId,\n    );\n\n    const preInstructions = [];\n\n    const [\n      { ataPubKey: userTokenX, ix: createPayerTokenXIx },\n      { ataPubKey: userTokenY, ix: createPayerTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        operator,\n        this.tokenX.owner,\n        payer,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        operator,\n        this.tokenY.owner,\n        payer,\n      ),\n    ]);\n\n    // create userTokenX and userTokenY accounts\n    createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);\n    createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);\n\n    let [binArrayBitmapExtension] = deriveBinArrayBitmapExtension(\n      this.pubkey,\n      this.program.programId,\n    );\n\n    const [binArrayAccount, positionAccount, bitmapExtensionAccount] =\n      await this.program.provider.connection.getMultipleAccountsInfo([\n        binArrayKey,\n        positionPda,\n        binArrayBitmapExtension,\n      ]);\n\n    if (isOverflowDefaultBinArrayBitmap(binArrayIndex)) {\n      if (!bitmapExtensionAccount) {\n        preInstructions.push(\n          await this.program.methods\n            .initializeBinArrayBitmapExtension()\n            .accountsPartial({\n              binArrayBitmapExtension,\n              funder: payer,\n              lbPair: this.pubkey,\n            })\n            .instruction(),\n        );\n\n        binArrayBitmapLamports = binArrayBitmapLamports.add(\n          BIN_ARRAY_BITMAP_FEE_BN,\n        );\n      }\n    } else {\n      binArrayBitmapExtension = this.program.programId;\n    }\n\n    const operatorTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      operator,\n      true,\n      this.tokenX.owner,\n    );\n    const positionOwnerTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      positionOwner,\n      true,\n      this.tokenX.owner,\n    );\n\n    if (shouldSeedPositionOwner) {\n      const positionOwnerTokenXAccount =\n        await this.program.provider.connection.getAccountInfo(\n          positionOwnerTokenX,\n        );\n\n      const proveAmount = calculateTransferFeeIncludedAmount(\n        new BN(1),\n        this.tokenX.mint,\n        this.clock.epoch.toNumber(),\n      ).amount;\n\n      if (positionOwnerTokenXAccount) {\n        const account = unpackAccount(\n          positionOwnerTokenX,\n          positionOwnerTokenXAccount,\n          this.tokenX.owner,\n        );\n\n        if (account.amount == BigInt(0)) {\n          // send 1 lamport to position owner token X to prove ownership\n          const transferIx = createTransferCheckedInstruction(\n            operatorTokenX,\n            this.lbPair.tokenXMint,\n            positionOwnerTokenX,\n            operator,\n            BigInt(proveAmount.toString()),\n            this.tokenX.mint.decimals,\n            [],\n            this.tokenX.owner,\n          );\n          transferIx.keys.push(...this.tokenX.transferHookAccountMetas);\n          preInstructions.push(transferIx);\n        }\n      } else {\n        const createPositionOwnerTokenXIx =\n          createAssociatedTokenAccountIdempotentInstruction(\n            payer,\n            positionOwnerTokenX,\n            positionOwner,\n            this.lbPair.tokenXMint,\n            this.tokenX.owner,\n          );\n        preInstructions.push(createPositionOwnerTokenXIx);\n\n        // send 1 lamport to position owner token X to prove ownership\n        const transferIx = createTransferCheckedInstruction(\n          operatorTokenX,\n          this.lbPair.tokenXMint,\n          positionOwnerTokenX,\n          operator,\n          BigInt(proveAmount.toString()),\n          this.tokenX.mint.decimals,\n          [],\n          this.tokenX.owner,\n        );\n        transferIx.keys.push(...this.tokenX.transferHookAccountMetas);\n        preInstructions.push(transferIx);\n\n        tokenOwnerProveAssociatedTokenAccountLamports =\n          tokenOwnerProveAssociatedTokenAccountLamports.add(\n            TOKEN_ACCOUNT_FEE_BN,\n          );\n      }\n    }\n\n    if (!binArrayAccount) {\n      preInstructions.push(\n        await this.program.methods\n          .initializeBinArray(binArrayIndex)\n          .accountsPartial({\n            binArray: binArrayKey,\n            funder: payer,\n            lbPair: this.pubkey,\n          })\n          .instruction(),\n      );\n\n      totalBinArraysCount = totalBinArraysCount.add(new BN(1));\n      totalBinArraysLamports = totalBinArraysLamports.add(BIN_ARRAY_FEE_BN);\n    }\n\n    if (!positionAccount) {\n      preInstructions.push(\n        await this.program.methods\n          .initializePositionByOperator(\n            binId.toNumber(),\n            1,\n            feeOwner,\n            lockReleasePoint,\n          )\n          .accountsPartial({\n            payer,\n            base,\n            position: positionPda,\n            lbPair: this.pubkey,\n            owner: positionOwner,\n            operator,\n            operatorTokenX,\n            ownerTokenX: positionOwnerTokenX,\n          })\n          .instruction(),\n      );\n\n      totalPositionCount = totalPositionCount.add(new BN(1));\n      totalPositionLamports = totalPositionLamports.add(POSITION_FEE_BN);\n    }\n\n    const slices: RemainingAccountsInfoSlice[] = [\n      {\n        accountsType: {\n          transferHookX: {},\n        },\n        length: this.tokenX.transferHookAccountMetas.length,\n      },\n    ];\n    const transferHookAccountMetas = this.tokenX.transferHookAccountMetas;\n\n    const binLiquidityDist: BinLiquidityDistribution = {\n      binId: binIdNumber,\n      distributionX: BASIS_POINT_MAX,\n      distributionY: BASIS_POINT_MAX,\n    };\n\n    const seedAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(\n      seedAmount,\n      this.tokenX.mint,\n      this.clock.epoch.toNumber(),\n    ).amount;\n\n    const addLiquidityParams: LiquidityParameter = {\n      amountX: seedAmountIncludeTransferFee,\n      amountY: new BN(0),\n      binLiquidityDist: [binLiquidityDist],\n    };\n\n    const depositLiquidityIx = await this.program.methods\n      .addLiquidity2(addLiquidityParams, {\n        slices,\n      })\n      .accountsPartial({\n        position: positionPda,\n        lbPair: this.pubkey,\n        binArrayBitmapExtension,\n        userTokenX,\n        userTokenY,\n        reserveX: this.lbPair.reserveX,\n        reserveY: this.lbPair.reserveY,\n        tokenXMint: this.lbPair.tokenXMint,\n        tokenYMint: this.lbPair.tokenYMint,\n        sender: operator,\n        tokenXProgram: this.tokenX.owner,\n        tokenYProgram: this.tokenY.owner,\n      })\n      .remainingAccounts([\n        ...transferHookAccountMetas,\n        {\n          pubkey: binArrayKey,\n          isSigner: false,\n          isWritable: true,\n        },\n      ])\n      .instruction();\n\n    const instructions = [...preInstructions, depositLiquidityIx];\n    return {\n      instructions,\n      costBreakdown: {\n        tokenOwnerProveAssociatedTokenAccountLamports,\n        totalBinArraysCount,\n        totalBinArraysLamports,\n        totalPositionCount,\n        totalPositionLamports,\n        binArrayBitmapLamports,\n      },\n    };\n  }\n\n  /**\n   * Initializes bin arrays for the given bin array indexes if it wasn't initialized.\n   *\n   * @param {BN[]} binArrayIndexes - An array of bin array indexes to initialize.\n   * @param {PublicKey} funder - The public key of the funder.\n   * @return {Promise<TransactionInstruction[]>} An array of transaction instructions to initialize the bin arrays.\n   */\n  public async initializeBinArrays(binArrayIndexes: BN[], funder: PublicKey) {\n    const ixs: TransactionInstruction[] = [];\n\n    for (const idx of binArrayIndexes) {\n      const [binArray] = deriveBinArray(\n        this.pubkey,\n        idx,\n        this.program.programId,\n      );\n\n      const binArrayAccount =\n        await this.program.provider.connection.getAccountInfo(binArray);\n\n      if (binArrayAccount === null) {\n        const initBinArrayIx = await this.program.methods\n          .initializeBinArray(idx)\n          .accountsPartial({\n            binArray,\n            funder,\n            lbPair: this.pubkey,\n          })\n          .instruction();\n        ixs.push(initBinArrayIx);\n      }\n    }\n\n    if (ixs.length > 0) {\n      const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n        this.program.provider.connection,\n        ixs,\n        funder,\n      );\n\n      ixs.unshift(setCUIx);\n    }\n\n    return ixs;\n  }\n\n  /**\n   *\n   * @param\n   *    - `lowerBinId`: Lower bin ID of the position. This represent the lowest price of the position\n   *    - `positionWidth`: Width of the position. This will decide the upper bin id of the position, which represents the highest price of the position. UpperBinId = lowerBinId + positionWidth\n   *    - `owner`: Owner of the position.\n   *    - `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.\n   *    - `base`: Base key\n   *    - `feeOwner`: Owner of the fees earned by the position.\n   *    - `payer`: Payer for the position account rental.\n   *    - `lockReleasePoint`: The lock release point of the position.\n   * @returns\n   */\n  public async initializePositionByOperator({\n    lowerBinId,\n    positionWidth,\n    owner,\n    feeOwner,\n    base,\n    operator,\n    payer,\n    lockReleasePoint,\n  }: {\n    lowerBinId: BN;\n    positionWidth: BN;\n    owner: PublicKey;\n    feeOwner: PublicKey;\n    operator: PublicKey;\n    payer: PublicKey;\n    base: PublicKey;\n    lockReleasePoint: BN;\n  }): Promise<Transaction> {\n    const [positionPda, _bump] = derivePosition(\n      this.pubkey,\n      base,\n      lowerBinId,\n      positionWidth,\n      this.program.programId,\n    );\n\n    const operatorTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      operator,\n      true,\n      this.tokenX.owner,\n    );\n\n    const ownerTokenX = getAssociatedTokenAddressSync(\n      this.lbPair.tokenXMint,\n      owner,\n      true,\n      this.tokenY.owner,\n    );\n\n    const initializePositionByOperatorTx = await this.program.methods\n      .initializePositionByOperator(\n        lowerBinId.toNumber(),\n        DEFAULT_BIN_PER_POSITION.toNumber(),\n        feeOwner,\n        lockReleasePoint,\n      )\n      .accountsPartial({\n        lbPair: this.pubkey,\n        position: positionPda,\n        base,\n        operator,\n        owner,\n        ownerTokenX,\n        operatorTokenX,\n        payer,\n      })\n      .transaction();\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      feePayer: operator,\n      blockhash,\n      lastValidBlockHeight,\n    }).add(initializePositionByOperatorTx);\n  }\n\n  /**\n   * The `claimAllRewards` function to claim swap fees and LM rewards for multiple positions owned by a specific owner.\n   * @param\n   *    - `owner`: The public key of the owner of the positions.\n   *    - `positions`: An array of objects of type `PositionData` that represents the positions to claim swap fees and LM rewards from.\n   * @returns {Promise<Transaction[]>} Array of claim swap fee and LM reward transactions.\n   */\n  public async claimAllRewards({\n    owner,\n    positions,\n  }: {\n    owner: PublicKey;\n    positions: LbPosition[];\n  }): Promise<Transaction[]> {\n    // Filter only position with fees and/or rewards\n    positions = positions.filter(\n      ({ positionData: { feeX, feeY, rewardOne, rewardTwo } }) =>\n        !feeX.isZero() ||\n        !feeY.isZero() ||\n        !rewardOne.isZero() ||\n        !rewardTwo.isZero(),\n    );\n\n    const claimAllSwapFeeTxs = (\n      await Promise.all(\n        positions.map(async (position) => {\n          return await this.createClaimSwapFeeMethod({\n            owner,\n            position,\n          });\n        }),\n      )\n    ).flat();\n\n    const claimAllLMTxs = (\n      await Promise.all(\n        positions.map(async (position) => {\n          return await this.createClaimBuildMethod({\n            owner,\n            position,\n          });\n        }),\n      )\n    ).flat();\n\n    const transactions = chunks(\n      [...claimAllSwapFeeTxs, ...claimAllLMTxs],\n      MAX_CLAIM_ALL_ALLOWED,\n    );\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n    return Promise.all(\n      transactions.map(async (txs) => {\n        const instructions = txs.flatMap((i) => i.instructions);\n\n        const setCUIx = await getEstimatedComputeUnitIxWithBuffer(\n          this.program.provider.connection,\n          instructions,\n          owner,\n        );\n\n        const transaction = new Transaction({\n          feePayer: owner,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(setCUIx, ...instructions);\n\n        return transaction;\n      }),\n    );\n  }\n\n  public canSyncWithMarketPrice(marketPrice: number, activeBinId: number) {\n    const marketPriceBinId = this.getBinIdFromPrice(\n      Number(\n        DLMM.getPricePerLamport(\n          this.tokenX.mint.decimals,\n          this.tokenY.mint.decimals,\n          marketPrice,\n        ),\n      ),\n      false,\n    );\n\n    const marketPriceBinArrayIndex = binIdToBinArrayIndex(\n      new BN(marketPriceBinId),\n    );\n\n    const swapForY = marketPriceBinId < activeBinId;\n    const toBinArrayIndex = findNextBinArrayIndexWithLiquidity(\n      swapForY,\n      new BN(activeBinId),\n      this.lbPair,\n      this.binArrayBitmapExtension?.account ?? null,\n    );\n    if (toBinArrayIndex === null) return true;\n\n    return swapForY\n      ? marketPriceBinArrayIndex.gt(toBinArrayIndex)\n      : marketPriceBinArrayIndex.lt(toBinArrayIndex);\n  }\n\n  /**\n   * The `syncWithMarketPrice` function is used to sync the liquidity pool with the market price.\n   * @param\n   *    - `marketPrice`: The market price to sync with.\n   *    - `owner`: The public key of the owner of the liquidity pool.\n   * @returns {Promise<Transaction>}\n   */\n  public async syncWithMarketPrice(marketPrice: number, owner: PublicKey) {\n    const marketPriceBinId = this.getBinIdFromPrice(\n      Number(\n        DLMM.getPricePerLamport(\n          this.tokenX.mint.decimals,\n          this.tokenY.mint.decimals,\n          marketPrice,\n        ),\n      ),\n      false,\n    );\n    const activeBin = await this.getActiveBin();\n    const activeBinId = activeBin.binId;\n\n    if (!this.canSyncWithMarketPrice(marketPrice, activeBinId)) {\n      throw new Error(\n        \"Unable to sync with market price due to bin with liquidity between current and market price bin\",\n      );\n    }\n\n    const fromBinArrayIndex = binIdToBinArrayIndex(new BN(activeBinId));\n\n    const swapForY = marketPriceBinId < activeBinId;\n    const toBinArrayIndex = findNextBinArrayIndexWithLiquidity(\n      swapForY,\n      new BN(activeBinId),\n      this.lbPair,\n      this.binArrayBitmapExtension?.account ?? null,\n    );\n    const marketPriceBinArrayIndex = binIdToBinArrayIndex(\n      new BN(marketPriceBinId),\n    );\n    const accountsToFetch = [];\n    const binArrayBitMapExtensionPubkey = isOverflowDefaultBinArrayBitmap(\n      new BN(marketPriceBinArrayIndex),\n    )\n      ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0]\n      : null;\n\n    binArrayBitMapExtensionPubkey &&\n      accountsToFetch.push(binArrayBitMapExtensionPubkey);\n    const [fromBinArrayPubkey] = deriveBinArray(\n      this.pubkey,\n      fromBinArrayIndex,\n      this.program.programId,\n    );\n    accountsToFetch.push(fromBinArrayPubkey);\n    const toBinArrayPubkey = (() => {\n      if (!toBinArrayIndex) return null;\n\n      const [toBinArrayPubkey] = deriveBinArray(\n        this.pubkey,\n        toBinArrayIndex,\n        this.program.programId,\n      );\n\n      accountsToFetch.push(toBinArrayPubkey);\n\n      return toBinArrayPubkey;\n    })();\n\n    const binArrayAccounts =\n      await this.program.provider.connection.getMultipleAccountsInfo(\n        accountsToFetch,\n      );\n\n    const preInstructions: TransactionInstruction[] = [];\n    let fromBinArray: PublicKey | null = null;\n    let toBinArray: PublicKey | null = null;\n    let binArrayBitmapExtension: PublicKey | null = null;\n    if (binArrayBitMapExtensionPubkey) {\n      binArrayBitmapExtension = binArrayBitMapExtensionPubkey;\n      if (!binArrayAccounts?.[0]) {\n        const initializeBitmapExtensionIx = await this.program.methods\n          .initializeBinArrayBitmapExtension()\n          .accountsPartial({\n            binArrayBitmapExtension: binArrayBitMapExtensionPubkey,\n            funder: owner,\n            lbPair: this.pubkey,\n          })\n          .instruction();\n        preInstructions.push(initializeBitmapExtensionIx);\n      }\n    }\n    if (!!binArrayAccounts?.[1]) {\n      fromBinArray = fromBinArrayPubkey;\n    }\n\n    if (!!binArrayAccounts?.[2] && !!toBinArrayIndex) {\n      toBinArray = toBinArrayPubkey;\n    }\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    const syncWithMarketPriceTx = await this.program.methods\n      .goToABin(marketPriceBinId)\n      .accountsPartial({\n        lbPair: this.pubkey,\n        binArrayBitmapExtension,\n        fromBinArray,\n        toBinArray,\n      })\n      .preInstructions(preInstructions)\n      .transaction();\n\n    return new Transaction({\n      feePayer: owner,\n      blockhash,\n      lastValidBlockHeight,\n    }).add(syncWithMarketPriceTx);\n  }\n\n  public async getMaxPriceInBinArrays(\n    binArrayAccounts: BinArrayAccount[],\n  ): Promise<string> {\n    // Don't mutate\n    const sortedBinArrays = [...binArrayAccounts].sort(\n      ({ account: { index: indexA } }, { account: { index: indexB } }) =>\n        indexA.toNumber() - indexB.toNumber(),\n    );\n    let count = sortedBinArrays.length - 1;\n    let binPriceWithLastLiquidity;\n    while (count >= 0) {\n      const binArray = sortedBinArrays[count];\n      if (binArray) {\n        const bins = binArray.account.bins;\n        if (bins.every(({ amountX }) => amountX.isZero())) {\n          count--;\n        } else {\n          const lastBinWithLiquidityIndex = bins.findLastIndex(\n            ({ amountX }) => !amountX.isZero(),\n          );\n          binPriceWithLastLiquidity =\n            bins[lastBinWithLiquidityIndex].price.toString();\n          count = -1;\n        }\n      }\n    }\n\n    return this.fromPricePerLamport(\n      Number(binPriceWithLastLiquidity) / (2 ** 64 - 1),\n    );\n  }\n\n  /**\n   *\n   * @param swapInitiator Address of the swap initiator\n   * @returns\n   */\n  public isSwapDisabled(swapInitiator: PublicKey) {\n    if (this.lbPair.status == PairStatus.Disabled) {\n      return true;\n    }\n\n    if (\n      this.lbPair.pairType == PairType.Permissioned ||\n      this.lbPair.pairType == PairType.CustomizablePermissionless\n    ) {\n      const currentPoint =\n        this.lbPair.activationType == ActivationType.Slot\n          ? this.clock.slot\n          : this.clock.unixTimestamp;\n\n      const preActivationSwapPoint = this.lbPair.activationPoint.sub(\n        this.lbPair.preActivationDuration,\n      );\n\n      const activationPoint =\n        !this.lbPair.preActivationSwapAddress.equals(PublicKey.default) &&\n        this.lbPair.preActivationSwapAddress.equals(swapInitiator)\n          ? preActivationSwapPoint\n          : this.lbPair.activationPoint;\n\n      if (currentPoint < activationPoint) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  /**\n   * Decrease the length of a position. The segment of the position to be decreased must be empty.\n   *\n   * @param position The public key of the position to decrease.\n   * @param side The side of the position to decrease.\n   * @param length The amount of length to decrease.\n   * @param allowParallelExecution If true, the instructions will be grouped to allow parallel execution. Otherwise, the instructions will be executed sequentially.\n   * @returns An array of transactions if allowParallelExecution is true. Otherwise, an empty array.\n   */\n  public async decreasePositionLength(\n    position: PublicKey,\n    side: ResizeSide,\n    length: BN,\n    allowParallelExecution = true,\n  ) {\n    const positionAccount =\n      await this.program.provider.connection.getAccountInfo(position);\n\n    const positionState = wrapPosition(this.program, position, positionAccount);\n\n    const newWidth = positionState.width().sub(length);\n\n    // 1. Cap if it exceeds the min position length\n    if (newWidth.lte(new BN(0))) {\n      // Position must have at least one bin\n      length = length.sub(newWidth.abs()).subn(1);\n    }\n\n    const groupedIxs: TransactionInstruction[][] = [];\n    const promises = [];\n\n    // 2. Split into multiple decrease position length ix to bypass stack size limit\n    for (let i = length.toNumber(); i > 0; i -= MAX_RESIZE_LENGTH.toNumber()) {\n      const lengthToReduce = Math.min(i, MAX_RESIZE_LENGTH.toNumber());\n\n      const setCuIx = ComputeBudgetProgram.setComputeUnitLimit({\n        units: getDefaultExtendPositionCU(side),\n      });\n\n      const ixPromise = this.program.methods\n        .decreasePositionLength(lengthToReduce, Number(side))\n        .accountsPartial({\n          position,\n          owner: positionState.owner(),\n          rentReceiver: positionState.owner(),\n        })\n        .instruction()\n        .then((decreasePositionLengthIx) => {\n          if (allowParallelExecution) {\n            // Trick to make each decrease position length transaction to be unique to allow parallel execution\n            decreasePositionLengthIx.keys.push({\n              isSigner: false,\n              isWritable: false,\n              pubkey: PublicKey.unique(),\n            });\n          }\n          const ixs = [setCuIx, decreasePositionLengthIx];\n          groupedIxs.push(ixs);\n        });\n\n      promises.push(ixPromise);\n    }\n\n    await Promise.all(promises);\n\n    if (groupedIxs.length > 0) {\n      const { blockhash, lastValidBlockHeight } =\n        await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n      return groupedIxs.map((ixs) => {\n        return new Transaction({\n          feePayer: positionState.owner(),\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...ixs);\n      });\n    }\n  }\n\n  /**\n   * Expand the position bin range to the left or right (lower or upper).\n   *\n   * @param position The address of the position to increase the length of.\n   * @param side The side of the position to increase the length of. Must be either\n   *             ResizeSide.Lower or ResizeSide.Upper.\n   * @param length The number of bins to increase the length of. Position length after increase must be <= 1400.\n   * @param funder The address to account rental and transaction fee.\n   * @param allowParallelExecution Whether to allow parallel execution of the transaction.\n   * @returns The transaction to execute this instruction.\n   */\n  public async increasePositionLength(\n    position: PublicKey,\n    side: ResizeSide,\n    length: BN,\n    funder: PublicKey,\n    allowParallelExecution = true,\n  ) {\n    const positionAccount =\n      await this.program.provider.connection.getAccountInfo(position);\n\n    const positionState = wrapPosition(this.program, position, positionAccount);\n\n    const newWidth = positionState.width().add(length);\n\n    // 1. Cap if it exceeds the max position length\n    if (newWidth.gt(POSITION_MAX_LENGTH)) {\n      length = newWidth.sub(POSITION_MAX_LENGTH);\n    }\n\n    const groupedIxs = await this.increasePositionLengthIxs(\n      position,\n      side,\n      length,\n      funder,\n      positionState.owner(),\n      true,\n      allowParallelExecution,\n    );\n\n    if (groupedIxs.length > 0) {\n      const { blockhash, lastValidBlockHeight } =\n        await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n\n      return groupedIxs.map((ixs) => {\n        return new Transaction({\n          feePayer: funder,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...ixs);\n      });\n    }\n  }\n\n  public async simulateRebalancePositionWithBalancedStrategy(\n    positionAddress: PublicKey,\n    positionData: PositionData,\n    strategy: StrategyType,\n    topUpAmountX: BN,\n    topUpAmountY: BN,\n    xWithdrawBps: BN,\n    yWithdrawBps: BN,\n  ) {\n    const rebalancePosition = await RebalancePosition.create({\n      program: this.program,\n      positionAddress,\n      positionData,\n      shouldClaimFee: true,\n      shouldClaimReward: true,\n      pairAddress: this.pubkey,\n    });\n\n    const rebalanceStrategyBuilder = new BalancedStrategyBuilder(\n      new BN(rebalancePosition.lbPair.activeId),\n      new BN(rebalancePosition.lbPair.binStep),\n      positionData,\n      topUpAmountX,\n      topUpAmountY,\n      xWithdrawBps,\n      yWithdrawBps,\n      strategy,\n    );\n\n    return this.simulateRebalancePositionWithStrategy(\n      rebalancePosition,\n      rebalanceStrategyBuilder,\n    );\n  }\n\n  private async simulateRebalancePositionWithStrategy(\n    rebalancePosition: RebalancePosition,\n    rebalanceStrategy: RebalanceStrategyBuilder,\n  ): Promise<\n    RebalancePositionResponse & RebalancePositionBinArrayRentalCostQuote\n  > {\n    const { deposits, withdraws } =\n      rebalanceStrategy.buildRebalanceStrategyParameters();\n\n    const simulationResult = await rebalancePosition.simulateRebalance(\n      this.program.provider.connection,\n      new BN(this.lbPair.binStep),\n      new BN(this.tokenX.mint.decimals),\n      new BN(this.tokenY.mint.decimals),\n      withdraws,\n      deposits,\n    );\n\n    const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(\n      simulationResult.depositParams,\n      simulationResult.withdrawParams,\n      new BN(rebalancePosition.lbPair.activeId),\n    );\n\n    return {\n      rebalancePosition,\n      simulationResult,\n      ...binArrayQuoteResult,\n    };\n  }\n\n  private async quoteBinArrayAccountsRentalCost(\n    deposits: RebalanceAddLiquidityParam[],\n    withdraws: RebalanceRemoveLiquidityParam[],\n    activeId: BN,\n  ): Promise<{\n    binArrayExistence: Set<string>;\n    binArrayCount: number;\n    binArrayCost: number;\n    bitmapExtensionCost: number;\n  }> {\n    const { binArrayBitmap, binArrayIndexes } =\n      getRebalanceBinArrayIndexesAndBitmapCoverage(\n        deposits,\n        withdraws,\n        activeId.toNumber(),\n        this.pubkey,\n        this.program.programId,\n      );\n\n    const binArrayPublicKeys = binArrayIndexes.map((index) => {\n      const [binArrayPubkey] = deriveBinArray(\n        this.pubkey,\n        index,\n        this.program.programId,\n      );\n      return binArrayPubkey;\n    });\n\n    const accountPublicKeys = [...binArrayPublicKeys];\n    if (!binArrayBitmap.equals(PublicKey.default)) {\n      accountPublicKeys.push(binArrayBitmap);\n    }\n\n    const accounts = await chunkedGetMultipleAccountInfos(\n      this.program.provider.connection,\n      binArrayPublicKeys,\n    );\n\n    const binArrayAccounts = accounts.splice(0, binArrayPublicKeys.length);\n\n    let binArrayCount = 0;\n    let bitmapExtensionCost = 0;\n\n    const binArraySet = new Set<string>();\n\n    for (let i = 0; i < binArrayAccounts.length; i++) {\n      const binArrayAccount = binArrayAccounts[i];\n      const binArrayPubkey = binArrayPublicKeys[i];\n      if (!binArrayAccount) {\n        binArrayCount++;\n      } else {\n        binArraySet.add(binArrayPubkey.toBase58());\n      }\n    }\n\n    if (!binArrayBitmap.equals(PublicKey.default)) {\n      const bitmapAccount = accounts.pop();\n      if (!bitmapAccount) {\n        bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;\n      }\n    }\n\n    return {\n      binArrayCost: binArrayCount * BIN_ARRAY_FEE,\n      binArrayCount,\n      binArrayExistence: binArraySet,\n      bitmapExtensionCost,\n    };\n  }\n\n  /**\n   * Simulates a rebalance operation on a position without actually executing it. It's recommended to use simulateRebalancePositionWithXStrategy instead unless you know what you're doing.\n   *\n   * @param positionAddress The address of the position to simulate rebalancing.\n   * @param positionData The PositionData object associated with the position.\n   * @param shouldClaimFee True if the fee should be claimed during rebalancing.\n   * @param shouldClaimReward True if the reward should be claimed during rebalancing.\n   * @param deposits An array of RebalanceWithDeposit objects representing the deposits to simulate.\n   * @param withdraws An array of RebalanceWithWithdraw objects representing the withdraws to simulate.\n   */\n  public async simulateRebalancePosition(\n    positionAddress: PublicKey,\n    positionData: PositionData,\n    shouldClaimFee: boolean,\n    shouldClaimReward: boolean,\n    deposits: RebalanceWithDeposit[],\n    withdraws: RebalanceWithWithdraw[],\n  ): Promise<\n    RebalancePositionResponse & RebalancePositionBinArrayRentalCostQuote\n  > {\n    const rebalancePosition = await RebalancePosition.create({\n      program: this.program,\n      positionAddress,\n      positionData,\n      shouldClaimFee,\n      shouldClaimReward,\n      pairAddress: this.pubkey,\n    });\n\n    const simulationResult = await rebalancePosition.simulateRebalance(\n      this.program.provider.connection,\n      new BN(this.lbPair.binStep),\n      new BN(this.tokenX.mint.decimals),\n      new BN(this.tokenY.mint.decimals),\n      withdraws,\n      deposits,\n    );\n\n    const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(\n      simulationResult.depositParams,\n      simulationResult.withdrawParams,\n      new BN(rebalancePosition.lbPair.activeId),\n    );\n\n    return {\n      rebalancePosition,\n      simulationResult,\n      ...binArrayQuoteResult,\n    };\n  }\n\n  /**\n   * Rebalances a position and claim rewards if specified.\n   *\n   * @param rebalancePositionResponse The result of `simulateRebalancePosition`.\n   * @param maxActiveBinSlippage The maximum slippage allowed for active bin selection.\n   * @param slippage The slippage tolerance percentage for rebalncing.\n   *\n   * @returns An object containing the instructions to initialize new bin arrays and the instruction to rebalance the position.\n   */\n  public async rebalancePosition(\n    rebalancePositionResponse: RebalancePositionResponse,\n    maxActiveBinSlippage: BN,\n    rentPayer?: PublicKey,\n    slippage: number = 100,\n  ) {\n    const { rebalancePosition, simulationResult } = rebalancePositionResponse;\n\n    const { lbPair, shouldClaimFee, shouldClaimReward, owner, address } =\n      rebalancePosition;\n    const { depositParams, withdrawParams } = simulationResult;\n\n    const activeId = new BN(lbPair.activeId);\n\n    const { slices, accounts: transferHookAccounts } =\n      this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n    const preInstructions: TransactionInstruction[] = [];\n    const harvestRewardRemainingAccountMetas: AccountMeta[] = [];\n\n    if (shouldClaimReward) {\n      for (const [idx, reward] of this.lbPair.rewardInfos.entries()) {\n        if (!reward.mint.equals(PublicKey.default)) {\n          const rewardTokenInfo = this.rewards[idx];\n          slices.push({\n            accountsType: {\n              transferHookMultiReward: {\n                0: idx,\n              },\n            },\n            length: rewardTokenInfo.transferHookAccountMetas.length,\n          });\n\n          transferHookAccounts.push(\n            ...rewardTokenInfo.transferHookAccountMetas,\n          );\n\n          const userTokenRewardAddress = getAssociatedTokenAddressSync(\n            reward.mint,\n            owner,\n            true,\n            rewardTokenInfo.owner,\n          );\n\n          preInstructions.push(\n            createAssociatedTokenAccountIdempotentInstruction(\n              owner,\n              userTokenRewardAddress,\n              owner,\n              reward.mint,\n              rewardTokenInfo.owner,\n            ),\n          );\n\n          const rewardVault: AccountMeta = {\n            pubkey: reward.vault,\n            isSigner: false,\n            isWritable: true,\n          };\n\n          const userTokenReward: AccountMeta = {\n            pubkey: userTokenRewardAddress,\n            isSigner: false,\n            isWritable: true,\n          };\n\n          const rewardMint: AccountMeta = {\n            pubkey: reward.mint,\n            isSigner: false,\n            isWritable: false,\n          };\n\n          const rewardTokenProgram: AccountMeta = {\n            pubkey: rewardTokenInfo.owner,\n            isSigner: false,\n            isWritable: false,\n          };\n\n          harvestRewardRemainingAccountMetas.push(\n            rewardVault,\n            userTokenReward,\n            rewardMint,\n            rewardTokenProgram,\n          );\n        }\n      }\n    }\n\n    const initBinArrayInstructions: TransactionInstruction[] = [];\n\n    const { binArrayBitmap, binArrayIndexes } =\n      getRebalanceBinArrayIndexesAndBitmapCoverage(\n        depositParams,\n        withdrawParams,\n        activeId.toNumber(),\n        this.pubkey,\n        this.program.programId,\n      );\n\n    const binArrayPublicKeys = binArrayIndexes.map((index) => {\n      const [binArrayPubkey] = deriveBinArray(\n        this.pubkey,\n        index,\n        this.program.programId,\n      );\n      return binArrayPubkey;\n    });\n\n    const binArrayAccounts = await chunkedGetMultipleAccountInfos(\n      this.program.provider.connection,\n      binArrayPublicKeys,\n    );\n\n    for (let i = 0; i < binArrayAccounts.length; i++) {\n      const binArrayAccount = binArrayAccounts[i];\n      if (!binArrayAccount) {\n        const binArrayPubkey = binArrayPublicKeys[i];\n        const binArrayIndex = binArrayIndexes[i];\n        const initBinArrayIx = await this.program.methods\n          .initializeBinArray(binArrayIndex)\n          .accountsPartial({\n            binArray: binArrayPubkey,\n            funder: owner,\n            lbPair: this.pubkey,\n          })\n          .instruction();\n\n        initBinArrayInstructions.push(initBinArrayIx);\n      }\n    }\n\n    if (!binArrayBitmap.equals(PublicKey.default)) {\n      const bitmapAccount =\n        await this.program.provider.connection.getAccountInfo(binArrayBitmap);\n\n      if (!bitmapAccount) {\n        const initBitmapExtensionIx = await this.program.methods\n          .initializeBinArrayBitmapExtension()\n          .accountsPartial({\n            binArrayBitmapExtension: binArrayBitmap,\n            funder: owner,\n            lbPair: this.pubkey,\n          })\n          .preInstructions([\n            ComputeBudgetProgram.setComputeUnitLimit({\n              units: DEFAULT_INIT_BIN_ARRAY_CU,\n            }),\n          ])\n          .instruction();\n        preInstructions.push(initBitmapExtensionIx);\n      }\n    }\n\n    const [\n      { ataPubKey: userTokenX, ix: createUserTokenXIx },\n      { ataPubKey: userTokenY, ix: createUserTokenYIx },\n    ] = await Promise.all([\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenX.publicKey,\n        owner,\n        this.tokenX.owner,\n      ),\n      getOrCreateATAInstruction(\n        this.program.provider.connection,\n        this.tokenY.publicKey,\n        owner,\n        this.tokenY.owner,\n      ),\n    ]);\n    createUserTokenXIx && preInstructions.push(createUserTokenXIx);\n    createUserTokenYIx && preInstructions.push(createUserTokenYIx);\n\n    slippage = capSlippagePercentage(slippage);\n\n    const maxDepositXAmount = getSlippageMaxAmount(\n      simulationResult.actualAmountXDeposited,\n      slippage,\n    );\n\n    const maxDepositYAmount = getSlippageMaxAmount(\n      simulationResult.actualAmountYDeposited,\n      slippage,\n    );\n\n    const minWithdrawXAmount = getSlippageMinAmount(\n      simulationResult.actualAmountXWithdrawn,\n      slippage,\n    );\n\n    const minWithdrawYAmount = getSlippageMinAmount(\n      simulationResult.actualAmountYWithdrawn,\n      slippage,\n    );\n\n    const postInstructions: Array<TransactionInstruction> = [];\n\n    // Add wrapSOL instructions if tokenX or tokenY is NATIVE_MINT\n    if (\n      this.tokenX.publicKey.equals(NATIVE_MINT) &&\n      simulationResult.actualAmountXDeposited.gtn(0) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        owner,\n        userTokenX,\n        BigInt(simulationResult.actualAmountXDeposited.toString()),\n      );\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    if (\n      this.tokenY.publicKey.equals(NATIVE_MINT) &&\n      simulationResult.actualAmountYDeposited.gtn(0) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const wrapSOLIx = wrapSOLInstruction(\n        owner,\n        userTokenY,\n        BigInt(simulationResult.actualAmountYDeposited.toString()),\n      );\n      preInstructions.push(...wrapSOLIx);\n    }\n\n    // Add unwrapSOL instructions if tokenX or tokenY is NATIVE_MINT\n    if (\n      (this.tokenX.publicKey.equals(NATIVE_MINT) ||\n        this.tokenY.publicKey.equals(NATIVE_MINT)) &&\n      !this.opt?.skipSolWrappingOperation\n    ) {\n      const closeWrappedSOLIx = await unwrapSOLInstruction(owner);\n      closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n    }\n\n    const instruction = await this.program.methods\n      .rebalanceLiquidity(\n        {\n          adds: depositParams,\n          removes: withdrawParams,\n          activeId: activeId.toNumber(),\n          shouldClaimFee,\n          shouldClaimReward,\n          maxActiveBinSlippage: maxActiveBinSlippage.toNumber(),\n          maxDepositXAmount,\n          maxDepositYAmount,\n          minWithdrawXAmount,\n          minWithdrawYAmount,\n          shrinkMode: ShrinkMode.ShrinkBoth,\n          padding: REBALANCE_POSITION_PADDING,\n        },\n        {\n          slices,\n        },\n      )\n      .accountsPartial({\n        lbPair: this.pubkey,\n        binArrayBitmapExtension: binArrayBitmap,\n        position: address,\n        owner,\n        userTokenX,\n        userTokenY,\n        reserveX: this.lbPair.reserveX,\n        reserveY: this.lbPair.reserveY,\n        tokenXMint: this.tokenX.publicKey,\n        tokenYMint: this.tokenY.publicKey,\n        tokenXProgram: this.tokenX.owner,\n        tokenYProgram: this.tokenY.owner,\n        memoProgram: MEMO_PROGRAM_ID,\n        rentPayer: rentPayer ?? owner,\n      })\n      .remainingAccounts(transferHookAccounts)\n      .remainingAccounts(\n        binArrayPublicKeys.map((pubkey) => {\n          return {\n            pubkey,\n            isSigner: false,\n            isWritable: true,\n          };\n        }),\n      )\n      .instruction();\n\n    const setCUIX = await getEstimatedComputeUnitIxWithBuffer(\n      this.program.provider.connection,\n      [instruction],\n      owner,\n    );\n\n    const rebalancePositionInstruction = [\n      setCUIX,\n      ...preInstructions,\n      instruction,\n      ...postInstructions,\n    ];\n\n    return {\n      initBinArrayInstructions,\n      rebalancePositionInstruction,\n    };\n  }\n\n  /**\n   * Create an extended empty position.\n   *\n   * @param lowerBinid The lowest bin of the position.\n   * @param upperBinId The highest bin of the position.\n   * @param position The public key of the position.\n   * @param owner The owner of the position.\n   * @returns The instructions to create the extended empty position.\n   */\n  public async createExtendedEmptyPosition(\n    lowerBinid: number,\n    upperBinId: number,\n    position: PublicKey,\n    owner: PublicKey,\n  ) {\n    const positionWidth = upperBinId - lowerBinid + 1;\n    const basePositionWidth = Math.min(\n      positionWidth,\n      DEFAULT_BIN_PER_POSITION.toNumber(),\n    );\n\n    const ixs = await this.createInitAndExtendPositionIx(\n      lowerBinid,\n      upperBinId,\n      basePositionWidth,\n      owner,\n      position,\n    );\n\n    const latestBlockhashInfo =\n      await this.program.provider.connection.getLatestBlockhash();\n\n    const tx = new Transaction({\n      ...latestBlockhashInfo,\n      feePayer: owner,\n    }).add(...ixs);\n\n    return tx;\n  }\n\n  private async createInitAndExtendPositionIx(\n    lowerBinId: number,\n    upperBinId: number,\n    basePositionWidth: number,\n    user: PublicKey,\n    position: PublicKey,\n  ) {\n    const createPositionIx = await this.program.methods\n      .initializePosition(lowerBinId, basePositionWidth)\n      .accountsPartial({\n        payer: user,\n        position,\n        lbPair: this.pubkey,\n        owner: user,\n        rent: SYSVAR_RENT_PUBKEY,\n      })\n      .instruction();\n\n    const extendedBinCount = getExtendedPositionBinCount(\n      new BN(lowerBinId),\n      new BN(upperBinId),\n    );\n\n    if (extendedBinCount.gt(new BN(0))) {\n      const extendPositionIxs = await this.increasePositionLengthIxs(\n        position,\n        ResizeSide.Upper,\n        extendedBinCount,\n        user,\n        user,\n        false,\n        false,\n      );\n\n      const extendPositionDefaultCU =\n        getDefaultExtendPositionCU(ResizeSide.Upper) *\n        extendedBinCount.toNumber();\n\n      return [\n        ComputeBudgetProgram.setComputeUnitLimit({\n          units: Math.min(\n            DEFAULT_INIT_POSITION_CU + extendPositionDefaultCU,\n            1_400_000,\n          ),\n        }),\n        createPositionIx,\n        ...extendPositionIxs.flat(),\n      ];\n    } else {\n      return [\n        ComputeBudgetProgram.setComputeUnitLimit({\n          units: DEFAULT_INIT_POSITION_CU,\n        }),\n        createPositionIx,\n      ];\n    }\n  }\n\n  private async increasePositionLengthIxs(\n    position: PublicKey,\n    side: ResizeSide,\n    length: BN,\n    funder: PublicKey,\n    positionOwner: PublicKey,\n    includeSetCuIx = true,\n    allowParallelExecution = true,\n  ) {\n    // Split into multiple increase position length ix to bypass stack size limit\n    const groupedIxs: TransactionInstruction[][] = [];\n    const promises = [];\n\n    for (let i = 0; i < length.toNumber(); i += MAX_RESIZE_LENGTH.toNumber()) {\n      const lengthToAdd = Math.min(\n        length.toNumber() - i,\n        MAX_RESIZE_LENGTH.toNumber(),\n      );\n\n      // Estimate CU might off due to the CU might higher and higher as the position length increase. However, simulate CU always based on current position length.\n      const setCuIx = ComputeBudgetProgram.setComputeUnitLimit({\n        units: getDefaultExtendPositionCU(side),\n      });\n\n      const ixPromise = this.program.methods\n        .increasePositionLength(lengthToAdd, Number(side))\n        .accountsPartial({\n          lbPair: this.pubkey,\n          position,\n          owner: positionOwner,\n          funder,\n        })\n        .instruction()\n        .then((increasePositionLengthIx) => {\n          if (allowParallelExecution) {\n            // Trick to make each increase position length transaction to be unique to allow parallel execution\n            increasePositionLengthIx.keys.push({\n              isSigner: false,\n              isWritable: false,\n              pubkey: PublicKey.unique(),\n            });\n          }\n\n          const ixs = [increasePositionLengthIx];\n\n          if (includeSetCuIx) {\n            ixs.unshift(setCuIx);\n          }\n\n          groupedIxs.push(ixs);\n        });\n\n      promises.push(ixPromise);\n    }\n\n    await Promise.all(promises);\n    return groupedIxs;\n  }\n\n  /** Private static method */\n\n  private static async getBinArrays(\n    program: ClmmProgram,\n    lbPairPubkey: PublicKey,\n  ): Promise<Array<BinArrayAccount>> {\n    return program.account.binArray.all([binArrayLbPairFilter(lbPairPubkey)]);\n  }\n\n  private static async processPosition(\n    program: ClmmProgram,\n    lbPair: LbPair,\n    clock: Clock,\n    position: IPosition,\n    baseMint: Mint,\n    quoteMint: Mint,\n    rewardMint0: Mint | null,\n    rewardMint1: Mint | null,\n    binArrayMap: Map<String, BinArray>,\n  ): Promise<PositionData | null> {\n    const lbPairKey = position.lbPair();\n    const lowerBinId = position.lowerBinId();\n    const upperBinId = position.upperBinId();\n\n    const posShares = position.liquidityShares();\n    const lastUpdatedAt = position.lastUpdatedAt();\n    const feeInfos = position.feeInfos();\n\n    const totalClaimedFeeXAmount = position.totalClaimedFeeXAmount();\n    const totalClaimedFeeYAmount = position.totalClaimedFeeYAmount();\n\n    const positionRewardInfos = position.rewardInfos();\n\n    const feeOwner = position.feeOwner();\n\n    const bins = this.getBinsBetweenLowerAndUpperBound(\n      lbPairKey,\n      lbPair,\n      lowerBinId.toNumber(),\n      upperBinId.toNumber(),\n      baseMint.decimals,\n      quoteMint.decimals,\n      binArrayMap,\n      program.programId,\n    );\n\n    if (!bins.length) return null;\n\n    const positionData: PositionBinData[] = [];\n\n    let totalXAmount = new Decimal(0);\n    let totalYAmount = new Decimal(0);\n\n    const ZERO = new BN(0);\n\n    let feeX = ZERO;\n    let feeY = ZERO;\n\n    let rewards = [ZERO, ZERO];\n\n    bins.forEach((bin, idx) => {\n      const binSupply = bin.supply;\n      const posShare = posShares[idx];\n\n      const posBinRewardInfo = positionRewardInfos[idx];\n\n      const positionXAmount = binSupply.eq(ZERO)\n        ? ZERO\n        : posShare.mul(bin.xAmount).div(binSupply);\n\n      const positionYAmount = binSupply.eq(ZERO)\n        ? ZERO\n        : posShare.mul(bin.yAmount).div(binSupply);\n\n      totalXAmount = totalXAmount.add(new Decimal(positionXAmount.toString()));\n      totalYAmount = totalYAmount.add(new Decimal(positionYAmount.toString()));\n\n      const feeInfo = feeInfos[idx];\n\n      const newFeeX = posShare.isZero()\n        ? new BN(0)\n        : mulShr(\n            posShares[idx].shrn(SCALE_OFFSET),\n            bin.feeAmountXPerTokenStored.sub(feeInfo.feeXPerTokenComplete),\n            SCALE_OFFSET,\n            Rounding.Down,\n          );\n\n      const newFeeY = posShare.isZero()\n        ? new BN(0)\n        : mulShr(\n            posShares[idx].shrn(SCALE_OFFSET),\n            bin.feeAmountYPerTokenStored.sub(feeInfo.feeYPerTokenComplete),\n            SCALE_OFFSET,\n            Rounding.Down,\n          );\n\n      const claimableFeeX = newFeeX.add(feeInfo.feeXPending);\n      const claimableFeeY = newFeeY.add(feeInfo.feeYPending);\n\n      feeX = feeX.add(claimableFeeX);\n      feeY = feeY.add(claimableFeeY);\n\n      const claimableRewardsInBin = [new BN(0), new BN(0)];\n\n      for (let j = 0; j < claimableRewardsInBin.length; j++) {\n        const pairRewardInfo = lbPair.rewardInfos[j];\n\n        if (!pairRewardInfo.mint.equals(PublicKey.default)) {\n          let rewardPerTokenStored = bin.rewardPerTokenStored[j];\n\n          if (bin.binId == lbPair.activeId && !bin.supply.isZero()) {\n            const currentTime = new BN(\n              Math.min(\n                clock.unixTimestamp.toNumber(),\n                pairRewardInfo.rewardDurationEnd.toNumber(),\n              ),\n            );\n\n            const delta = currentTime.sub(pairRewardInfo.lastUpdateTime);\n            const liquiditySupply = bin.supply.shrn(SCALE_OFFSET);\n\n            const rewardPerTokenStoredDelta = pairRewardInfo.rewardRate\n              .mul(delta)\n              .div(new BN(15))\n              .div(liquiditySupply);\n\n            rewardPerTokenStored = rewardPerTokenStored.add(\n              rewardPerTokenStoredDelta,\n            );\n          }\n\n          const delta = rewardPerTokenStored.sub(\n            posBinRewardInfo.rewardPerTokenCompletes[j],\n          );\n\n          const newReward = posShares[idx].isZero()\n            ? new BN(0)\n            : mulShr(\n                delta,\n                posShares[idx].shrn(SCALE_OFFSET),\n                SCALE_OFFSET,\n                Rounding.Down,\n              );\n\n          const claimableReward = newReward.add(\n            posBinRewardInfo.rewardPendings[j],\n          );\n\n          claimableRewardsInBin[j] =\n            claimableRewardsInBin[j].add(claimableReward);\n          rewards[j] = rewards[j].add(claimableReward);\n        }\n      }\n\n      positionData.push({\n        binId: bin.binId,\n        price: bin.price,\n        pricePerToken: bin.pricePerToken,\n        binXAmount: bin.xAmount.toString(),\n        binYAmount: bin.yAmount.toString(),\n        binLiquidity: binSupply.toString(),\n        positionLiquidity: posShare.toString(),\n        positionXAmount: positionXAmount.toString(),\n        positionYAmount: positionYAmount.toString(),\n        positionFeeXAmount: claimableFeeX.toString(),\n        positionFeeYAmount: claimableFeeY.toString(),\n        positionRewardAmount: claimableRewardsInBin.map((amount) =>\n          amount.toString(),\n        ),\n      });\n    });\n\n    const currentEpoch = clock.epoch.toNumber();\n\n    const feeXExcludeTransferFee = calculateTransferFeeExcludedAmount(\n      feeX,\n      baseMint,\n      currentEpoch,\n    ).amount;\n\n    const feeYExcludeTransferFee = calculateTransferFeeExcludedAmount(\n      feeY,\n      quoteMint,\n      currentEpoch,\n    ).amount;\n\n    const rewardOne = rewards[0];\n    const rewardTwo = rewards[1];\n\n    let rewardOneExcludeTransferFee = new BN(0);\n    let rewardTwoExcludeTransferFee = new BN(0);\n\n    if (rewardMint0) {\n      rewardOneExcludeTransferFee = calculateTransferFeeExcludedAmount(\n        rewardOne,\n        rewardMint0,\n        currentEpoch,\n      ).amount;\n    }\n\n    if (rewardMint1) {\n      rewardTwoExcludeTransferFee = calculateTransferFeeExcludedAmount(\n        rewardTwo,\n        rewardMint1,\n        currentEpoch,\n      ).amount;\n    }\n\n    const totalXAmountExcludeTransferFee = calculateTransferFeeExcludedAmount(\n      new BN(totalXAmount.floor().toString()),\n      baseMint,\n      currentEpoch,\n    ).amount;\n\n    const totalYAmountExcludeTransferFee = calculateTransferFeeExcludedAmount(\n      new BN(totalYAmount.floor().toString()),\n      quoteMint,\n      currentEpoch,\n    ).amount;\n\n    return {\n      totalXAmount: totalXAmount.toString(),\n      totalYAmount: totalYAmount.toString(),\n      positionBinData: positionData,\n      lastUpdatedAt,\n      lowerBinId: lowerBinId.toNumber(),\n      upperBinId: upperBinId.toNumber(),\n      feeX,\n      feeY,\n      rewardOne,\n      rewardTwo,\n      feeOwner,\n      totalClaimedFeeXAmount,\n      totalClaimedFeeYAmount,\n      totalXAmountExcludeTransferFee,\n      totalYAmountExcludeTransferFee,\n      rewardOneExcludeTransferFee,\n      rewardTwoExcludeTransferFee,\n      feeXExcludeTransferFee,\n      feeYExcludeTransferFee,\n      owner: position.owner(),\n    };\n  }\n\n  private static getBinsBetweenLowerAndUpperBound(\n    lbPairKey: PublicKey,\n    lbPair: LbPair,\n    lowerBinId: number,\n    upperBinId: number,\n    baseTokenDecimal: number,\n    quoteTokenDecimal: number,\n    binArrayMap: Map<String, BinArray>,\n    programId: PublicKey,\n  ): BinLiquidity[] {\n    const lowerBinArrayIndex = binIdToBinArrayIndex(new BN(lowerBinId));\n    const upperBinArrayIndex = binIdToBinArrayIndex(new BN(upperBinId));\n\n    let bins: BinLiquidity[] = [];\n    const ZERO = new BN(0);\n\n    for (\n      let binArrayIndex = lowerBinArrayIndex.toNumber();\n      binArrayIndex <= upperBinArrayIndex.toNumber();\n      binArrayIndex++\n    ) {\n      const binArrayIndexBN = new BN(binArrayIndex);\n      const binArrayKey = deriveBinArray(\n        lbPairKey,\n        binArrayIndexBN,\n        programId,\n      )[0];\n\n      const [lowerBinIdForBinArray] =\n        getBinArrayLowerUpperBinId(binArrayIndexBN);\n\n      const binArray = binArrayMap.get(binArrayKey.toBase58());\n\n      for (let i = 0; i < MAX_BIN_ARRAY_SIZE.toNumber(); i++) {\n        const binId = lowerBinIdForBinArray.toNumber() + i;\n\n        if (binId >= lowerBinId && binId <= upperBinId) {\n          const pricePerLamport = getPriceOfBinByBinId(\n            binId,\n            lbPair.binStep,\n          ).toString();\n\n          if (!binArray) {\n            bins.push({\n              binId,\n              xAmount: ZERO,\n              yAmount: ZERO,\n              supply: ZERO,\n              feeAmountXPerTokenStored: ZERO,\n              feeAmountYPerTokenStored: ZERO,\n              rewardPerTokenStored: [ZERO, ZERO],\n              price: pricePerLamport,\n              version: 2,\n              pricePerToken: new Decimal(pricePerLamport)\n                .mul(new Decimal(10 ** (baseTokenDecimal - quoteTokenDecimal)))\n                .toString(),\n            });\n          } else {\n            const bin = binArray.bins[i];\n\n            bins.push({\n              binId,\n              xAmount: bin.amountX,\n              yAmount: bin.amountY,\n              supply: bin.liquiditySupply,\n              feeAmountXPerTokenStored: bin.feeAmountXPerTokenStored,\n              feeAmountYPerTokenStored: bin.feeAmountYPerTokenStored,\n              rewardPerTokenStored: bin.functionBytes,\n              price: pricePerLamport,\n              version: binArray.version,\n              pricePerToken: new Decimal(pricePerLamport)\n                .mul(new Decimal(10 ** (baseTokenDecimal - quoteTokenDecimal)))\n                .toString(),\n            });\n          }\n        }\n      }\n    }\n\n    return bins;\n  }\n\n  /** Private method */\n\n  private processXYAmountDistribution(xYAmountDistribution: BinAndAmount[]) {\n    let currentBinId: number | null = null;\n    const xAmountDistribution: BN[] = [];\n    const yAmountDistribution: BN[] = [];\n    const binIds: number[] = [];\n\n    xYAmountDistribution.forEach((binAndAmount) => {\n      xAmountDistribution.push(binAndAmount.xAmountBpsOfTotal);\n      yAmountDistribution.push(binAndAmount.yAmountBpsOfTotal);\n      binIds.push(binAndAmount.binId);\n\n      if (currentBinId && binAndAmount.binId !== currentBinId + 1) {\n        throw new Error(\"Discontinuous Bin ID\");\n      } else {\n        currentBinId = binAndAmount.binId;\n      }\n    });\n\n    return {\n      lowerBinId: xYAmountDistribution[0].binId,\n      upperBinId: xYAmountDistribution[xYAmountDistribution.length - 1].binId,\n      xAmountDistribution,\n      yAmountDistribution,\n      binIds,\n    };\n  }\n\n  private async getBins(\n    lbPairPubKey: PublicKey,\n    lowerBinId: number,\n    upperBinId: number,\n    baseTokenDecimal: number,\n    quoteTokenDecimal: number,\n    lowerBinArray?: BinArray,\n    upperBinArray?: BinArray,\n  ) {\n    const lowerBinArrayIndex = binIdToBinArrayIndex(new BN(lowerBinId));\n    const upperBinArrayIndex = binIdToBinArrayIndex(new BN(upperBinId));\n\n    const hasCachedLowerBinArray = lowerBinArray != null;\n    const hasCachedUpperBinArray = upperBinArray != null;\n    const isSingleBinArray = lowerBinArrayIndex.eq(upperBinArrayIndex);\n\n    const lowerBinArrayIndexOffset = hasCachedLowerBinArray ? 1 : 0;\n    const upperBinArrayIndexOffset = hasCachedUpperBinArray ? -1 : 0;\n\n    const binArrayPubkeys = range(\n      lowerBinArrayIndex.toNumber() + lowerBinArrayIndexOffset,\n      upperBinArrayIndex.toNumber() + upperBinArrayIndexOffset,\n      (i) => deriveBinArray(lbPairPubKey, new BN(i), this.program.programId)[0],\n    );\n    const fetchedBinArrays =\n      binArrayPubkeys.length !== 0\n        ? await this.program.account.binArray.fetchMultiple(binArrayPubkeys)\n        : [];\n    const binArrays = [\n      ...(hasCachedLowerBinArray ? [lowerBinArray] : []),\n      ...fetchedBinArrays,\n      ...(hasCachedUpperBinArray && !isSingleBinArray ? [upperBinArray] : []),\n    ];\n\n    const binsById = new Map(\n      binArrays\n        .filter((x) => x != null)\n        .flatMap(({ bins, index }) => {\n          const [lowerBinId] = getBinArrayLowerUpperBinId(index);\n          return bins.map(\n            (b, i) => [lowerBinId.toNumber() + i, b] as [number, Bin],\n          );\n        }),\n    );\n    const version =\n      binArrays.find((binArray) => binArray != null)?.version ?? 1;\n\n    return Array.from(\n      enumerateBins(\n        binsById,\n        lowerBinId,\n        upperBinId,\n        this.lbPair.binStep,\n        baseTokenDecimal,\n        quoteTokenDecimal,\n        version,\n      ),\n    );\n  }\n\n  private async binArraysToBeCreate(\n    lowerBinArrayIndex: BN,\n    upperBinArrayIndex: BN,\n  ) {\n    const binArrayIndexes: BN[] = Array.from(\n      { length: upperBinArrayIndex.sub(lowerBinArrayIndex).toNumber() + 1 },\n      (_, index) => index + lowerBinArrayIndex.toNumber(),\n    ).map((idx) => new BN(idx));\n\n    const binArrays: PublicKey[] = [];\n    for (const idx of binArrayIndexes) {\n      const [binArrayPubKey] = deriveBinArray(\n        this.pubkey,\n        idx,\n        this.program.programId,\n      );\n      binArrays.push(binArrayPubKey);\n    }\n\n    const binArrayAccounts =\n      await this.program.provider.connection.getMultipleAccountsInfo(binArrays);\n\n    return binArrayAccounts\n      .filter((binArray) => binArray === null)\n      .map((_, index) => binArrays[index]);\n  }\n\n  private async createBinArraysIfNeeded(\n    binArrayIndexes: BN[],\n    funder: PublicKey,\n  ): Promise<TransactionInstruction[]> {\n    const ixs: TransactionInstruction[] = [];\n\n    for (const idx of binArrayIndexes) {\n      const [binArrayKey] = deriveBinArray(\n        this.pubkey,\n        idx,\n        this.program.programId,\n      );\n      const binArrayAccount =\n        await this.program.provider.connection.getAccountInfo(binArrayKey);\n\n      if (binArrayAccount === null) {\n        ixs.push(\n          await this.program.methods\n            .initializeBinArray(idx)\n            .accountsPartial({\n              binArray: binArrayKey,\n              funder,\n              lbPair: this.pubkey,\n            })\n            .instruction(),\n        );\n      }\n    }\n    return ixs;\n  }\n\n  public static updateVolatilityAccumulator(\n    vParameter: vParameters,\n    sParameter: sParameters,\n    activeId: number,\n  ) {\n    const deltaId = Math.abs(vParameter.indexReference - activeId);\n    const newVolatilityAccumulator =\n      vParameter.volatilityReference + deltaId * BASIS_POINT_MAX;\n\n    vParameter.volatilityAccumulator = Math.min(\n      newVolatilityAccumulator,\n      sParameter.maxVolatilityAccumulator,\n    );\n  }\n\n  public static updateReference(\n    activeId: number,\n    vParameter: vParameters,\n    sParameter: sParameters,\n    currentTimestamp: number,\n  ) {\n    const elapsed =\n      currentTimestamp - vParameter.lastUpdateTimestamp.toNumber();\n\n    if (elapsed >= sParameter.filterPeriod) {\n      vParameter.indexReference = activeId;\n      if (elapsed < sParameter.decayPeriod) {\n        const decayedVolatilityReference = Math.floor(\n          (vParameter.volatilityAccumulator * sParameter.reductionFactor) /\n            BASIS_POINT_MAX,\n        );\n        vParameter.volatilityReference = decayedVolatilityReference;\n      } else {\n        vParameter.volatilityReference = 0;\n      }\n    }\n  }\n\n  private async createClaimBuildMethod({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction[]> {\n    // Avoid to attempt to load uninitialized bin array on the program\n    const maybeClaimableBinRange = getPositionLowerUpperBinIdWithLiquidity(\n      position.positionData,\n    );\n\n    if (!maybeClaimableBinRange) return [];\n\n    const { lowerBinId, upperBinId } = maybeClaimableBinRange;\n\n    const chunkedBinRange = chunkBinRange(\n      lowerBinId.toNumber(),\n      upperBinId.toNumber(),\n    );\n\n    const claimTransactions: Transaction[] = [];\n\n    for (const {\n      lowerBinId: chunkedLowerBinId,\n      upperBinId: chunkedUpperBinId,\n    } of chunkedBinRange) {\n      const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(\n        new BN(chunkedLowerBinId),\n        new BN(chunkedUpperBinId),\n        this.pubkey,\n        this.program.programId,\n      );\n\n      for (let i = 0; i < 2; i++) {\n        const rewardInfo = this.lbPair.rewardInfos[i];\n        if (!rewardInfo || rewardInfo.mint.equals(PublicKey.default)) continue;\n\n        const preInstructions = [];\n        const userRewardToken = getAssociatedTokenAddressSync(\n          rewardInfo.mint,\n          owner,\n          true,\n          this.rewards[i].owner,\n        );\n\n        const createUserTokenIx =\n          createAssociatedTokenAccountIdempotentInstruction(\n            owner,\n            userRewardToken,\n            owner,\n            rewardInfo.mint,\n            this.rewards[i].owner,\n          );\n\n        preInstructions.push(createUserTokenIx);\n\n        const { slices, accounts: transferHookAccounts } =\n          this.getPotentialToken2022IxDataAndAccounts(ActionType.Reward, i);\n\n        const claimTransaction = await this.program.methods\n          .claimReward2(new BN(i), chunkedLowerBinId, chunkedUpperBinId, {\n            slices,\n          })\n          .accountsPartial({\n            lbPair: this.pubkey,\n            sender: owner,\n            position: position.publicKey,\n            rewardVault: rewardInfo.vault,\n            rewardMint: rewardInfo.mint,\n            tokenProgram: this.rewards[i].owner,\n            userTokenAccount: userRewardToken,\n            memoProgram: MEMO_PROGRAM_ID,\n          })\n          .remainingAccounts(transferHookAccounts)\n          .remainingAccounts(binArrayAccountsMeta)\n          .preInstructions(preInstructions)\n          .transaction();\n\n        claimTransactions.push(claimTransaction);\n      }\n    }\n\n    return claimTransactions;\n  }\n\n  private async createClaimSwapFeeMethod({\n    owner,\n    position,\n  }: {\n    owner: PublicKey;\n    position: LbPosition;\n  }): Promise<Transaction[]> {\n    // Avoid to attempt to load uninitialized bin array on the program\n    const maybeClaimableBinRange = getPositionLowerUpperBinIdWithLiquidity(\n      position.positionData,\n    );\n\n    if (!maybeClaimableBinRange) return [];\n\n    const { lowerBinId, upperBinId } = maybeClaimableBinRange;\n\n    const chunkedBinRange = chunkBinRange(\n      lowerBinId.toNumber(),\n      upperBinId.toNumber(),\n    );\n\n    const claimFeeTxs = [];\n\n    for (const {\n      lowerBinId: chunkedLowerBinId,\n      upperBinId: chunkedUpperBinId,\n    } of chunkedBinRange) {\n      const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(\n        new BN(chunkedLowerBinId),\n        new BN(chunkedUpperBinId),\n        this.pubkey,\n        this.program.programId,\n      );\n\n      const { feeOwner } = position.positionData;\n\n      const walletToReceiveFee = feeOwner.equals(PublicKey.default)\n        ? owner\n        : feeOwner;\n\n      const preInstructions: TransactionInstruction[] = [];\n\n      const userTokenX = getAssociatedTokenAddressSync(\n        this.lbPair.tokenXMint,\n        walletToReceiveFee,\n        true,\n        this.tokenX.owner,\n      );\n\n      const userTokenY = getAssociatedTokenAddressSync(\n        this.lbPair.tokenYMint,\n        walletToReceiveFee,\n        true,\n        this.tokenY.owner,\n      );\n\n      const createUserTokenXIx =\n        createAssociatedTokenAccountIdempotentInstruction(\n          owner,\n          userTokenX,\n          walletToReceiveFee,\n          this.lbPair.tokenXMint,\n          this.tokenX.owner,\n        );\n\n      const createUserTokenYIx =\n        createAssociatedTokenAccountIdempotentInstruction(\n          owner,\n          userTokenY,\n          walletToReceiveFee,\n          this.lbPair.tokenYMint,\n          this.tokenY.owner,\n        );\n\n      preInstructions.push(createUserTokenXIx);\n      preInstructions.push(createUserTokenYIx);\n\n      const postInstructions: Array<TransactionInstruction> = [];\n      if (\n        [\n          this.tokenX.publicKey.toBase58(),\n          this.tokenY.publicKey.toBase58(),\n        ].includes(NATIVE_MINT.toBase58()) &&\n        !this.opt?.skipSolWrappingOperation\n      ) {\n        const closeWrappedSOLIx = await unwrapSOLInstruction(owner);\n        closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);\n      }\n\n      const { slices, accounts: transferHookAccounts } =\n        this.getPotentialToken2022IxDataAndAccounts(ActionType.Liquidity);\n\n      const claimFeeTx = await this.program.methods\n        .claimFee2(chunkedLowerBinId, chunkedUpperBinId, {\n          slices,\n        })\n        .accountsPartial({\n          lbPair: this.pubkey,\n          sender: owner,\n          position: position.publicKey,\n          reserveX: this.lbPair.reserveX,\n          reserveY: this.lbPair.reserveY,\n          tokenProgramX: this.tokenX.owner,\n          tokenProgramY: this.tokenY.owner,\n          tokenXMint: this.tokenX.publicKey,\n          tokenYMint: this.tokenY.publicKey,\n          userTokenX,\n          userTokenY,\n          memoProgram: MEMO_PROGRAM_ID,\n        })\n        .remainingAccounts(transferHookAccounts)\n        .remainingAccounts(binArrayAccountsMeta)\n        .preInstructions(preInstructions)\n        .postInstructions(postInstructions)\n        .transaction();\n\n      claimFeeTxs.push(claimFeeTx);\n    }\n\n    return claimFeeTxs;\n  }\n\n  public getPotentialToken2022IxDataAndAccounts(\n    actionType: ActionType,\n    rewardIndex?: number,\n  ): { slices: RemainingAccountsInfoSlice[]; accounts: AccountMeta[] } {\n    if (actionType == ActionType.Liquidity) {\n      return {\n        slices: [\n          {\n            accountsType: {\n              transferHookX: {},\n            },\n            length: this.tokenX.transferHookAccountMetas.length,\n          },\n          {\n            accountsType: {\n              transferHookY: {},\n            },\n            length: this.tokenY.transferHookAccountMetas.length,\n          },\n        ],\n        accounts: this.tokenX.transferHookAccountMetas.concat(\n          this.tokenY.transferHookAccountMetas,\n        ),\n      };\n    }\n    return {\n      slices: [\n        {\n          accountsType: {\n            transferHookReward: {},\n          },\n          length: this.rewards[rewardIndex].transferHookAccountMetas.length,\n        },\n      ],\n      accounts: this.rewards[rewardIndex].transferHookAccountMetas,\n    };\n  }\n\n  /**\n   * Fetches the oracle account and returns an IDynamicOracle instance that can be\n   * used to query TWAP (Time-Weighted Average Price) data.\n   *\n   * @returns An IDynamicOracle instance with methods like getActiveIdByTime,\n   * getPriceByTime, getUiPriceByTime, etc.\n   */\n  public async getOracle(): Promise<IDynamicOracle> {\n    const oracleAddress = this.lbPair.oracle;\n    const [oracleAccountInfo, lbPairAccountInfo] =\n      await this.program.provider.connection.getMultipleAccountsInfo([\n        oracleAddress,\n        this.pubkey,\n      ]);\n\n    const lbPairState: LbPair = decodeAccount(\n      this.program,\n      \"lbPair\",\n      lbPairAccountInfo.data,\n    );\n\n    return wrapOracle(\n      oracleAddress,\n      oracleAccountInfo.data,\n      this.lbPair.binStep,\n      new BN(lbPairState.activeId),\n      this.tokenX.mint.decimals,\n      this.tokenY.mint.decimals,\n      this.program,\n    );\n  }\n\n  /**\n   * Returns a transaction to increase the oracle observation storage length.\n   * A longer oracle stores more historical data, enabling TWAP queries over\n   * longer time ranges.\n   *\n   * @param lengthToAdd - Number of observation slots to add.\n   * @param funder - The public key of the account funding the reallocation.\n   * @returns A Transaction that can be signed and sent.\n   */\n  public async increaseOracleLength(\n    lengthToAdd: BN,\n    funder: PublicKey,\n  ): Promise<Transaction> {\n    const oracleAddress = this.lbPair.oracle;\n\n    const increaseOracleLengthIx = await this.program.methods\n      .increaseOracleLength(lengthToAdd)\n      .accountsPartial({\n        oracle: oracleAddress,\n        funder,\n      })\n      .instruction();\n\n    const { blockhash, lastValidBlockHeight } =\n      await this.program.provider.connection.getLatestBlockhash(\"confirmed\");\n    return new Transaction({\n      blockhash,\n      lastValidBlockHeight,\n      feePayer: funder,\n    }).add(increaseOracleLengthIx);\n  }\n}\n"
  },
  {
    "path": "ts-client/src/dlmm/types/index.ts",
    "content": "import {\n  BN,\n  IdlAccounts,\n  IdlTypes,\n  Program,\n  ProgramAccount,\n} from \"@coral-xyz/anchor\";\nimport { LbClmm } from \"../idl/idl\";\nimport { getPriceOfBinByBinId } from \"../helpers\";\nimport {\n  AccountInfo,\n  AccountMeta,\n  Keypair,\n  PublicKey,\n  TransactionInstruction,\n} from \"@solana/web3.js\";\nimport Decimal from \"decimal.js\";\nimport { u64, i64, struct, rustEnum } from \"@coral-xyz/borsh\";\nimport { Mint } from \"@solana/spl-token\";\nimport { AllAccountsMap } from \"@coral-xyz/anchor/dist/cjs/program/namespace/types\";\nimport { RebalancePosition, SimulateRebalanceResp } from \"../helpers/rebalance\";\n\nexport interface FeeInfo {\n  baseFeeRatePercentage: Decimal;\n  maxFeeRatePercentage: Decimal;\n  protocolFeePercentage: Decimal;\n}\n\nexport interface BinAndAmount {\n  binId: number;\n  xAmountBpsOfTotal: BN;\n  yAmountBpsOfTotal: BN;\n}\n\nexport interface TokenReserve {\n  publicKey: PublicKey;\n  reserve: PublicKey;\n  mint: Mint;\n  amount: bigint;\n  owner: PublicKey;\n  transferHookAccountMetas: AccountMeta[];\n}\n\nexport type ClmmProgram = Program<LbClmm>;\n\nexport type LbPair = IdlAccounts<LbClmm>[\"lbPair\"];\nexport type LbPairAccount = ProgramAccount<IdlAccounts<LbClmm>[\"lbPair\"]>;\n\nexport type AccountName = keyof AllAccountsMap<LbClmm>;\n\nexport type Bin = IdlTypes<LbClmm>[\"bin\"];\nexport type BinArray = IdlAccounts<LbClmm>[\"binArray\"];\nexport type BinArrayAccount = ProgramAccount<IdlAccounts<LbClmm>[\"binArray\"]>;\n\nexport type Position = IdlAccounts<LbClmm>[\"position\"];\nexport type PositionV2 = IdlAccounts<LbClmm>[\"positionV2\"];\n\nexport type PresetParameter = IdlAccounts<LbClmm>[\"presetParameter\"];\nexport type PresetParameter2 = IdlAccounts<LbClmm>[\"presetParameter2\"];\n\nexport type vParameters = IdlAccounts<LbClmm>[\"lbPair\"][\"vParameters\"];\nexport type sParameters = IdlAccounts<LbClmm>[\"lbPair\"][\"parameters\"];\nexport type RewardInfos = IdlAccounts<LbClmm>[\"lbPair\"][\"rewardInfos\"];\nexport type RewardInfo = IdlTypes<LbClmm>[\"rewardInfo\"];\n\nexport type UserRewardInfo = IdlTypes<LbClmm>[\"userRewardInfo\"];\nexport type UserFeeInfo = IdlTypes<LbClmm>[\"feeInfo\"];\nexport type RebalanceAddLiquidityParam = IdlTypes<LbClmm>[\"addLiquidityParams\"];\nexport type RebalanceRemoveLiquidityParam =\n  IdlTypes<LbClmm>[\"removeLiquidityParams\"];\n\nexport type InitPermissionPairIx = IdlTypes<LbClmm>[\"initPermissionPairIx\"];\nexport type InitCustomizablePermissionlessPairIx =\n  IdlTypes<LbClmm>[\"customizableParams\"];\n\nexport type BinLiquidityDistribution =\n  IdlTypes<LbClmm>[\"binLiquidityDistribution\"];\nexport type BinLiquidityReduction = IdlTypes<LbClmm>[\"binLiquidityReduction\"];\n\nexport type BinArrayBitmapExtensionAccount = ProgramAccount<\n  IdlAccounts<LbClmm>[\"binArrayBitmapExtension\"]\n>;\nexport type BinArrayBitmapExtension =\n  IdlAccounts<LbClmm>[\"binArrayBitmapExtension\"];\n\nexport type LiquidityParameterByWeight =\n  IdlTypes<LbClmm>[\"liquidityParameterByWeight\"];\nexport type LiquidityOneSideParameter =\n  IdlTypes<LbClmm>[\"liquidityOneSideParameter\"];\n\nexport type LiquidityParameterByStrategy =\n  IdlTypes<LbClmm>[\"liquidityParameterByStrategy\"];\nexport type LiquidityParameterByStrategyOneSide =\n  IdlTypes<LbClmm>[\"liquidityParameterByStrategyOneSide\"];\nexport type LiquidityParameter = IdlTypes<LbClmm>[\"liquidityParameter\"];\n\nexport type ProgramStrategyParameter = IdlTypes<LbClmm>[\"strategyParameters\"];\nexport type ProgramStrategyType = IdlTypes<LbClmm>[\"strategyType\"];\n\nexport type RemainingAccountInfo = IdlTypes<LbClmm>[\"remainingAccountsInfo\"];\nexport type RemainingAccountsInfoSlice =\n  IdlTypes<LbClmm>[\"remainingAccountsSlice\"];\n\nexport type CompressedBinDepositAmount =\n  IdlTypes<LbClmm>[\"compressedBinDepositAmount\"];\nexport type CompressedBinDepositAmounts = CompressedBinDepositAmount[];\n\nexport type ResizeSideEnum = IdlTypes<LbClmm>[\"resizeSide\"];\nexport type ExtendedPositionBinData = IdlTypes<LbClmm>[\"positionBinData\"];\n\nexport type Oracle = IdlTypes<LbClmm>[\"oracle\"];\n\nexport interface LbPosition {\n  publicKey: PublicKey;\n  positionData: PositionData;\n  version: PositionVersion;\n}\n\nexport interface PositionInfo {\n  publicKey: PublicKey;\n  lbPair: LbPair;\n  tokenX: TokenReserve;\n  tokenY: TokenReserve;\n  lbPairPositionsData: Array<LbPosition>;\n}\n\nexport interface FeeInfo {\n  baseFeeRatePercentage: Decimal;\n  maxFeeRatePercentage: Decimal;\n  protocolFeePercentage: Decimal;\n}\n\nexport interface EmissionRate {\n  rewardOne: Decimal | undefined;\n  rewardTwo: Decimal | undefined;\n}\n\nexport interface SwapFee {\n  feeX: BN;\n  feeY: BN;\n}\n\nexport interface LMRewards {\n  rewardOne: BN;\n  rewardTwo: BN;\n}\n\nexport enum PositionVersion {\n  V1,\n  V2,\n}\n\nexport enum PairType {\n  Permissionless,\n  Permissioned,\n  CustomizablePermissionless,\n  PermissionlessV2,\n}\n\nexport enum ShrinkMode {\n  ShrinkBoth,\n  NoShrinkLeft,\n  NoShrinkRight,\n  NoShrinkBoth,\n}\n\nexport const Strategy = {\n  SpotBalanced: { spotBalanced: {} },\n  CurveBalanced: { curveBalanced: {} },\n  BidAskBalanced: { bidAskBalanced: {} },\n  SpotImBalanced: { spotImBalanced: {} },\n  CurveImBalanced: { curveImBalanced: {} },\n  BidAskImBalanced: { bidAskImBalanced: {} },\n};\n\nexport enum StrategyType {\n  Spot,\n  Curve,\n  BidAsk,\n}\n\nexport enum ActivationType {\n  Slot,\n  Timestamp,\n}\n\n// This is position struct size, it doesn't include the discriminator bytes\nexport const POSITION_MIN_SIZE = 8112;\nexport const POSITION_BIN_DATA_SIZE = 112;\n\nexport interface StrategyParameters {\n  maxBinId: number;\n  minBinId: number;\n  strategyType: StrategyType;\n  singleSidedX?: boolean;\n}\n\nexport interface TQuoteCreatePositionParams {\n  strategy: StrategyParameters;\n}\n\nexport interface TInitializePositionAndAddLiquidityParams {\n  positionPubKey: PublicKey;\n  totalXAmount: BN;\n  totalYAmount: BN;\n  xYAmountDistribution: BinAndAmount[];\n  user: PublicKey;\n  slippage?: number;\n}\n\nexport interface TInitializePositionAndAddLiquidityParamsByStrategy {\n  positionPubKey: PublicKey;\n  totalXAmount: BN;\n  totalYAmount: BN;\n  strategy: StrategyParameters;\n  user: PublicKey;\n  slippage?: number;\n}\n\nexport interface InitializeMultiplePositionAndAddLiquidityByStrategyResponse {\n  instructionsByPositions: {\n    positionKeypair: Keypair;\n    initializePositionIx: TransactionInstruction;\n    initializeAtaIxs: TransactionInstruction[];\n    addLiquidityIxs: TransactionInstruction[][];\n  }[];\n}\n\nexport interface InitializeMultiplePositionAndAddLiquidityByStrategyResponse2 {\n  instructionsByPositions: {\n    positionKeypair: Keypair;\n    transactionInstructions: TransactionInstruction[][];\n  }[];\n  lookupTableAddress?: PublicKey;\n}\n\nexport interface TInitializeMultiplePositionAndAddLiquidityParamsByStrategy {\n  totalXAmount: BN;\n  totalYAmount: BN;\n  strategy: StrategyParameters;\n  user: PublicKey;\n  slippage?: number;\n  customKeyPairGenerator?: () => Promise<Keypair>;\n}\n\nexport interface BinLiquidity {\n  binId: number;\n  xAmount: BN;\n  yAmount: BN;\n  supply: BN;\n  version: number;\n  price: string;\n  pricePerToken: string;\n  feeAmountXPerTokenStored: BN;\n  feeAmountYPerTokenStored: BN;\n  rewardPerTokenStored: BN[];\n}\n\nexport module BinLiquidity {\n  export function fromBin(\n    bin: Bin,\n    binId: number,\n    binStep: number,\n    baseTokenDecimal: number,\n    quoteTokenDecimal: number,\n    version: number,\n  ): BinLiquidity {\n    const pricePerLamport = getPriceOfBinByBinId(binId, binStep).toString();\n    return {\n      binId,\n      xAmount: bin.amountX,\n      yAmount: bin.amountY,\n      supply: bin.liquiditySupply,\n      price: pricePerLamport,\n      version,\n      pricePerToken: new Decimal(pricePerLamport)\n        .mul(new Decimal(10 ** (baseTokenDecimal - quoteTokenDecimal)))\n        .toString(),\n      feeAmountXPerTokenStored: bin.feeAmountXPerTokenStored,\n      feeAmountYPerTokenStored: bin.feeAmountYPerTokenStored,\n      rewardPerTokenStored: bin.functionBytes,\n    };\n  }\n\n  export function empty(\n    binId: number,\n    binStep: number,\n    baseTokenDecimal: number,\n    quoteTokenDecimal: number,\n    version: number,\n  ): BinLiquidity {\n    const pricePerLamport = getPriceOfBinByBinId(binId, binStep).toString();\n    return {\n      binId,\n      xAmount: new BN(0),\n      yAmount: new BN(0),\n      supply: new BN(0),\n      price: pricePerLamport,\n      version,\n      pricePerToken: new Decimal(pricePerLamport)\n        .mul(new Decimal(10 ** (baseTokenDecimal - quoteTokenDecimal)))\n        .toString(),\n      feeAmountXPerTokenStored: new BN(0),\n      feeAmountYPerTokenStored: new BN(0),\n      rewardPerTokenStored: [new BN(0), new BN(0)],\n    };\n  }\n}\n\nexport interface SwapQuote {\n  consumedInAmount: BN;\n  outAmount: BN;\n  fee: BN;\n  protocolFee: BN;\n  minOutAmount: BN;\n  priceImpact: Decimal;\n  binArraysPubkey: any[];\n  endPrice: Decimal;\n}\n\nexport interface SwapQuoteExactOut {\n  inAmount: BN;\n  outAmount: BN;\n  fee: BN;\n  priceImpact: Decimal;\n  protocolFee: BN;\n  maxInAmount: BN;\n  binArraysPubkey: any[];\n}\n\nexport interface IAccountsCache {\n  binArrays: Map<String, BinArray>;\n  lbPair: LbPair;\n}\n\nexport interface PositionBinData {\n  binId: number;\n  price: string;\n  pricePerToken: string;\n  binXAmount: string;\n  binYAmount: string;\n  binLiquidity: string;\n  positionLiquidity: string;\n  positionXAmount: string;\n  positionYAmount: string;\n  positionFeeXAmount: string;\n  positionFeeYAmount: string;\n  positionRewardAmount: string[];\n}\n\nexport interface PositionData {\n  totalXAmount: string;\n  totalYAmount: string;\n  positionBinData: PositionBinData[];\n  lastUpdatedAt: BN;\n  upperBinId: number;\n  lowerBinId: number;\n  feeX: BN;\n  feeY: BN;\n  rewardOne: BN;\n  rewardTwo: BN;\n  feeOwner: PublicKey;\n  totalClaimedFeeXAmount: BN;\n  totalClaimedFeeYAmount: BN;\n  feeXExcludeTransferFee: BN;\n  feeYExcludeTransferFee: BN;\n  rewardOneExcludeTransferFee: BN;\n  rewardTwoExcludeTransferFee: BN;\n  totalXAmountExcludeTransferFee: BN;\n  totalYAmountExcludeTransferFee: BN;\n  owner: PublicKey;\n}\n\nexport interface SwapWithPriceImpactParams {\n  /**\n   * mint of in token\n   */\n  inToken: PublicKey;\n  /**\n   * mint of out token\n   */\n  outToken: PublicKey;\n  /**\n   * in token amount\n   */\n  inAmount: BN;\n  /**\n   * price impact in bps\n   */\n  priceImpact: BN;\n  /**\n   * desired lbPair to swap against\n   */\n  lbPair: PublicKey;\n  /**\n   * user\n   */\n  user: PublicKey;\n  binArraysPubkey: PublicKey[];\n}\n\nexport interface SwapParams {\n  /**\n   * mint of in token\n   */\n  inToken: PublicKey;\n  /**\n   * mint of out token\n   */\n  outToken: PublicKey;\n  /**\n   * in token amount\n   */\n  inAmount: BN;\n  /**\n   * minimum out with slippage\n   */\n  minOutAmount: BN;\n  /**\n   * desired lbPair to swap against\n   */\n  lbPair: PublicKey;\n  /**\n   * user\n   */\n  user: PublicKey;\n  binArraysPubkey: PublicKey[];\n}\n\nexport interface SwapExactOutParams {\n  /**\n   * mint of in token\n   */\n  inToken: PublicKey;\n  /**\n   * mint of out token\n   */\n  outToken: PublicKey;\n  /**\n   * out token amount\n   */\n  outAmount: BN;\n  /**\n   * maximum in amount, also known as slippage\n   */\n  maxInAmount: BN;\n  /**\n   * desired lbPair to swap against\n   */\n  lbPair: PublicKey;\n  /**\n   * user\n   */\n  user: PublicKey;\n  binArraysPubkey: PublicKey[];\n}\n\nexport interface GetOrCreateATAResponse {\n  ataPubKey: PublicKey;\n  ix?: TransactionInstruction;\n}\n\nexport enum BitmapType {\n  U1024,\n  U512,\n}\n\nexport interface SeedLiquidityResponse {\n  sendPositionOwnerTokenProveIxs: TransactionInstruction[];\n  initializeBinArraysAndPositionIxs: TransactionInstruction[][];\n  addLiquidityIxs: TransactionInstruction[][];\n  costBreakdown: SeedLiquidityCostBreakdown;\n}\n\nexport interface SeedLiquiditySingleBinResponse {\n  instructions: TransactionInstruction[];\n  costBreakdown: SeedLiquidityCostBreakdown;\n}\n\nexport interface SeedLiquidityCostBreakdown {\n  tokenOwnerProveAssociatedTokenAccountLamports: BN;\n  totalPositionLamports: BN;\n  totalBinArraysLamports: BN;\n  totalPositionCount: BN;\n  totalBinArraysCount: BN;\n  binArrayBitmapLamports: BN;\n}\n\nexport interface Clock {\n  slot: BN;\n  epochStartTimestamp: BN;\n  epoch: BN;\n  leaderScheduleEpoch: BN;\n  unixTimestamp: BN;\n}\n\nexport const ClockLayout = struct([\n  u64(\"slot\"),\n  i64(\"epochStartTimestamp\"),\n  u64(\"epoch\"),\n  u64(\"leaderScheduleEpoch\"),\n  i64(\"unixTimestamp\"),\n]);\n\nexport enum PairStatus {\n  Enabled,\n  Disabled,\n}\n\nexport interface PairLockInfo {\n  positions: Array<PositionLockInfo>;\n}\n\nexport interface PositionLockInfo {\n  positionAddress: PublicKey;\n  owner: PublicKey;\n  tokenXAmount: string;\n  tokenYAmount: string;\n  lockReleasePoint: number;\n}\n\nexport enum ActionType {\n  Liquidity,\n  Reward,\n}\n\nexport enum ResizeSide {\n  Lower,\n  Upper,\n}\n\nexport const MEMO_PROGRAM_ID = new PublicKey(\n  \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\",\n);\n\nexport interface RebalancePositionResponse {\n  rebalancePosition: RebalancePosition;\n  simulationResult: SimulateRebalanceResp;\n}\n\nexport interface RebalancePositionBinArrayRentalCostQuote {\n  binArrayExistence: Set<string>;\n  binArrayCount: number;\n  binArrayCost: number;\n  bitmapExtensionCost: number;\n}\n\nexport const REBALANCE_POSITION_PADDING = Array(31).fill(0);\n\nexport interface ChunkCallbackInfo {\n  chunksLoaded: number;\n  totalChunks: number;\n  accountsLoaded: number;\n  totalAccounts: number;\n}\n\nexport type ChunkCallback = (\n  accounts: { pubkey: PublicKey; account: AccountInfo<Buffer> }[],\n  progress: ChunkCallbackInfo,\n) => void;\n\n/**\n * Options for fetching positions with chunked RPC calls.\n */\nexport interface GetPositionsOpt {\n  /**\n   * Number of accounts to fetch per RPC call when retrieving position data.\n   * Default: 100\n   */\n  chunkSize?: number;\n\n  /**\n   * Optional callback called as each chunk of positions is fetched.\n   * Note: When isParallelExecution is false (default), callbacks fire sequentially in order.\n   * When isParallelExecution is true, callbacks fire in parallel (order not guaranteed).\n   */\n  onChunkFetched?: ChunkCallback;\n\n  /**\n   * Controls whether chunks are fetched in parallel or sequentially.\n   * Default: false (sequential execution)\n   * When false, chunks are fetched sequentially and callbacks fire in order.\n   * When true, callback progress is approximate due to parallel execution.\n   */\n  isParallelExecution?: boolean;\n}\n"
  },
  {
    "path": "ts-client/src/examples/example.ts",
    "content": "import {\n  Connection,\n  Keypair,\n  PublicKey,\n  sendAndConfirmTransaction,\n  TransactionMessage,\n  VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { bs58 } from \"@coral-xyz/anchor/dist/cjs/utils/bytes\";\nimport { DLMM } from \"../dlmm\";\nimport BN from \"bn.js\";\nimport { BinLiquidity, LbPosition, StrategyType } from \"../dlmm/types\";\n\nconst user = Keypair.fromSecretKey(\n  new Uint8Array(bs58.decode(process.env.USER_PRIVATE_KEY))\n);\nconst RPC = process.env.RPC || \"https://api.devnet.solana.com\";\nconst connection = new Connection(RPC, \"finalized\");\n\nconst poolAddress = new PublicKey(\n  \"3W2HKgUa96Z69zzG3LK1g8KdcRAWzAttiLiHfYnKuPw5\"\n);\n\n/** Utils */\nexport interface ParsedClockState {\n  info: {\n    epoch: number;\n    epochStartTimestamp: number;\n    leaderScheduleEpoch: number;\n    slot: number;\n    unixTimestamp: number;\n  };\n  type: string;\n  program: string;\n  space: number;\n}\n\nlet activeBin: BinLiquidity;\nlet userPositions: LbPosition[] = [];\n\nconst newBalancePosition = new Keypair();\nconst newImbalancePosition = new Keypair();\nconst newOneSidePosition = new Keypair();\n\nasync function getActiveBin(dlmmPool: DLMM) {\n  // Get pool state\n  activeBin = await dlmmPool.getActiveBin();\n  console.log(\"🚀 ~ activeBin:\", activeBin);\n}\n\n// To create a balance deposit position\nasync function createBalancePosition(dlmmPool: DLMM) {\n  const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\n  const minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\n  const maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\n  const activeBinPricePerToken = dlmmPool.fromPricePerLamport(\n    Number(activeBin.price)\n  );\n  const totalXAmount = new BN(100);\n  const totalYAmount = totalXAmount.mul(new BN(Number(activeBinPricePerToken)));\n\n  // Create Position\n  const createPositionTx =\n    await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n      positionPubKey: newBalancePosition.publicKey,\n      user: user.publicKey,\n      totalXAmount,\n      totalYAmount,\n      strategy: {\n        maxBinId,\n        minBinId,\n        strategyType: StrategyType.Spot,\n      },\n    });\n\n  try {\n    const createBalancePositionTxHash = await sendAndConfirmTransaction(\n      connection,\n      createPositionTx,\n      [user, newBalancePosition]\n    );\n    console.log(\n      \"🚀 ~ createBalancePositionTxHash:\",\n      createBalancePositionTxHash\n    );\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nasync function createImbalancePosition(dlmmPool: DLMM) {\n  const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\n  const minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\n  const maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\n  const totalXAmount = new BN(100);\n  const totalYAmount = new BN(50);\n\n  // Create Position\n  const createPositionTx =\n    await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n      positionPubKey: newImbalancePosition.publicKey,\n      user: user.publicKey,\n      totalXAmount,\n      totalYAmount,\n      strategy: {\n        maxBinId,\n        minBinId,\n        strategyType: StrategyType.Spot,\n      },\n    });\n\n  try {\n    const createImbalancePositionTxHash = await sendAndConfirmTransaction(\n      connection,\n      createPositionTx,\n      [user, newImbalancePosition]\n    );\n    console.log(\n      \"🚀 ~ createImbalancePositionTxHash:\",\n      createImbalancePositionTxHash\n    );\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nasync function createOneSidePosition(dlmmPool: DLMM) {\n  const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\n  const minBinId = activeBin.binId;\n  const maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL * 2;\n\n  const totalXAmount = new BN(100);\n  const totalYAmount = new BN(0);\n\n  // Create Position\n  const createPositionTx =\n    await dlmmPool.initializePositionAndAddLiquidityByStrategy({\n      positionPubKey: newOneSidePosition.publicKey,\n      user: user.publicKey,\n      totalXAmount,\n      totalYAmount,\n      strategy: {\n        maxBinId,\n        minBinId,\n        strategyType: StrategyType.Spot,\n      },\n    });\n\n  try {\n    const createOneSidePositionTxHash = await sendAndConfirmTransaction(\n      connection,\n      createPositionTx,\n      [user, newOneSidePosition]\n    );\n    console.log(\n      \"🚀 ~ createOneSidePositionTxHash:\",\n      createOneSidePositionTxHash\n    );\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nasync function getPositionsState(dlmmPool: DLMM) {\n  // Get position state\n  const positionsState = await dlmmPool.getPositionsByUserAndLbPair(\n    user.publicKey\n  );\n\n  userPositions = positionsState.userPositions;\n  console.log(\"🚀 ~ userPositions:\", userPositions);\n}\n\nasync function addLiquidityToExistingPosition(dlmmPool: DLMM) {\n  const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin\n  const minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;\n  const maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;\n\n  const activeBinPricePerToken = dlmmPool.fromPricePerLamport(\n    Number(activeBin.price)\n  );\n  const totalXAmount = new BN(100);\n  const totalYAmount = totalXAmount.mul(new BN(Number(activeBinPricePerToken)));\n\n  // Add Liquidity to existing position\n  const addLiquidityTx = await dlmmPool.addLiquidityByStrategy({\n    positionPubKey: newBalancePosition.publicKey,\n    user: user.publicKey,\n    totalXAmount,\n    totalYAmount,\n    strategy: {\n      maxBinId,\n      minBinId,\n      strategyType: StrategyType.Spot,\n    },\n  });\n\n  try {\n    const addLiquidityTxHash = await sendAndConfirmTransaction(\n      connection,\n      addLiquidityTx,\n      [user]\n    );\n    console.log(\"🚀 ~ addLiquidityTxHash:\", addLiquidityTxHash);\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nasync function removePositionLiquidity(dlmmPool: DLMM) {\n  // Remove Liquidity\n  const removeLiquidityTxs = (\n    await Promise.all(\n      userPositions.map(({ publicKey, positionData }) => {\n        const binIdsToRemove = positionData.positionBinData.map(\n          (bin) => bin.binId\n        );\n        return dlmmPool.removeLiquidity({\n          position: publicKey,\n          user: user.publicKey,\n          fromBinId: binIdsToRemove[0],\n          toBinId: binIdsToRemove[binIdsToRemove.length - 1],\n          bps: new BN(100 * 100),\n          shouldClaimAndClose: true, // should claim swap fee and close position together\n        });\n      })\n    )\n  ).flat();\n\n  try {\n    for (let tx of removeLiquidityTxs) {\n      const removeBalanceLiquidityTxHash = await sendAndConfirmTransaction(\n        connection,\n        tx,\n        [user],\n        { skipPreflight: false, preflightCommitment: \"confirmed\" }\n      );\n      console.log(\n        \"🚀 ~ removeBalanceLiquidityTxHash:\",\n        removeBalanceLiquidityTxHash\n      );\n    }\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nasync function swap(dlmmPool: DLMM) {\n  const swapAmount = new BN(100);\n  // Swap quote\n  const swapYtoX = true;\n  const binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX);\n\n  const swapQuote = await dlmmPool.swapQuote(\n    swapAmount,\n    swapYtoX,\n    new BN(10),\n    binArrays\n  );\n\n  console.log(\"🚀 ~ swapQuote:\", swapQuote);\n\n  const [inToken, outToken] = swapYtoX\n    ? [dlmmPool.tokenY.publicKey, dlmmPool.tokenX.publicKey]\n    : [dlmmPool.tokenX.publicKey, dlmmPool.tokenY.publicKey];\n\n  // Swap\n  const swapTx = await dlmmPool.swap({\n    inToken,\n    binArraysPubkey: swapQuote.binArraysPubkey,\n    inAmount: swapAmount,\n    lbPair: dlmmPool.pubkey,\n    user: user.publicKey,\n    minOutAmount: swapQuote.minOutAmount,\n    outToken,\n  });\n\n  try {\n    const swapTxHash = await sendAndConfirmTransaction(connection, swapTx, [\n      user,\n    ]);\n    console.log(\"🚀 ~ swapTxHash:\", swapTxHash);\n  } catch (error) {\n    console.log(\"🚀 ~ error:\", JSON.parse(JSON.stringify(error)));\n  }\n}\n\nconst positionKeypairGenerator = async (count: number) => {\n  const keypairs = [];\n  for (let i = 0; i < count; i++) {\n    keypairs.push(Keypair.generate());\n  }\n  return keypairs;\n};\n\nasync function initializePositionAndAddLiquidityByStrategyParallelExecution(\n  dlmm: DLMM\n) {\n  // Deposit bid side 400 bins\n  const minBinId = dlmm.lbPair.activeId - 401;\n  const maxBinId = dlmm.lbPair.activeId - 1;\n\n  const amountX = new BN(0);\n  const amountY = new BN(10_000_000);\n\n  const slippagePercentage = 0.05;\n\n  const { instructionsByPositions, lookupTableAddress } =\n    await dlmm.initializeMultiplePositionAndAddLiquidityByStrategy2(\n      positionKeypairGenerator,\n      amountX,\n      amountY,\n      {\n        strategyType: StrategyType.Spot,\n        minBinId,\n        maxBinId,\n      },\n      user.publicKey,\n      user.publicKey,\n      slippagePercentage\n    );\n\n  // Get lookup table address if applicable\n  const altState = [];\n\n  if (lookupTableAddress) {\n    const altAccount = await connection.getAddressLookupTable(\n      lookupTableAddress\n    );\n\n    altState.push(altAccount.value);\n  }\n\n  const allPromises = [];\n  const latestBlockhash = await connection.getLatestBlockhash();\n\n  for (const {\n    positionKeypair,\n    transactionInstructions,\n  } of instructionsByPositions) {\n    const transactions = transactionInstructions.map(async (ixs) => {\n      const messageV0 = new TransactionMessage({\n        payerKey: user.publicKey,\n        recentBlockhash: latestBlockhash.blockhash,\n        instructions: ixs,\n      }).compileToV0Message(altState);\n\n      const transaction = new VersionedTransaction(messageV0);\n      transaction.sign([user, positionKeypair]);\n\n      const signature = await connection.sendRawTransaction(\n        transaction.serialize()\n      );\n      console.log(signature);\n\n      return connection.confirmTransaction({\n        signature,\n        ...latestBlockhash,\n      });\n    });\n\n    allPromises.push(transactions.flat());\n  }\n\n  await Promise.all(allPromises);\n}\n\nasync function main() {\n  const dlmmPool = await DLMM.create(connection, poolAddress, {\n    cluster: \"devnet\",\n  });\n\n  await getActiveBin(dlmmPool);\n  await createBalancePosition(dlmmPool);\n  await createImbalancePosition(dlmmPool);\n  await createOneSidePosition(dlmmPool);\n  await getPositionsState(dlmmPool);\n  await addLiquidityToExistingPosition(dlmmPool);\n  await removePositionLiquidity(dlmmPool);\n  await swap(dlmmPool);\n  await initializePositionAndAddLiquidityByStrategyParallelExecution(dlmmPool);\n}\n\nmain();\n"
  },
  {
    "path": "ts-client/src/examples/fetch_lb_pair_lock_info.ts",
    "content": "import { Connection, Keypair, PublicKey, Transaction } from \"@solana/web3.js\";\nimport { DLMM } from \"../dlmm\";\n\nasync function fetchLbPairLockInfoExample() {\n  const poolAddress = new PublicKey(\n    \"9DiruRpjnAnzhn6ts5HGLouHtJrT1JGsPbXNYCrFz2ad\"\n  );\n\n  let rpc = process.env.RPC || \"https://api.mainnet-beta.solana.com\";\n  const connection = new Connection(rpc, \"finalized\");\n  const dlmmPool = await DLMM.create(connection, poolAddress, {\n    cluster: \"mainnet-beta\",\n  });\n\n  const lbPairLockInfo = await dlmmPool.getLbPairLockInfo();\n  console.log(lbPairLockInfo);\n}\n\nfetchLbPairLockInfoExample();\n"
  },
  {
    "path": "ts-client/src/examples/get_oracle.ts",
    "content": "import { Connection, PublicKey, SYSVAR_CLOCK_PUBKEY } from \"@solana/web3.js\";\nimport { DLMM } from \"../dlmm\";\nimport { IDynamicOracle } from \"../dlmm/helpers\";\nimport { Clock, ClockLayout } from \"../dlmm/types\";\nimport BN from \"bn.js\";\n\nconst poolAddress = new PublicKey(\n  \"5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6\",\n);\n\nasync function main() {\n  const rpc = process.env.RPC || \"https://api.mainnet-beta.solana.com\";\n  const connection = new Connection(rpc, \"finalized\");\n  const dlmmPool = await DLMM.create(connection, poolAddress, {\n    cluster: \"mainnet-beta\",\n  });\n\n  const oracle: IDynamicOracle = await dlmmPool.getOracle();\n\n  // Current on-chain timestamp from clock sysvar\n  const clockAccInfo = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);\n  const clock: Clock = ClockLayout.decode(clockAccInfo.data);\n  const currentTimestamp = clock.unixTimestamp;\n\n  // Max observable duration\n  const maxDuration = oracle.getMaxDuration(currentTimestamp);\n  console.log(\"Max oracle duration (seconds):\", maxDuration.toString());\n\n  if (maxDuration.isZero()) {\n    console.log(\"Oracle has no observations yet.\");\n    return;\n  }\n\n  // TWAP active bin ID from earliest to now\n  const twapActiveId = oracle.getActiveId(currentTimestamp);\n  console.log(\"TWAP active bin ID:\", twapActiveId?.value.toString());\n  console.log(\"TWAP duration (seconds):\", twapActiveId?.duration.toString());\n\n  // TWAP UI price over the last 10 minutes (or max duration if shorter)\n  const tenMinutes = new BN(600);\n  const duration = BN.min(tenMinutes, maxDuration);\n  const timePoint0 = currentTimestamp.sub(duration);\n  const timePoint1 = currentTimestamp;\n\n  const twapPrice = oracle.getUiPriceByTime(timePoint0, timePoint1);\n  if (twapPrice) {\n    console.log(\n      `TWAP UI price (last ${duration.toString()}s):`,\n      twapPrice.value.toString(),\n    );\n  } else {\n    console.log(\"Not enough oracle data for the requested time range.\");\n  }\n\n  // Query TWAP for each quarter of the observable window [currentTimestamp - maxDuration, currentTimestamp].\n  // To extend the observable window, use dlmmPool.increaseOracleLength(lengthToAdd, funder)\n  // to allocate more observation slots. A larger oracle stores more history, enabling TWAP\n  // queries over longer time ranges.\n  const windowStart = currentTimestamp.sub(maxDuration);\n  const windows = 4;\n  const quarterDuration = maxDuration.div(new BN(windows));\n\n  for (let i = 0; i < windows; i++) {\n    const from = windowStart.add(quarterDuration.mul(new BN(i)));\n    const to = windowStart.add(quarterDuration.mul(new BN(i + 1)));\n\n    const windowPrice = oracle.getUiPriceByTime(from, to);\n    if (windowPrice) {\n      console.log(\n        `Window ${i + 1}/${windows} [${from.toString()} -> ${to.toString()}] (${windowPrice.duration.toString()}s): ${windowPrice.value.toString()}`,\n      );\n    } else {\n      console.log(\n        `Window ${i + 1}/${windows} [${from.toString()} -> ${to.toString()}]: insufficient oracle data`,\n      );\n    }\n  }\n}\n\nmain();\n"
  },
  {
    "path": "ts-client/src/examples/initialize_bin_arrays.ts",
    "content": "import { Connection, Keypair, PublicKey, Transaction } from \"@solana/web3.js\";\nimport { DLMM } from \"../dlmm\";\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { getBinArraysRequiredByPositionRange } from \"../dlmm/helpers\";\nimport { simulateTransaction } from \"@coral-xyz/anchor/dist/cjs/utils/rpc\";\n\nasync function initializeBinArrayExample() {\n  const funder = Keypair.fromSecretKey(\n    new Uint8Array(JSON.parse(process.env.WALLET))\n  );\n\n  console.log(\"Connected wallet\", funder.publicKey.toBase58());\n\n  const poolAddress = new PublicKey(\n    \"BfxJcifavkCgznhvAtLsBHQpyNwaTMs2cR986qbH4fPh\"\n  );\n\n  let rpc = \"https://api.mainnet-beta.solana.com\";\n  const connection = new Connection(rpc, \"finalized\");\n  const dlmmPool = await DLMM.create(connection, poolAddress, {\n    cluster: \"mainnet-beta\",\n  });\n\n  const fromUIPrice = 1.0;\n  const toUIPrice = 4.0;\n\n  const toLamportMultiplier = new Decimal(\n    10 ** (dlmmPool.tokenX.mint.decimals - dlmmPool.tokenX.mint.decimals)\n  );\n\n  const minPricePerLamport = new Decimal(fromUIPrice).mul(toLamportMultiplier);\n  const maxPricePerLamport = new Decimal(toUIPrice).mul(toLamportMultiplier);\n\n  const minBinId = new BN(\n    DLMM.getBinIdFromPrice(minPricePerLamport, dlmmPool.lbPair.binStep, false)\n  );\n\n  const maxBinId = new BN(\n    DLMM.getBinIdFromPrice(maxPricePerLamport, dlmmPool.lbPair.binStep, false)\n  );\n\n  const binArraysRequired = getBinArraysRequiredByPositionRange(\n    poolAddress,\n    minBinId,\n    maxBinId,\n    dlmmPool.program.programId\n  );\n\n  console.log(binArraysRequired);\n\n  const initializeBinArrayIxs = await dlmmPool.initializeBinArrays(\n    binArraysRequired.map((b) => b.index),\n    funder.publicKey\n  );\n\n  const { blockhash, lastValidBlockHeight } =\n    await connection.getLatestBlockhash();\n\n  const transaction = new Transaction({\n    blockhash,\n    lastValidBlockHeight,\n    feePayer: funder.publicKey,\n  }).add(...initializeBinArrayIxs);\n\n  transaction.sign(funder);\n\n  const simulationResult = await simulateTransaction(connection, transaction, [\n    funder,\n  ]);\n\n  console.log(simulationResult);\n}\n\ninitializeBinArrayExample();\n"
  },
  {
    "path": "ts-client/src/examples/swap_quote.ts",
    "content": "import { Connection, PublicKey } from \"@solana/web3.js\";\nimport { DLMM } from \"../dlmm\";\nimport BN from \"bn.js\";\n\nasync function swapQuote(\n  poolAddress: PublicKey,\n  swapAmount: BN,\n  swapYtoX: boolean,\n  isPartialFill: boolean,\n  maxExtraBinArrays: number = 0\n) {\n  let rpc = \"https://api.mainnet-beta.solana.com\";\n  const connection = new Connection(rpc, \"finalized\");\n  const dlmmPool = await DLMM.create(connection, poolAddress, {\n    cluster: \"mainnet-beta\",\n  });\n\n  const binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX);\n\n  const swapQuote = dlmmPool.swapQuote(\n    swapAmount,\n    swapYtoX,\n    new BN(10),\n    binArrays,\n    isPartialFill,\n    maxExtraBinArrays\n  );\n  console.log(\"🚀 ~ swapQuote:\", swapQuote);\n  console.log(\n    \"consumedInAmount: %s, outAmount: %s\",\n    swapQuote.consumedInAmount.toString(),\n    swapQuote.outAmount.toString()\n  );\n}\n\nasync function main() {\n  await swapQuote(\n    new PublicKey(\"5BKxfWMbmYBAEWvyPZS9esPducUba9GqyMjtLCfbaqyF\"),\n    new BN(5_000 * 10 ** 6),\n    true,\n    false,\n    3\n  );\n}\n\nmain();\n"
  },
  {
    "path": "ts-client/src/index.ts",
    "content": "import { DLMM } from \"./dlmm\";\n\nexport default DLMM;\nexport * from \"./dlmm/helpers\";\nexport * from \"./dlmm/types\";\nexport * from \"./dlmm/error\";\nexport * from \"./dlmm/constants\";\nexport * from \"./dlmm/idl/idl\";\nexport { default as IDL } from \"./dlmm/idl/idl.json\";\nexport * from \"./dlmm/helpers/accountFilters\";\n"
  },
  {
    "path": "ts-client/src/server/index.ts",
    "content": "import { Connection, PublicKey } from \"@solana/web3.js\";\nimport express from \"express\";\nimport { DLMM } from \"../dlmm\";\nimport { BinArrayAccount, LbPosition } from \"../dlmm/types\";\nimport { BN } from \"bn.js\";\nimport { convertToPosition } from \"./utils\";\nimport { FunctionType } from \"../dlmm/constants\";\n\ndeclare global {\n  namespace Express {\n    export interface Request {\n      pool: PublicKey;\n      rpc: string;\n      connect: Connection;\n    }\n  }\n}\n\nconst app = express();\napp.use(express.urlencoded());\napp.use(express.json());\napp.use(function (req, res, next) {\n  console.log(req.method, req.url);\n  console.log(req.body);\n\n  req.pool = new PublicKey(req.headers.pool as string);\n  req.rpc = req.headers.rpc as string;\n  req.connect = new Connection(req.rpc, \"finalized\");\n  next();\n});\n\napp.get(\"/\", (req, res) => {\n  res.send(\"Hello World!\");\n});\n\nfunction safeStringify(obj: Record<string, any>): string {\n  const seen = new WeakSet();\n  return JSON.stringify(obj, (key, value) => {\n    if (typeof value === \"bigint\") {\n      return value.toString();\n    }\n    if (typeof value === \"object\" && value !== null) {\n      if (seen.has(value)) {\n        return;\n      }\n      seen.add(value);\n    }\n    return value;\n  });\n}\n\napp.get(\"/dlmm/create\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    return res.status(200).send(safeStringify(dlmm));\n  } catch (error) {\n    return res.status(400).send(error);\n  }\n});\n\n// app.get('/dlmm/create-multiple', async (req, res) => {\n//   try {\n//     const poolAddresses = req.pool;\n//     const dlmm = await DLMM.createMultiple(req.connect, poolAddresses);\n//     return res.status(200).send(safeStringify(dlmm));\n//   }\n//   catch (error) {\n//     return res.status(400).send(error)\n//   }\n// })\n\napp.post(\"/dlmm/get-all-lb-pair-positions-by-user\", async (req, res) => {\n  try {\n    const userPublicKey = new PublicKey(req.body.user);\n    const positions = await DLMM.getAllLbPairPositionsByUser(\n      req.connect,\n      userPublicKey\n    );\n    return res.status(200).send(safeStringify(Object.fromEntries(positions)));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\n  \"/dlmm/create-customizable-permissionless-lb-pair\",\n  async (req, res) => {\n    try {\n      const binStep = new BN(req.body.binStep);\n      const tokenX = new PublicKey(req.body.tokenX);\n      const tokenY = new PublicKey(req.body.tokenY);\n      const activeId = new BN(req.body.activeId);\n      const feeBps = new BN(req.body.feeBps);\n      const activationType = parseInt(req.body.activationType);\n      const hasAlphaVault = Boolean(req.body.hasAlphaVault);\n      const creatorKey = new PublicKey(req.body.creatorKey);\n      const functionType = FunctionType.LiquidityMining;\n      const activationPoint =\n        req.body.activationPoint !== null\n          ? new BN(req.body.activationPoint)\n          : null;\n      const transaction = DLMM.createCustomizablePermissionlessLbPair(\n        req.connect,\n        binStep,\n        tokenX,\n        tokenY,\n        activeId,\n        feeBps,\n        activationType,\n        hasAlphaVault,\n        creatorKey,\n        functionType,\n        activationPoint\n      );\n      return res.status(200).send(safeStringify(transaction));\n    } catch (error) {\n      console.log(error);\n      return res.status(400).send(error);\n    }\n  }\n);\n\napp.get(\"/dlmm/get-active-bin\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const activeBin = await dlmm.getActiveBin();\n    return res.status(200).send(safeStringify(activeBin));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/from-price-per-lamport\", async (req, res) => {\n  try {\n    const pricePerLamport = req.body.price;\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const from = dlmm.fromPricePerLamport(pricePerLamport);\n    return res.status(200).send({ price: from });\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/to-price-per-lamport\", async (req, res) => {\n  try {\n    const price = req.body.price;\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const to = dlmm.toPricePerLamport(price);\n    return res.status(200).send({ price: to });\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\n  \"/dlmm/initialize-position-and-add-liquidity-by-strategy\",\n  async (req, res) => {\n    try {\n      const positionPublicKey = req.body.positionPubKey;\n      const userPublicKey = req.body.userPublicKey;\n      const totalXAmount = new BN(req.body.totalXAmount);\n      const totalYAmount = new BN(req.body.totalYAmount);\n      const maxBinId = req.body.maxBinId;\n      const minBinId = req.body.minBinId;\n      const strategyType = parseInt(req.body.strategyType);\n      const data = {\n        positionPubKey: new PublicKey(positionPublicKey),\n        user: new PublicKey(userPublicKey),\n        totalXAmount,\n        totalYAmount,\n        strategy: {\n          maxBinId,\n          minBinId,\n          strategyType,\n        },\n      };\n\n      const poolAddress = req.pool;\n      const dlmm = await DLMM.create(req.connect, poolAddress);\n      const position = await dlmm.initializePositionAndAddLiquidityByStrategy(\n        data\n      );\n      return res.status(200).send(safeStringify(position));\n    } catch (error) {\n      console.log(error);\n      return res.status(400).send(error);\n    }\n  }\n);\n\napp.post(\"/dlmm/add-liquidity-by-strategy\", async (req, res) => {\n  try {\n    const positionPublicKey = req.body.positionPubKey;\n    const userPublicKey = req.body.userPublicKey;\n    const totalXAmount = new BN(req.body.totalXAmount);\n    const totalYAmount = new BN(req.body.totalYAmount);\n    const maxBinId = req.body.maxBinId;\n    const minBinId = req.body.minBinId;\n    const strategyType = parseInt(req.body.strategyType);\n    const data = {\n      positionPubKey: new PublicKey(positionPublicKey),\n      user: new PublicKey(userPublicKey),\n      totalXAmount,\n      totalYAmount,\n      strategy: {\n        maxBinId,\n        minBinId,\n        strategyType,\n      },\n    };\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const position = await dlmm.addLiquidityByStrategy(data);\n    return res.status(200).send(safeStringify(position));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-positions-by-user-and-lb-pair\", async (req, res) => {\n  try {\n    const userPublicKey = req.body.userPublicKey;\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const positions = await dlmm.getPositionsByUserAndLbPair(\n      new PublicKey(userPublicKey)\n    );\n    return res.status(200).send(safeStringify(positions));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/remove-liquidity\", async (req, res) => {\n  try {\n    const positionPublicKey = req.body.positionPubKey;\n    const userPublicKey = req.body.userPublicKey;\n    const binIds = req.body.binIds;\n    const bps = new BN(req.body.bps);\n    const shouldClaimAndClose = req.body.shouldClaimAndClose;\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n\n    const fromBinId = Math.min(...binIds);\n    const toBinId = Math.max(...binIds);\n\n    const removeTxs = await dlmm.removeLiquidity({\n      position: new PublicKey(positionPublicKey),\n      user: new PublicKey(userPublicKey),\n      fromBinId,\n      toBinId,\n      bps,\n      shouldClaimAndClose,\n    });\n    return res.status(200).send(safeStringify(removeTxs));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/close-position\", async (req, res) => {\n  try {\n    const owner = new PublicKey(req.body.owner);\n    const position = convertToPosition(req.body.position);\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const closeTx = await dlmm.closePosition({ owner, position });\n    return res.status(200).send(safeStringify(closeTx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-bin-array-for-swap\", async (req, res) => {\n  try {\n    const swapYtoX = Boolean(req.body.swapYtoX);\n    const count = parseInt(req.body.count);\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const binArray = (await dlmm.getBinArrayForSwap(swapYtoX, count)).map(\n      (bin) => ({\n        publicKey: bin.publicKey,\n        account: {\n          ...bin.account,\n          index: bin.account.index.toString(\"hex\"),\n          bins: bin.account.bins.map((b) => ({\n            amountX: b.amountX.toString(\"hex\"),\n            amountY: b.amountY.toString(\"hex\"),\n            feeAmountXPerTokenStored:\n              b.feeAmountXPerTokenStored.toString(\"hex\"),\n            feeAmountYPerTokenStored:\n              b.feeAmountYPerTokenStored.toString(\"hex\"),\n            liquiditySupply: b.liquiditySupply.toString(\"hex\"),\n            price: b.price.toString(\"hex\"),\n            rewardPerTokenStored: b.functionBytes.map((r) => r.toString(\"hex\")),\n          })),\n        },\n      })\n    );\n\n    return res.status(200).send(safeStringify(binArray));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/swap-quote\", async (req, res) => {\n  try {\n    const swapYtoX = req.body.swapYToX;\n    const swapAmount = new BN(req.body.amount);\n    const allowedSlippage = new BN(req.body.allowedSlippage);\n    const binArrays: BinArrayAccount[] = req.body.binArrays.map((bin) => ({\n      publicKey: new PublicKey(bin[\"publicKey\"]),\n      account: {\n        ...bin[\"account\"],\n        index: new BN(bin[\"account\"][\"index\"], 16),\n        lbPair: new PublicKey(bin[\"account\"][\"lbPair\"]),\n        bins: bin[\"account\"][\"bins\"].map((b) => ({\n          amountX: new BN(b[\"amountX\"], 16),\n          amountY: new BN(b[\"amountY\"], 16),\n          feeAmountXPerTokenStored: new BN(b[\"feeAmountXPerTokenStored\"], 16),\n          feeAmountYPerTokenStored: new BN(b[\"feeAmountYPerTokenStored\"], 16),\n          liquiditySupply: new BN(b[\"liquiditySupply\"], 16),\n          price: new BN(b[\"price\"], 16),\n          rewardPerTokenStored: b[\"rewardPerTokenStored\"].map(\n            (r) => new BN(r, 16)\n          ),\n        })),\n      },\n    }));\n    const isPartialFill = req.body.isPartialFilled;\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    // const binArrays = await dlmm.getBinArrayForSwap(swapYtoX, 10); // TEMP SOLUTION\n    const quote = dlmm.swapQuote(\n      swapAmount,\n      swapYtoX,\n      allowedSlippage,\n      binArrays,\n      isPartialFill\n    );\n    return res.status(200).send(safeStringify(quote));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/swap\", async (req, res) => {\n  try {\n    const inToken = new PublicKey(req.body.inToken);\n    const outToken = new PublicKey(req.body.outToken);\n    const inAmount = new BN(req.body.inAmount);\n    const minOutAmount = new BN(req.body.minOutAmount);\n    const lbPair = new PublicKey(req.body.lbPair);\n    const user = new PublicKey(req.body.userPublicKey);\n    const binArraysPubkey = req.body.binArrays.map(\n      (bin: string) => new PublicKey(bin)\n    );\n\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const swap = await dlmm.swap({\n      inToken,\n      outToken,\n      inAmount,\n      minOutAmount,\n      lbPair,\n      user,\n      binArraysPubkey,\n    });\n    return res.status(200).send(safeStringify(swap));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.get(\"/dlmm/refetch-states\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    await dlmm.refetchStates();\n    return res.status(200).send(\"Refetched states successfully\");\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.get(\"/dlmm/get-bin-arrays\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const binArray = (await dlmm.getBinArrays()).map((bin) => ({\n      publicKey: bin.publicKey,\n      account: {\n        ...bin.account,\n        index: bin.account.index.toString(\"hex\"),\n        bins: bin.account.bins.map((b) => ({\n          amountX: b.amountX.toString(\"hex\"),\n          amountY: b.amountY.toString(\"hex\"),\n          feeAmountXPerTokenStored: b.feeAmountXPerTokenStored.toString(\"hex\"),\n          feeAmountYPerTokenStored: b.feeAmountYPerTokenStored.toString(\"hex\"),\n          liquiditySupply: b.liquiditySupply.toString(\"hex\"),\n          price: b.price.toString(\"hex\"),\n          rewardPerTokenStored: b.functionBytes.map((r) => r.toString(\"hex\")),\n        })),\n      },\n    }));\n    return res.status(200).send(safeStringify(binArray));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.get(\"/dlmm/get-fee-info\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const feeInfo = dlmm.getFeeInfo();\n    return res.status(200).send(safeStringify(feeInfo));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.get(\"/dlmm/get-dynamic-fee\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const dynamicFee = dlmm.getDynamicFee();\n    return res.status(200).send({ fee: dynamicFee.toString() });\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-bin-id-from-price\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const price = req.body.price;\n    const min = Boolean(req.body.min);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const binId = dlmm.getBinIdFromPrice(price, min);\n    return res.status(200).send({ binId });\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-bins-around-active-bin\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const numberOfBinsToTheLeft = parseInt(req.body.numberOfBinsToTheLeft);\n    const numberOfBinsToTheRight = parseInt(req.body.numberOfBinsToTheRight);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const bins = await dlmm.getBinsAroundActiveBin(\n      numberOfBinsToTheLeft,\n      numberOfBinsToTheRight\n    );\n    return res.status(200).send(safeStringify(bins));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-bins-between-min-and-max-price\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const minPrice = req.body.minPrice;\n    const maxPrice = req.body.maxPrice;\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const bins = await dlmm.getBinsBetweenMinAndMaxPrice(minPrice, maxPrice);\n    return res.status(200).send(safeStringify(bins));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/get-bins-between-lower-and-upper-bound\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const lowerBound = parseInt(req.body.lowerBound);\n    const upperBound = parseInt(req.body.upperBound);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const bins = await dlmm.getBinsBetweenLowerAndUpperBound(\n      lowerBound,\n      upperBound\n    );\n    return res.status(200).send(safeStringify(bins));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/claim-lm-reward\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const owner = new PublicKey(req.body.owner);\n    const position = convertToPosition(req.body.position);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const tx = await dlmm.claimLMReward({ owner, position });\n    return res.status(200).send(safeStringify(tx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/claim-all-lm-rewards\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const owner = new PublicKey(req.body.owner);\n    const positions = req.body.positions.map(convertToPosition);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const tx = await dlmm.claimAllLMRewards({ owner, positions });\n    return res.status(200).send(safeStringify(tx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/claim-swap-fee\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const owner = new PublicKey(req.body.owner);\n    const position = convertToPosition(req.body.position);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const tx = await dlmm.claimSwapFee({ owner, position });\n    return res.status(200).send(safeStringify(tx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/claim-all-swap-fee\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const owner = new PublicKey(req.body.owner);\n    const positions = req.body.positions.map(convertToPosition);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const tx = await dlmm.claimAllSwapFee({ owner, positions });\n    return res.status(200).send(safeStringify(tx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.post(\"/dlmm/claim-all-rewards\", async (req, res) => {\n  try {\n    const poolAddress = req.pool;\n    const owner = new PublicKey(req.body.owner);\n    const positions = req.body.positions.map(convertToPosition);\n\n    const dlmm = await DLMM.create(req.connect, poolAddress);\n    const tx = await dlmm.claimAllRewards({ owner, positions });\n    return res.status(200).send(safeStringify(tx));\n  } catch (error) {\n    console.log(error);\n    return res.status(400).send(error);\n  }\n});\n\napp.listen(3000, () => {\n  console.log(\"Server is running on http://localhost:3000\");\n});\n"
  },
  {
    "path": "ts-client/src/server/utils.ts",
    "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { LbPosition } from \"../dlmm/types\";\nimport BN from \"bn.js\";\n\nexport const convertToPosition = (rawPosition: any): LbPosition => {\n    return {\n        ...rawPosition,\n        publicKey: new PublicKey(rawPosition.publicKey),\n        positionData: {\n          ...rawPosition.positionData,\n          lastUpdatedAt: new BN(rawPosition.positionData.lastUpdatedAt, 16),\n          feeX: new BN(rawPosition.positionData.feeX, 16),\n          feeY: new BN(rawPosition.positionData.feeY, 16),\n          rewardOne: new BN(rawPosition.positionData.rewardOne, 16),\n          rewardTwo: new BN(rawPosition.positionData.rewardTwo, 16),\n          feeOwner: new PublicKey(rawPosition.positionData.feeOwner),\n          totalClaimedFeeXAmount: new BN(rawPosition.positionData.totalClaimedFeeXAmount, 16),\n          totalClaimedFeeYAmount: new BN(rawPosition.positionData.totalClaimedFeeYAmount, 16),\n        },\n      }\n}"
  },
  {
    "path": "ts-client/src/test/bug_fix.test.ts",
    "content": "import {\n  createAssociatedTokenAccountIdempotent,\n  createAssociatedTokenAccountIdempotentInstruction,\n  createMint,\n  getAssociatedTokenAddressSync,\n  mintTo,\n  NATIVE_MINT,\n  TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  PublicKey,\n  sendAndConfirmTransaction,\n  SystemProgram,\n  Transaction,\n} from \"@solana/web3.js\";\nimport { BN } from \"bn.js\";\nimport fs from \"fs\";\nimport { DLMM } from \"../dlmm\";\nimport { LBCLMM_PROGRAM_IDS } from \"../dlmm/constants\";\nimport {\n  binIdToBinArrayIndex,\n  deriveBinArray,\n  deriveCustomizablePermissionlessLbPair,\n  deriveOperator,\n  deriveRewardVault,\n} from \"../dlmm/helpers\";\nimport { StrategyType } from \"../dlmm/types\";\nimport {\n  createTestProgram,\n  createWhitelistOperator,\n  OperatorPermission,\n  swap,\n} from \"./helper\";\n\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\n\nconst adminKeypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\",\n);\nconst adminKeypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(adminKeypairBuffer)),\n);\nconst programId = new PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\n\nasync function createMintAndPair(\n  mintA: Keypair | PublicKey,\n  mintB: Keypair | PublicKey,\n  keypair: Keypair,\n) {\n  for (const mint of [mintA, mintB]) {\n    if (mint instanceof Keypair) {\n      await createMint(connection, keypair, keypair.publicKey, null, 9, mint);\n\n      const userToken = getAssociatedTokenAddressSync(\n        mint.publicKey,\n        keypair.publicKey,\n      );\n\n      await createAssociatedTokenAccountIdempotent(\n        connection,\n        keypair,\n        mint.publicKey,\n        keypair.publicKey,\n      );\n\n      await mintTo(\n        connection,\n        keypair,\n        mint.publicKey,\n        userToken,\n        keypair,\n        BigInt(\"1000000000000\"),\n      );\n    }\n  }\n\n  const binStep = new BN(10);\n  const activeId = new BN(0);\n  const feeBps = new BN(100);\n\n  const initTx = await DLMM.createCustomizablePermissionlessLbPair2(\n    connection,\n    binStep,\n    mintA instanceof Keypair ? mintA.publicKey : mintA,\n    mintB instanceof Keypair ? mintB.publicKey : mintB,\n    activeId,\n    feeBps,\n    1,\n    false,\n    keypair.publicKey,\n    null,\n    null,\n    {\n      cluster: \"localhost\",\n    },\n  );\n\n  const userTokenX = getAssociatedTokenAddressSync(\n    mintA instanceof Keypair ? mintA.publicKey : mintA,\n    keypair.publicKey,\n  );\n\n  const userTokenY = getAssociatedTokenAddressSync(\n    mintB instanceof Keypair ? mintB.publicKey : mintB,\n    keypair.publicKey,\n  );\n\n  const initUserTokenXIx = createAssociatedTokenAccountIdempotentInstruction(\n    keypair.publicKey,\n    userTokenX,\n    keypair.publicKey,\n    mintA instanceof Keypair ? mintA.publicKey : mintA,\n  );\n\n  const initUserTokenYIx = createAssociatedTokenAccountIdempotentInstruction(\n    keypair.publicKey,\n    userTokenY,\n    keypair.publicKey,\n    mintB instanceof Keypair ? mintB.publicKey : mintB,\n  );\n\n  const latestBlockhashInfo = await connection.getLatestBlockhash();\n  const tx = new Transaction({\n    ...latestBlockhashInfo,\n  }).add(initUserTokenXIx, initUserTokenYIx, ...initTx.instructions);\n\n  tx.sign(keypair);\n  const serializedTx = tx.serialize();\n\n  const txSig = await connection.sendRawTransaction(serializedTx);\n  await connection.confirmTransaction(txSig, \"confirmed\");\n\n  const pairAddress = await deriveCustomizablePermissionlessLbPair(\n    mintA instanceof Keypair ? mintA.publicKey : mintA,\n    mintB instanceof Keypair ? mintB.publicKey : mintB,\n    new PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]),\n  )[0];\n\n  return pairAddress;\n}\n\ndescribe(\"Bug fixes\", () => {\n  it(\"Rebalance wrap more tokens than needed\", async () => {\n    const user = Keypair.generate();\n\n    let txSig = await connection.requestAirdrop(user.publicKey, 5e9);\n    await connection.confirmTransaction(txSig, \"confirmed\");\n\n    const mintA = Keypair.generate();\n    const mintB = NATIVE_MINT;\n\n    const pairAddress = await createMintAndPair(mintA, mintB, user);\n    const dlmm = await DLMM.create(connection, pairAddress, {\n      cluster: \"localhost\",\n    });\n\n    const positionKeypair = Keypair.generate();\n\n    const minBinId = dlmm.lbPair.activeId - 59;\n    const maxBinId = dlmm.lbPair.activeId - 1;\n\n    const initPositionTx = await dlmm.createEmptyPosition({\n      positionPubKey: positionKeypair.publicKey,\n      minBinId,\n      maxBinId,\n      user: user.publicKey,\n    });\n\n    await initPositionTx.sign(user, positionKeypair);\n    txSig = await connection.sendRawTransaction(initPositionTx.serialize());\n    await connection.confirmTransaction(txSig, \"confirmed\");\n\n    const addLiquidityTxs = await dlmm.addLiquidityByStrategyChunkable({\n      positionPubKey: positionKeypair.publicKey,\n      totalXAmount: new BN(0),\n      totalYAmount: new BN(4e9),\n      strategy: {\n        minBinId,\n        maxBinId,\n        strategyType: StrategyType.Curve,\n      },\n      user: user.publicKey,\n      slippage: 0,\n    });\n\n    expect(addLiquidityTxs.length).toBe(1);\n\n    const addLiquidityTx = addLiquidityTxs[0];\n    await addLiquidityTx.sign(user);\n\n    const result = await connection.simulateTransaction(addLiquidityTx, [user]);\n    expect(result.value.err).toBeNull();\n  });\n\n  it(\"removeLiquidity with shouldClaimAndClose when fees exist in empty bins\", async () => {\n    const user = Keypair.generate();\n    let txSig = await connection.requestAirdrop(user.publicKey, 5e9);\n    await connection.confirmTransaction(txSig, \"confirmed\");\n\n    const mintA = Keypair.generate();\n    const mintB = Keypair.generate();\n\n    const pairAddress = await createMintAndPair(mintA, mintB, user);\n    const dlmm = await DLMM.create(connection, pairAddress, {\n      cluster: \"localhost\",\n    });\n\n    const positionKeypair = Keypair.generate();\n    const minBinId = dlmm.lbPair.activeId - 5;\n    const maxBinId = dlmm.lbPair.activeId + 5;\n\n    const initPositionTx = await dlmm.createEmptyPosition({\n      positionPubKey: positionKeypair.publicKey,\n      minBinId,\n      maxBinId,\n      user: user.publicKey,\n    });\n    await sendAndConfirmTransaction(connection, initPositionTx, [\n      user,\n      positionKeypair,\n    ]);\n\n    const addLiquidityTxs = await dlmm.addLiquidityByStrategyChunkable({\n      positionPubKey: positionKeypair.publicKey,\n      totalXAmount: new BN(100e9),\n      totalYAmount: new BN(100e9),\n      strategy: {\n        minBinId,\n        maxBinId,\n        strategyType: StrategyType.Spot,\n      },\n      user: user.publicKey,\n      slippage: 0,\n    });\n    for (const tx of addLiquidityTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    await swap(true, new BN(10e9), dlmm, user);\n    await swap(false, new BN(10e9), dlmm, user);\n\n    await dlmm.refetchStates();\n    const removeTxs = await dlmm.removeLiquidity({\n      user: user.publicKey,\n      position: positionKeypair.publicKey,\n      fromBinId: minBinId,\n      toBinId: maxBinId,\n      bps: new BN(10_000),\n      shouldClaimAndClose: false,\n    });\n    for (const tx of removeTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    await dlmm.refetchStates();\n    const { userPositions } = await dlmm.getPositionsByUserAndLbPair(\n      user.publicKey,\n    );\n    const pos = userPositions.find((p) =>\n      p.publicKey.equals(positionKeypair.publicKey),\n    );\n    // position has no liquidity\n    expect(Number(pos.positionData.totalXAmount)).toBe(0);\n    expect(Number(pos.positionData.totalYAmount)).toBe(0);\n\n    const claimAndCloseTxs = await dlmm.removeLiquidity({\n      user: user.publicKey,\n      position: positionKeypair.publicKey,\n      fromBinId: minBinId,\n      toBinId: maxBinId,\n      bps: new BN(10_000),\n      shouldClaimAndClose: true,\n    });\n    for (const tx of claimAndCloseTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    const positionAccount = await connection.getAccountInfo(\n      positionKeypair.publicKey,\n    );\n    expect(positionAccount).toBeNull();\n  });\n\n  it(\"removeLiquidity with shouldClaimAndClose when rewards exist in empty bins\", async () => {\n    const user = Keypair.generate();\n    let txSig = await connection.requestAirdrop(user.publicKey, 5e9);\n    await connection.confirmTransaction(txSig, \"confirmed\");\n    txSig = await connection.requestAirdrop(adminKeypair.publicKey, 5e9);\n    await connection.confirmTransaction(txSig, \"confirmed\");\n\n    const mintA = Keypair.generate();\n    const mintB = Keypair.generate();\n\n    const rewardMintKeypair = Keypair.generate();\n    await createMint(\n      connection,\n      adminKeypair,\n      adminKeypair.publicKey,\n      null,\n      9,\n      rewardMintKeypair,\n    );\n    const adminRewardAta = await createAssociatedTokenAccountIdempotent(\n      connection,\n      adminKeypair,\n      rewardMintKeypair.publicKey,\n      adminKeypair.publicKey,\n    );\n    await mintTo(\n      connection,\n      adminKeypair,\n      rewardMintKeypair.publicKey,\n      adminRewardAta,\n      adminKeypair,\n      BigInt(\"1000000000000\"),\n    );\n\n    const pairAddress = await createMintAndPair(mintA, mintB, user);\n    let dlmm = await DLMM.create(connection, pairAddress, {\n      cluster: \"localhost\",\n    });\n\n    await createWhitelistOperator(\n      connection,\n      adminKeypair,\n      adminKeypair.publicKey,\n      [OperatorPermission.InitializeReward],\n      programId,\n    );\n\n    const program = createTestProgram(connection, programId, adminKeypair);\n    const rewardIndex = new BN(0);\n    const rewardDuration = new BN(300);\n\n    const [rewardVault] = deriveRewardVault(\n      pairAddress,\n      rewardIndex,\n      programId,\n    );\n\n    const operatorPda = deriveOperator(adminKeypair.publicKey, programId);\n\n    await program.methods\n      .initializeReward(rewardIndex, rewardDuration, adminKeypair.publicKey)\n      .accountsPartial({\n        lbPair: pairAddress,\n        rewardMint: rewardMintKeypair.publicKey,\n        rewardVault,\n        signer: adminKeypair.publicKey,\n        tokenBadge: null,\n        tokenProgram: TOKEN_PROGRAM_ID,\n        systemProgram: SystemProgram.programId,\n        operator: operatorPda,\n      })\n      .signers([adminKeypair])\n      .rpc();\n\n    const activeBinArrayIndex = binIdToBinArrayIndex(\n      new BN(dlmm.lbPair.activeId),\n    );\n    const activeBinArrayKey = deriveBinArray(\n      pairAddress,\n      activeBinArrayIndex,\n      programId,\n    )[0];\n\n    const initBinArrayIxs = await dlmm.initializeBinArrays(\n      [activeBinArrayIndex],\n      adminKeypair.publicKey,\n    );\n    if (initBinArrayIxs.length > 0) {\n      const { blockhash, lastValidBlockHeight } =\n        await connection.getLatestBlockhash(\"confirmed\");\n      const initBinTx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n      }).add(...initBinArrayIxs);\n      await sendAndConfirmTransaction(connection, initBinTx, [adminKeypair]);\n    }\n\n    const fundingAmount = new BN(\"1000000000000\");\n    await program.methods\n      .fundReward(rewardIndex, fundingAmount, true, {\n        slices: [],\n      })\n      .accountsPartial({\n        lbPair: pairAddress,\n        rewardMint: rewardMintKeypair.publicKey,\n        rewardVault,\n        funder: adminKeypair.publicKey,\n        binArray: activeBinArrayKey,\n        funderTokenAccount: adminRewardAta,\n        tokenProgram: TOKEN_PROGRAM_ID,\n      })\n      .signers([adminKeypair])\n      .rpc();\n\n    // Re-create DLMM so it picks up the new reward mint in lbPair state\n    dlmm = await DLMM.create(connection, pairAddress, {\n      cluster: \"localhost\",\n    });\n\n    const positionKeypair = Keypair.generate();\n    const minBinId = dlmm.lbPair.activeId - 5;\n    const maxBinId = dlmm.lbPair.activeId + 5;\n\n    const initPositionTx = await dlmm.createEmptyPosition({\n      positionPubKey: positionKeypair.publicKey,\n      minBinId,\n      maxBinId,\n      user: user.publicKey,\n    });\n    await sendAndConfirmTransaction(connection, initPositionTx, [\n      user,\n      positionKeypair,\n    ]);\n\n    const addLiquidityTxs = await dlmm.addLiquidityByStrategyChunkable({\n      positionPubKey: positionKeypair.publicKey,\n      totalXAmount: new BN(100e9),\n      totalYAmount: new BN(100e9),\n      strategy: {\n        minBinId,\n        maxBinId,\n        strategyType: StrategyType.Spot,\n      },\n      user: user.publicKey,\n      slippage: 0,\n    });\n    for (const tx of addLiquidityTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    await swap(true, new BN(10e9), dlmm, user);\n    await swap(false, new BN(10e9), dlmm, user);\n    // sleep for rewards\n    await new Promise((resolve) => setTimeout(resolve, 2000));\n\n    await dlmm.refetchStates();\n    const removeTxs = await dlmm.removeLiquidity({\n      user: user.publicKey,\n      position: positionKeypair.publicKey,\n      fromBinId: minBinId,\n      toBinId: maxBinId,\n      bps: new BN(10_000),\n      shouldClaimAndClose: false,\n    });\n    for (const tx of removeTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    await dlmm.refetchStates();\n    const { userPositions } = await dlmm.getPositionsByUserAndLbPair(\n      user.publicKey,\n    );\n    const pos = userPositions.find((p) =>\n      p.publicKey.equals(positionKeypair.publicKey),\n    );\n    //  position has no liquidity\n    expect(Number(pos.positionData.totalXAmount)).toBe(0);\n    expect(Number(pos.positionData.totalYAmount)).toBe(0);\n\n    // claim fee. so only rewards is left\n    const claimFeeTxs = await dlmm.claimSwapFee({\n      owner: user.publicKey,\n      position: pos,\n    });\n    for (const tx of claimFeeTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    const claimAndCloseTxs = await dlmm.removeLiquidity({\n      user: user.publicKey,\n      position: positionKeypair.publicKey,\n      fromBinId: minBinId,\n      toBinId: maxBinId,\n      bps: new BN(10_000),\n      shouldClaimAndClose: true,\n    });\n    for (const tx of claimAndCloseTxs) {\n      await sendAndConfirmTransaction(connection, tx, [user]);\n    }\n\n    const positionAccount = await connection.getAccountInfo(\n      positionKeypair.publicKey,\n    );\n    expect(positionAccount).toBeNull();\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/calculate_distribution.test.ts",
    "content": "import { BN } from \"@coral-xyz/anchor\";\nimport {\n  createInitializeMintInstruction,\n  createInitializeTransferFeeConfigInstruction,\n  createMint,\n  ExtensionType,\n  getMintLen,\n  Mint,\n  TOKEN_2022_PROGRAM_ID,\n  TOKEN_PROGRAM_ID,\n  unpackMint,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  sendAndConfirmTransaction,\n  SystemProgram,\n  SYSVAR_CLOCK_PUBKEY,\n  Transaction,\n} from \"@solana/web3.js\";\nimport babar from \"babar\";\nimport fs from \"fs\";\nimport {\n  calculateBidAskDistribution,\n  calculateNormalDistribution,\n  calculateSpotDistribution,\n  toAmountsBothSideByStrategy,\n  toWeightDistribution,\n} from \"../dlmm/helpers\";\nimport { Clock, ClockLayout, StrategyType } from \"../dlmm/types\";\n\ninterface Distribution {\n  binId: number;\n  xAmountBpsOfTotal;\n  yAmountBpsOfTotal;\n}\n\nexpect.extend({\n  toBeCloseTo(received: number, expected: number, precision: number) {\n    const pass = Math.abs(received - expected) <= precision;\n    return {\n      pass,\n      message: () =>\n        `expected ${received} to be close to ${expected} with precision ${precision}`,\n    };\n  },\n});\n\n// Print out distribution in console for debugging\nfunction debugDistributionChart(distributions: Distribution[]) {\n  const bars = [];\n  for (const dist of distributions) {\n    bars.push([\n      dist.binId,\n      dist.xAmountBpsOfTotal.add(dist.yAmountBpsOfTotal).toNumber(),\n    ]);\n  }\n  console.log(babar(bars));\n}\n\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\ndescribe(\"calculate_distribution\", () => {\n  const mint = Keypair.generate();\n  const mintWithTransferFee = Keypair.generate();\n\n  let mintAccount: Mint = null;\n  let mintWithTransferFeeAccount: Mint = null;\n  let clock: Clock;\n\n  beforeAll(async () => {\n    const decimal = 6;\n    await connection.requestAirdrop(keypair.publicKey, 10 * LAMPORTS_PER_SOL);\n    // 1. Create mint\n    await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      decimal,\n      mint,\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    // 2. Create mint with transfer fee\n    const extensions = [ExtensionType.TransferFeeConfig];\n    const mintLen = getMintLen(extensions);\n    const feeBasisPoint = 5000;\n    const maxFee = BigInt(100_000 * 10 ** decimal);\n    const minLamports =\n      await connection.getMinimumBalanceForRentExemption(mintLen);\n    const transaction = new Transaction()\n      .add(\n        SystemProgram.createAccount({\n          fromPubkey: keypair.publicKey,\n          newAccountPubkey: mintWithTransferFee.publicKey,\n          space: mintLen,\n          lamports: minLamports,\n          programId: TOKEN_2022_PROGRAM_ID,\n        })\n      )\n      .add(\n        createInitializeTransferFeeConfigInstruction(\n          mintWithTransferFee.publicKey,\n          keypair.publicKey,\n          keypair.publicKey,\n          feeBasisPoint,\n          maxFee,\n          TOKEN_2022_PROGRAM_ID\n        )\n      )\n      .add(\n        createInitializeMintInstruction(\n          mintWithTransferFee.publicKey,\n          decimal,\n          keypair.publicKey,\n          null,\n          TOKEN_2022_PROGRAM_ID\n        )\n      );\n\n    await sendAndConfirmTransaction(\n      connection,\n      transaction,\n      [keypair, mintWithTransferFee],\n      {\n        commitment: \"confirmed\",\n      }\n    );\n\n    const accounts = await connection.getMultipleAccountsInfo(\n      [mint.publicKey, mintWithTransferFee.publicKey, SYSVAR_CLOCK_PUBKEY],\n      {\n        commitment: \"confirmed\",\n      }\n    );\n\n    mintAccount = unpackMint(mint.publicKey, accounts[0], TOKEN_PROGRAM_ID);\n    mintWithTransferFeeAccount = unpackMint(\n      mintWithTransferFee.publicKey,\n      accounts[1],\n      TOKEN_2022_PROGRAM_ID\n    );\n    clock = ClockLayout.decode(accounts[2].data) as Clock;\n  });\n\n  describe(\"consists of only 1 bin id\", () => {\n    describe(\"when the deposit bin at the left of the active bin\", () => {\n      const binIds = [-10000];\n      const activeBin = -3333;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(1);\n      expect(distributions[0].binId).toBe(binIds[0]);\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(10000);\n    });\n\n    describe(\"when the deposit bin at the right of the active bin\", () => {\n      const binIds = [-2222];\n      const activeBin = -3333;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(1);\n      expect(distributions[0].binId).toBe(binIds[0]);\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(10000);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(0);\n    });\n\n    describe(\"when the deposit bin is the active bin\", () => {\n      const binIds = [-3333];\n      const activeBin = -3333;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(1);\n      expect(distributions[0].binId).toBe(binIds[0]);\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(10000);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(10000);\n    });\n  });\n\n  describe(\"spot distribution\", () => {\n    test(\"should return correct distribution with equal delta\", () => {\n      const binIds = [1, 2, 3, 4, 5];\n      const activeBin = 3;\n\n      const distributions = calculateSpotDistribution(activeBin, binIds);\n\n      const yNonActiveBinPct = Math.floor(10_000 / 2.5);\n      const xNonActiveBinPct = Math.floor(10_000 / 2.5);\n\n      expect(distributions[0].binId).toBe(1);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[1].binId).toBe(2);\n      expect(distributions[1].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[1].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[2].binId).toBe(3);\n      expect(distributions[2].yAmountBpsOfTotal.toNumber()).toBe(\n        Math.floor(yNonActiveBinPct * 0.5)\n      );\n      expect(distributions[2].xAmountBpsOfTotal.toNumber()).toBe(\n        Math.floor(xNonActiveBinPct * 0.5)\n      );\n\n      expect(distributions[3].binId).toBe(4);\n      expect(distributions[3].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[3].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      expect(distributions[4].binId).toBe(5);\n      expect(distributions[4].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[4].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n    });\n\n    test(\"should return correct distribution with unequal delta\", () => {\n      const binIds = [1, 2, 3, 4, 5];\n      const activeBin = 4;\n\n      const distributions = calculateSpotDistribution(activeBin, binIds);\n\n      const yNonActiveBinPct = Math.floor(10_000 / 3.5);\n      const xNonActiveBinPct = Math.floor(10_000 / 1.5);\n\n      expect(distributions[0].binId).toBe(1);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[1].binId).toBe(2);\n      expect(distributions[1].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[1].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[2].binId).toBe(3);\n      expect(distributions[2].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[2].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[3].binId).toBe(4);\n      // Precision loss added to active bin\n      expect(distributions[3].yAmountBpsOfTotal.toNumber()).toBeCloseTo(\n        Math.floor(yNonActiveBinPct * 0.5),\n        1\n      );\n      expect(distributions[3].xAmountBpsOfTotal.toNumber()).toBeCloseTo(\n        Math.floor(xNonActiveBinPct * 0.5),\n        1\n      );\n\n      expect(distributions[4].binId).toBe(5);\n      expect(distributions[4].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[4].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n    });\n\n    test(\"should return correct distribution with liquidity at the left side of the active bin\", () => {\n      const binIds = [1, 2, 3, 4, 5];\n      const activeBin = 10;\n\n      const distributions = calculateSpotDistribution(activeBin, binIds);\n\n      const yNonActiveBinPct = Math.floor(10_000 / 5);\n\n      expect(distributions[0].binId).toBe(1);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[1].binId).toBe(2);\n      expect(distributions[1].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[1].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[2].binId).toBe(3);\n      expect(distributions[2].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[2].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[3].binId).toBe(4);\n      expect(distributions[3].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[3].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      expect(distributions[4].binId).toBe(5);\n      expect(distributions[4].yAmountBpsOfTotal.toNumber()).toBe(\n        yNonActiveBinPct\n      );\n      expect(distributions[4].xAmountBpsOfTotal.toNumber()).toBe(0);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(0);\n      expect(yTokenTotalBps).toBe(10_000);\n    });\n\n    test(\"should return correct distribution with liquidity at the right side of the active bin\", () => {\n      const binIds = [5, 6, 7, 8, 9];\n      const activeBin = 1;\n\n      const distributions = calculateSpotDistribution(activeBin, binIds);\n\n      const xNonActiveBinPct = Math.floor(10_000 / 5);\n\n      expect(distributions[0].binId).toBe(5);\n      expect(distributions[0].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[0].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      expect(distributions[1].binId).toBe(6);\n      expect(distributions[1].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[1].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      expect(distributions[2].binId).toBe(7);\n      expect(distributions[2].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[2].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      expect(distributions[3].binId).toBe(8);\n      expect(distributions[3].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[3].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      expect(distributions[4].binId).toBe(9);\n      expect(distributions[4].yAmountBpsOfTotal.toNumber()).toBe(0);\n      expect(distributions[4].xAmountBpsOfTotal.toNumber()).toBe(\n        xNonActiveBinPct\n      );\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(0);\n    });\n  });\n\n  describe(\"curve distribution\", () => {\n    // Assert correct distribution when liquidity is surrounding the active bin\n    function assertDistributionAroundActiveBin(\n      activeBin: number,\n      distributions: Distribution[]\n    ) {\n      let beforeXBps: number = undefined;\n      let beforeYBps: number = undefined;\n\n      for (const dist of distributions) {\n        const { binId, xAmountBpsOfTotal, yAmountBpsOfTotal } = dist;\n        if (binId < activeBin) {\n          expect(xAmountBpsOfTotal.isZero()).toBeTruthy();\n          expect(yAmountBpsOfTotal.isZero()).toBeFalsy();\n          if (beforeYBps != undefined) {\n            // The bps should be increasing\n            expect(beforeYBps < yAmountBpsOfTotal.toNumber()).toBeTruthy();\n          }\n          beforeYBps = yAmountBpsOfTotal.toNumber();\n        } else if (binId == activeBin) {\n          expect(xAmountBpsOfTotal.isZero()).toBeFalsy();\n          expect(yAmountBpsOfTotal.isZero()).toBeFalsy();\n        } else {\n          expect(xAmountBpsOfTotal.isZero()).toBeFalsy();\n          expect(yAmountBpsOfTotal.isZero()).toBeTruthy();\n          if (beforeXBps != undefined) {\n            // The bps should be decreasing\n            expect(beforeXBps > xAmountBpsOfTotal.toNumber()).toBeTruthy();\n          }\n          beforeXBps = xAmountBpsOfTotal.toNumber();\n        }\n      }\n    }\n\n    test(\"should return correct distribution with liquidity concentrated around right side of the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5518;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity concentrated around left side of the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5508;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity concentrated around the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5513;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity to far right of the active bin\", () => {\n      const binIds = [5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513];\n      const activeBin = 3000;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(0);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity to far left of the active bin\", () => {\n      const binIds = [5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513];\n      const activeBin = 8000;\n\n      const distributions = calculateNormalDistribution(activeBin, binIds);\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(0);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n  });\n\n  describe(\"bid ask distribution\", () => {\n    // Assert correct distribution when liquidity is surrounding the active bin\n    function assertDistributionAroundActiveBin(\n      activeBin: number,\n      distributions: Distribution[]\n    ) {\n      let beforeXBps: number = undefined;\n      let beforeYBps: number = undefined;\n\n      for (const dist of distributions) {\n        const { binId, xAmountBpsOfTotal, yAmountBpsOfTotal } = dist;\n        if (binId < activeBin) {\n          expect(xAmountBpsOfTotal.isZero()).toBeTruthy();\n          expect(yAmountBpsOfTotal.isZero()).toBeFalsy();\n          if (beforeYBps != undefined) {\n            // The bps should be decreasing\n            expect(beforeYBps > yAmountBpsOfTotal.toNumber()).toBeTruthy();\n          }\n          beforeYBps = yAmountBpsOfTotal.toNumber();\n        } else if (binId == activeBin) {\n          expect(xAmountBpsOfTotal.isZero()).toBeFalsy();\n          expect(yAmountBpsOfTotal.isZero()).toBeFalsy();\n        } else {\n          expect(xAmountBpsOfTotal.isZero()).toBeFalsy();\n          expect(yAmountBpsOfTotal.isZero()).toBeTruthy();\n          if (beforeXBps != undefined) {\n            // The bps should be increasing\n            expect(beforeXBps < xAmountBpsOfTotal.toNumber()).toBeTruthy();\n          }\n          beforeXBps = xAmountBpsOfTotal.toNumber();\n        }\n      }\n    }\n\n    test(\"should return correct distribution with liquidity concentrated around right side of the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5518;\n\n      const distributions = calculateBidAskDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity concentrated around left side of the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5508;\n\n      const distributions = calculateBidAskDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity concentrated around the active bin\", () => {\n      const binIds = [\n        5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516,\n        5517, 5518, 5519, 5520, 5521,\n      ];\n      const activeBin = 5513;\n\n      const distributions = calculateBidAskDistribution(activeBin, binIds);\n\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity to far right of the active bin\", () => {\n      const binIds = [5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513];\n      const activeBin = 3000;\n\n      const distributions = calculateBidAskDistribution(activeBin, binIds);\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(10_000);\n      expect(yTokenTotalBps).toBe(0);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"should return correct distribution with liquidity to far left of the active bin\", () => {\n      const binIds = [5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513];\n      const activeBin = 8000;\n\n      const distributions = calculateBidAskDistribution(activeBin, binIds);\n      expect(distributions.length).toBe(binIds.length);\n\n      const xTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.xAmountBpsOfTotal.toNumber(),\n        0\n      );\n      const yTokenTotalBps = distributions.reduce(\n        (acc, d) => acc + d.yAmountBpsOfTotal.toNumber(),\n        0\n      );\n\n      expect(xTokenTotalBps).toBe(0);\n      expect(yTokenTotalBps).toBe(10_000);\n\n      debugDistributionChart(distributions);\n      assertDistributionAroundActiveBin(activeBin, distributions);\n    });\n\n    test(\"to weight distribution\", () => {\n      const binIds = [\n        -3563, -3562, -3561, -3560, -3559, -3558, -3557, -3556, -3555,\n      ];\n      const activeBin = -3556;\n\n      const distributions = calculateSpotDistribution(activeBin, binIds);\n\n      let weightDistribution = toWeightDistribution(\n        new BN(1000000000),\n        new BN(57000000),\n        distributions,\n        8\n      );\n      console.log(weightDistribution);\n      const bars = [];\n      for (const dist of weightDistribution) {\n        bars.push([dist.binId, dist.weight]);\n      }\n      console.log(babar(bars));\n    });\n\n    test(\"to amount both side by strategy\", () => {\n      let activeId = 45;\n      let minBinId = 20;\n      let maxBinId = 70;\n      let binStep = 10;\n      let amount = new BN(10000);\n\n      // 1. Without transfer fee\n      let amountInBins = toAmountsBothSideByStrategy(\n        activeId,\n        binStep,\n        minBinId,\n        maxBinId,\n        amount,\n        amount,\n        new BN(0),\n        new BN(0),\n        StrategyType.Spot,\n        mintAccount,\n        mintAccount,\n        clock\n      );\n\n      let totalAmountX = amountInBins.reduce((total, { amountX }) => {\n        return total.add(amountX);\n      }, new BN(0));\n\n      let totalAmountY = amountInBins.reduce((total, { amountY }) => {\n        return total.add(amountY);\n      }, new BN(0));\n\n      // Precision loss\n      let diff = amount.sub(totalAmountX);\n      expect(diff.lt(new BN(30))).toBeTruthy();\n\n      diff = amount.sub(totalAmountY);\n      expect(diff.lt(new BN(30))).toBeTruthy();\n\n      // 2. With transfer fee\n      amountInBins = toAmountsBothSideByStrategy(\n        activeId,\n        binStep,\n        minBinId,\n        maxBinId,\n        amount,\n        amount,\n        new BN(0),\n        new BN(0),\n        StrategyType.Spot,\n        mintWithTransferFeeAccount,\n        mintAccount,\n        clock\n      );\n\n      totalAmountX = amountInBins.reduce((total, { amountX }) => {\n        return total.add(amountX);\n      }, new BN(0));\n\n      totalAmountY = amountInBins.reduce((total, { amountY }) => {\n        return total.add(amountY);\n      }, new BN(0));\n\n      expect(totalAmountX.lt(amount.div(new BN(2)))).toBeTruthy();\n\n      diff = amount.sub(totalAmountY);\n      expect(diff.lt(new BN(30))).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/cjs.test.js",
    "content": "describe(\"CommonJS require() compatibility tests\", () => {\n    let DLMM;\n\n    beforeAll(() => {\n        // Test actual require() behavior\n        DLMM = require(\"../../dist/index.js\");\n    });\n\n    describe(\"require() import structure tests\", () => {\n        test(\"should import DLMM using require()\", () => {\n            expect(DLMM).toBeDefined();\n        });\n\n        test(\"should be a class constructor or have default export\", () => {\n            expect(typeof DLMM).toBe(\"function\");\n            expect(DLMM.name).toBe(\"DLMM\");\n        });\n\n        test(\"should have consistent export structure\", () => {\n            expect(DLMM.prototype).toBeDefined();\n            expect(DLMM.prototype.constructor).toBe(DLMM);\n        });\n    });\n\n    describe(\"static methods accessibility with require()\", () => {\n        test(\"should have getAllLbPairPositionsByUser accessible\", () => {\n            expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n            expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n        });\n\n        test(\"should have createLbPair accessible\", () => {\n            expect(DLMM.createLbPair).toBeDefined();\n            expect(typeof DLMM.createLbPair).toBe(\"function\");\n        });\n\n        test(\"should have createCustomizablePermissionlessLbPair accessible\", () => {\n            expect(DLMM.createCustomizablePermissionlessLbPair).toBeDefined();\n            expect(\n                typeof DLMM.createCustomizablePermissionlessLbPair\n            ).toBe(\"function\");\n        });\n\n        test(\"should have getLbPairs accessible\", () => {\n            expect(DLMM.getLbPairs).toBeDefined();\n            expect(typeof DLMM.getLbPairs).toBe(\"function\");\n        });\n    });\n\n    describe(\"CJS usage patterns\", () => {\n        test(\"should work with destructuring require\", () => {\n            const exported = require(\"../../dist/index.js\");\n\n            expect(exported).toBeDefined();\n            expect(typeof exported).toBe(\"function\");\n        });\n\n        test(\"should work with direct require assignment\", () => {\n\n            expect(typeof DLMM.create).toBe(\"function\");\n            expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n        });\n\n        test(\"should provide consistent API for CJS consumers\", () => {\n            const requiredMethods = [\n                \"createLbPair\",\n                \"createCustomizablePermissionlessLbPair\",\n                \"getAllLbPairPositionsByUser\",\n                \"getLbPairs\",\n                \"create\",\n            ];\n\n            requiredMethods.forEach((method) => {\n                expect(DLMM).toHaveProperty(method);\n                expect(typeof DLMM[method]).toBe(\"function\");\n            });\n        });\n    });\n\n    describe(\"CJS module.exports validation\", () => {\n        test(\"should have valid module.exports structure\", () => {\n            const exported = require(\"../../dist/index.js\");\n\n            expect(\n                typeof exported === \"function\" || typeof exported.default === \"function\"\n            ).toBe(true);\n        });\n\n        test(\"should not have double wrapping\", () => {\n\n            expect(DLMM.default).toBeUndefined();\n        });\n\n        test(\"should work with Node.js require caching\", () => {\n            const firstRequire = require(\"../../dist/index.js\");\n            const secondRequire = require(\"../../dist/index.js\");\n\n            expect(firstRequire).toBe(secondRequire);\n        });\n    });\n\n    describe(\"interoperability tests\", () => {\n        test(\"should work in Node.js without type: module\", () => {\n            expect(typeof require).toBe(\"function\");\n            expect(DLMM).toBeDefined();\n        });\n\n        test(\"should have __esModule marker if using Babel/TypeScript compilation\", () => {\n            const exported = require(\"../../dist/index.js\");\n\n            if (exported.__esModule) {\n                expect(exported.__esModule).toBe(true);\n                expect(exported.default).toBeDefined();\n            }\n        });\n    });\n\n    describe(\"error prevention for CJS users\", () => {\n        test(\"should not require confusing import patterns\", () => {\n\n            expect(typeof DLMM).toBe(\"function\");\n            expect(DLMM.name).toBe(\"DLMM\");\n        });\n\n        test(\"should prevent 'is not a function' errors with require()\", () => {\n\n            expect(() => {\n                const method = DLMM.getAllLbPairPositionsByUser;\n                expect(typeof method).toBe(\"function\");\n            }).not.toThrow();\n        });\n\n        test(\"should work with typical CJS usage in documentation\", () => {\n\n            expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n            expect(typeof DLMM.createLbPair).toBe(\"function\");\n        });\n    });\n});\n\n"
  },
  {
    "path": "ts-client/src/test/decode.test.ts",
    "content": "import { Connection, SYSVAR_CLOCK_PUBKEY } from \"@solana/web3.js\";\nimport { Clock, ClockLayout } from \"../dlmm/types\";\n\ndescribe(\"Decode\", () => {\n  const connection = new Connection(\"http://127.0.0.1:8899\", \"processed\");\n\n  test(\"Decode sysvar clock\", async () => {\n    const currentTime = Math.floor(Date.now() / 1000);\n\n    const clockAccount = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);\n    const clock = ClockLayout.decode(clockAccount!.data) as Clock;\n\n    console.log(clock.slot.toString());\n    console.log(clock.unixTimestamp.toString());\n\n    const secondDiff = Math.abs(currentTime - clock.unixTimestamp.toNumber());\n\n    expect(clock.slot.toNumber()).toBeGreaterThan(0);\n    expect(secondDiff).toBeLessThan(30);\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/esm_import.test.ts",
    "content": "import DLMM from \"../../dist\";\n\ndescribe(\"ESM default import tests\", () => {\n  describe(\"default import structure tests\", () => {\n    test(\"should import DLMM as a direct reference, not a namespace\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM).toBe(\"function\");\n    });\n\n    test(\"should be a class constructor\", () => {\n      expect(DLMM.name).toBe(\"DLMM\");\n      expect(DLMM.prototype).toBeDefined();\n      expect(DLMM.prototype.constructor).toBe(DLMM);\n    });\n\n    test(\"should NOT require .default to access the class\", () => {\n      expect((DLMM as any).default).toBeUndefined();\n    });\n  });\n\n  describe(\"static methods tests\", () => {\n    test(\"should have getAllLbPairPositionsByUser static method directly accessible\", () => {\n      expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n      expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n    });\n\n    test(\"should have createLbPair static method directly accessible\", () => {\n      expect(DLMM.createLbPair).toBeDefined();\n      expect(typeof DLMM.createLbPair).toBe(\"function\");\n    });\n\n    test(\"should have createCustomizablePermissionlessLbPair static method directly accessible\", () => {\n      expect(DLMM.createCustomizablePermissionlessLbPair).toBeDefined();\n      expect(typeof DLMM.createCustomizablePermissionlessLbPair).toBe(\n        \"function\"\n      );\n    });\n\n    test(\"should have getLbPairs static method directly accessible\", () => {\n      expect(DLMM.getLbPairs).toBeDefined();\n      expect(typeof DLMM.getLbPairs).toBe(\"function\");\n    });\n\n    test(\"should have getAllLbPairPositionsByUser static method directly accessible\", () => {\n      expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n      expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n    });\n  });\n\n  describe(\"typescript type tests\", () => {\n    test(\"should be compatible with TypeScript strict mode\", () => {\n      const DLMMClass: typeof DLMM = DLMM;\n      expect(DLMMClass).toBe(DLMM);\n    });\n\n    test(\"should support ESM import syntax in type definitions\", () => {\n      const importedDLMM: typeof DLMM = DLMM;\n      expect(importedDLMM.name).toBe(\"DLMM\");\n    });\n  });\n\n  describe(\"usage tests\", () => {\n    test(\"should allow direct usage without .default workaround\", () => {\n      expect(() => {\n        const method = DLMM.getAllLbPairPositionsByUser;\n        expect(method).toBeDefined();\n      }).not.toThrow();\n    });\n\n    test(\"should support TypeScript 5+ bundler module resolution\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM.create).toBe(\"function\");\n    });\n  });\n\n  describe(\"backward compatibility tests\", () => {\n    test(\"should work with traditional module resolution\", () => {\n      expect(DLMM).toBeDefined();\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n\n    test(\"should have consistent behavior across import styles\", () => {\n      const hasStaticMethods =\n        typeof DLMM.create === \"function\" &&\n        typeof DLMM.getAllLbPairPositionsByUser === \"function\";\n      expect(hasStaticMethods).toBe(true);\n    });\n  });\n\n  describe(\"export validation tests\", () => {\n    test(\"should export DLMM as the default export\", () => {\n      expect(DLMM).toBeDefined();\n      expect(DLMM.constructor.name).toBe(\"Function\");\n    });\n\n    test(\"should not wrap the class in an additional object\", () => {\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n  });\n\n  describe(\"error prevention tests\", () => {\n    test(\"should prevent 'DLMM.getAllLbPairPositionsByUser is not a function' error\", () => {\n      expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n\n      expect(\n        (DLMM as any).default?.getAllLbPairPositionsByUser\n      ).toBeUndefined();\n    });\n\n    test(\"should not require DLMM.default.createLbPair() workaround\", () => {\n      expect(typeof DLMM.createLbPair).toBe(\"function\");\n\n      expect((DLMM as any).default).toBeUndefined();\n    });\n\n    test(\"should work with modern ESM tooling (tsx, esbuild, vite)\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM).toBe(\"function\");\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/esm_module.test.ts",
    "content": "import DLMM from \"../../dist\";\n\ndescribe(\"ESM module compatibility tests\", () => {\n  describe(\"esm module resolution tests\", () => {\n    test(\"should support ES6 default import\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM).toBe(\"function\");\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n\n    test(\"should work with TypeScript moduleResolution: bundler\", () => {\n      const dlmmClass = DLMM;\n      expect(dlmmClass.getAllLbPairPositionsByUser).toBeDefined();\n    });\n\n    test(\"should work with package.json type: module\", () => {\n      expect(DLMM).toBeDefined();\n      expect(DLMM.prototype).toBeDefined();\n    });\n  });\n\n  describe(\"esm api surface tests\", () => {\n    test(\"should not have double-wrapping in ESM import\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM).toBe(\"function\"); // not double-wrapped\n    });\n\n    test(\"should provide consistent API for ESM consumers\", () => {\n      const requiredMethods = [\n        \"createLbPair\",\n        \"createCustomizablePermissionlessLbPair\",\n        \"getAllLbPairPositionsByUser\",\n        \"getLbPairs\",\n      ];\n\n      requiredMethods.forEach((method) => {\n        expect(DLMM).toHaveProperty(method);\n        expect(typeof (DLMM as any)[method]).toBe(\"function\");\n      });\n    });\n  });\n\n  describe(\"modern module tests\", () => {\n    test(\"should work with tsx\", () => {\n      expect(DLMM).toBeDefined();\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n\n    test(\"should work with esbuild\", () => {\n      expect(typeof DLMM).toBe(\"function\");\n      expect(DLMM.prototype.constructor).toBe(DLMM);\n    });\n\n    test(\"should work with modern bundlers (webpack, vite, rollup)\", () => {\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM.createLbPair).toBe(\"function\");\n    });\n  });\n\n  describe(\"Package.json Exports Field\", () => {\n    test(\"should have correct export structure for dual module support\", () => {\n      // The package.json should have:\n      // \"exports\": {\n      //   \".\": {\n      //     \"import\": \"./dist/index.mjs\",\n      //     \"require\": \"./dist/index.js\"\n      //   }\n      // }\n\n      expect(DLMM).toBeDefined();\n      expect(typeof DLMM).toBe(\"function\");\n    });\n  });\n\n  describe(\"TypeScript Version Compatibility\", () => {\n    test(\"should work with TypeScript 5.9.3 (from issue)\", () => {\n      const dlmm: typeof DLMM = DLMM;\n      expect(dlmm.name).toBe(\"DLMM\");\n    });\n\n    test(\"should work with TypeScript 5+ strict mode\", () => {\n      const staticMethod: typeof DLMM.getAllLbPairPositionsByUser =\n        DLMM.getAllLbPairPositionsByUser;\n      expect(typeof staticMethod).toBe(\"function\");\n    });\n  });\n\n  describe(\"Node.js Compatibility\", () => {\n    test(\"should work with Node.js 20.x (from issue)\", () => {\n      expect(DLMM).toBeDefined();\n      expect(DLMM.name).toBe(\"DLMM\");\n    });\n\n    test(\"should support Node.js ESM (package.json type: module)\", () => {\n      expect(typeof DLMM).toBe(\"function\");\n      expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n    });\n  });\n\n  describe(\"Regression Prevention\", () => {\n    test(\"should never require double .default access\", () => {\n      // DLMM.default.default.method()\n\n      expect(typeof DLMM).toBe(\"function\");\n\n      expect((DLMM as any).default).toBeUndefined();\n    });\n\n    test(\"should not expose internal export structures\", () => {\n      expect((DLMM as any).src_default).toBeUndefined();\n\n      expect((DLMM as any).__esModule).toBeUndefined();\n    });\n\n    test(\"should maintain consistent namespace across builds\", () => {\n      const publicAPI = Object.getOwnPropertyNames(DLMM);\n\n      expect(publicAPI.length).toBeGreaterThan(0);\n\n      expect(publicAPI).not.toContain(\"default\");\n      expect(publicAPI).not.toContain(\"__esModule\");\n    });\n  });\n\n  describe(\"Documentation Examples Validation\", () => {\n    test(\"should allow usage exactly as shown in docs\", () => {\n      expect(DLMM.getAllLbPairPositionsByUser).toBeDefined();\n      expect(typeof DLMM.getAllLbPairPositionsByUser).toBe(\"function\");\n\n      expect(\n        (DLMM as any).default?.getAllLbPairPositionsByUser\n      ).toBeUndefined();\n    });\n\n    test(\"should match expected console.log output\", () => {\n      const dlmmString = DLMM.toString();\n      expect(dlmmString).toContain(\"class\");\n      expect(DLMM.name).toBe(\"DLMM\");\n      expect(typeof DLMM).not.toBe(\"object\");\n      expect(typeof DLMM).toBe(\"function\");\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/external/helper.ts",
    "content": "import { Program, web3 } from \"@coral-xyz/anchor\";\nimport { TransferHookCounter } from \"./transfer_hook_counter\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  getExtraAccountMetaAddress,\n  TOKEN_2022_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport { SystemProgram } from \"@solana/web3.js\";\n\nexport async function createExtraAccountMetaListAndCounter(\n  program: Program<TransferHookCounter>,\n  mint: web3.PublicKey\n) {\n  const extraAccountMetaList = getExtraAccountMetaAddress(\n    mint,\n    program.programId\n  );\n  const counterAccount = deriveCounter(mint, program.programId);\n\n  await program.methods\n    .initializeExtraAccountMetaList()\n    .accountsStrict({\n      mint,\n      counterAccount,\n      extraAccountMetaList,\n      tokenProgram: TOKEN_2022_PROGRAM_ID,\n      payer: program.provider.wallet.publicKey,\n      systemProgram: SystemProgram.programId,\n      associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,\n    })\n    .rpc();\n\n  return [extraAccountMetaList, counterAccount];\n}\n\nexport function deriveCounter(mint: web3.PublicKey, programId: web3.PublicKey) {\n  const [counter] = web3.PublicKey.findProgramAddressSync(\n    [Buffer.from(\"counter\"), mint.toBuffer()],\n    programId\n  );\n\n  return counter;\n}\n"
  },
  {
    "path": "ts-client/src/test/external/program.ts",
    "content": "import { AnchorProvider, Program, Wallet, web3 } from \"@coral-xyz/anchor\";\nimport { TransferHookCounter } from \"./transfer_hook_counter\";\nimport TransferHookCounterIDL from \"./transfer_hook_counter.json\";\nimport { Connection } from \"@solana/web3.js\";\n\nexport const TRANSFER_HOOK_COUNTER_PROGRAM_ID = new web3.PublicKey(\n  \"abcSyangMHdGzUGKhBhKoQzSFdJKUdkPGf5cbXVHpEw\"\n);\n\nexport function createTransferHookCounterProgram(\n  wallet: Wallet,\n  programId: web3.PublicKey,\n  connection: Connection\n): Program<TransferHookCounter> {\n  const provider = new AnchorProvider(connection, wallet, {\n    maxRetries: 3,\n  });\n\n  const program = new Program<TransferHookCounter>(\n    { ...TransferHookCounterIDL, address: programId },\n    provider\n  );\n\n  return program;\n}\n"
  },
  {
    "path": "ts-client/src/test/external/transfer_hook_counter.json",
    "content": "{\n  \"address\": \"abcSyangMHdGzUGKhBhKoQzSFdJKUdkPGf5cbXVHpEw\",\n  \"metadata\": {\n    \"name\": \"transfer_hook_counter\",\n    \"version\": \"0.1.0\",\n    \"spec\": \"0.1.0\"\n  },\n  \"instructions\": [\n    {\n      \"name\": \"initialize_extra_account_meta_list\",\n      \"discriminator\": [\n        92,\n        197,\n        174,\n        197,\n        41,\n        124,\n        19,\n        3\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"extra_account_meta_list\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"mint\"\n        },\n        {\n          \"name\": \"counter_account\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"token_program\"\n        },\n        {\n          \"name\": \"associated_token_program\"\n        },\n        {\n          \"name\": \"system_program\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"transfer_hook\",\n      \"discriminator\": [\n        220,\n        57,\n        220,\n        152,\n        126,\n        125,\n        97,\n        168\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"source_token\"\n        },\n        {\n          \"name\": \"mint\"\n        },\n        {\n          \"name\": \"destination_token\"\n        },\n        {\n          \"name\": \"owner\"\n        },\n        {\n          \"name\": \"extra_account_meta_list\"\n        },\n        {\n          \"name\": \"counter_account\",\n          \"writable\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount\",\n          \"type\": \"u64\"\n        }\n      ]\n    }\n  ],\n  \"accounts\": [\n    {\n      \"name\": \"CounterAccount\",\n      \"discriminator\": [\n        164,\n        8,\n        153,\n        71,\n        8,\n        44,\n        93,\n        22\n      ]\n    }\n  ],\n  \"errors\": [\n    {\n      \"code\": 6000,\n      \"name\": \"AmountTooBig\",\n      \"msg\": \"The amount is too big\"\n    }\n  ],\n  \"types\": [\n    {\n      \"name\": \"CounterAccount\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"counter\",\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    }\n  ]\n}"
  },
  {
    "path": "ts-client/src/test/external/transfer_hook_counter.ts",
    "content": "/**\n * Program IDL in camelCase format in order to be used in JS/TS.\n *\n * Note that this is only a type helper and is not the actual IDL. The original\n * IDL can be found at `target/idl/transfer_hook_counter.json`.\n */\nexport type TransferHookCounter = {\n  \"address\": \"abcSyangMHdGzUGKhBhKoQzSFdJKUdkPGf5cbXVHpEw\",\n  \"metadata\": {\n    \"name\": \"transferHookCounter\",\n    \"version\": \"0.1.0\",\n    \"spec\": \"0.1.0\"\n  },\n  \"instructions\": [\n    {\n      \"name\": \"initializeExtraAccountMetaList\",\n      \"discriminator\": [\n        92,\n        197,\n        174,\n        197,\n        41,\n        124,\n        19,\n        3\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"payer\",\n          \"writable\": true,\n          \"signer\": true\n        },\n        {\n          \"name\": \"extraAccountMetaList\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"mint\"\n        },\n        {\n          \"name\": \"counterAccount\",\n          \"writable\": true\n        },\n        {\n          \"name\": \"tokenProgram\"\n        },\n        {\n          \"name\": \"associatedTokenProgram\"\n        },\n        {\n          \"name\": \"systemProgram\"\n        }\n      ],\n      \"args\": []\n    },\n    {\n      \"name\": \"transferHook\",\n      \"discriminator\": [\n        220,\n        57,\n        220,\n        152,\n        126,\n        125,\n        97,\n        168\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"sourceToken\"\n        },\n        {\n          \"name\": \"mint\"\n        },\n        {\n          \"name\": \"destinationToken\"\n        },\n        {\n          \"name\": \"owner\"\n        },\n        {\n          \"name\": \"extraAccountMetaList\"\n        },\n        {\n          \"name\": \"counterAccount\",\n          \"writable\": true\n        }\n      ],\n      \"args\": [\n        {\n          \"name\": \"amount\",\n          \"type\": \"u64\"\n        }\n      ]\n    }\n  ],\n  \"accounts\": [\n    {\n      \"name\": \"counterAccount\",\n      \"discriminator\": [\n        164,\n        8,\n        153,\n        71,\n        8,\n        44,\n        93,\n        22\n      ]\n    }\n  ],\n  \"errors\": [\n    {\n      \"code\": 6000,\n      \"name\": \"amountTooBig\",\n      \"msg\": \"The amount is too big\"\n    }\n  ],\n  \"types\": [\n    {\n      \"name\": \"counterAccount\",\n      \"type\": {\n        \"kind\": \"struct\",\n        \"fields\": [\n          {\n            \"name\": \"counter\",\n            \"type\": \"u32\"\n          }\n        ]\n      }\n    }\n  ]\n};\n"
  },
  {
    "path": "ts-client/src/test/helper.ts",
    "content": "import {\n  Connection,\n  Keypair,\n  PublicKey,\n  sendAndConfirmTransaction,\n  SystemProgram,\n} from \"@solana/web3.js\";\nimport { LbPosition, Position, PositionData } from \"../dlmm/types\";\nimport { DLMM } from \"../dlmm\";\nimport BN from \"bn.js\";\nimport { AnchorProvider, Program, Wallet } from \"@coral-xyz/anchor\";\nimport IDL from \"../dlmm/idl/idl.json\";\nimport { LbClmm } from \"../dlmm/idl/idl\";\nimport { RebalancePosition } from \"../dlmm/helpers/rebalance\";\nimport babar from \"babar\";\nimport Decimal from \"decimal.js\";\nimport {\n  deriveOperator,\n  getBinArrayLowerUpperBinId,\n  getPriceOfBinByBinId,\n} from \"../dlmm/helpers\";\n\nexport function createTestProgram(\n  connection: Connection,\n  programId: PublicKey,\n  keypair: Keypair\n) {\n  const provider = new AnchorProvider(\n    connection,\n    new Wallet(keypair),\n    AnchorProvider.defaultOptions()\n  );\n  return new Program<LbClmm>({ ...IDL, address: programId }, provider);\n}\n\nexport function assertAmountWithPrecision(\n  actualAmount: number,\n  expectedAmount: number,\n  precisionPercent: number\n) {\n  if (expectedAmount == 0 && actualAmount == 0) {\n    return;\n  }\n  let maxAmount, minAmount;\n  if (expectedAmount > actualAmount) {\n    maxAmount = expectedAmount;\n    minAmount = actualAmount;\n  } else {\n    maxAmount = actualAmount;\n    minAmount = expectedAmount;\n  }\n  let diff = ((maxAmount - minAmount) * 100) / maxAmount;\n  expect(diff).toBeLessThan(precisionPercent);\n}\n\nexport async function assertPosition({\n  lbClmm,\n  positionPubkey,\n  userPublicKey,\n  xAmount,\n  yAmount,\n}: {\n  lbClmm: DLMM;\n  positionPubkey: PublicKey;\n  userPublicKey: PublicKey;\n  xAmount: BN;\n  yAmount: BN;\n}) {\n  const positionState: Position = await lbClmm.program.account.positionV2.fetch(\n    positionPubkey\n  );\n\n  const { userPositions } = await lbClmm.getPositionsByUserAndLbPair(\n    userPublicKey\n  );\n\n  expect(userPositions.length).toBeGreaterThan(0);\n  const position = userPositions.find((ps) =>\n    ps.publicKey.equals(positionPubkey)\n  );\n  expect(position).not.toBeUndefined();\n  expect(position.positionData.positionBinData.length).toBe(\n    positionState.upperBinId - positionState.lowerBinId + 1\n  );\n  expect(position.positionData.positionBinData[0].binId).toBe(\n    positionState.lowerBinId\n  );\n  expect(\n    position.positionData.positionBinData[\n      position.positionData.positionBinData.length - 1\n    ].binId\n  ).toBe(positionState.upperBinId);\n  expect(+position.positionData.totalXAmount).toBeLessThan(xAmount.toNumber());\n  assertAmountWithPrecision(\n    +position.positionData.totalXAmount,\n    xAmount.toNumber(),\n    5\n  );\n  expect(+position.positionData.totalYAmount).toBeLessThan(yAmount.toNumber());\n  assertAmountWithPrecision(\n    +position.positionData.totalYAmount,\n    yAmount.toNumber(),\n    5\n  );\n\n  return { bins: position.positionData.positionBinData };\n}\n\nexport function assertEqRebalanceSimulationWithActualResult(\n  rebalancePosition: RebalancePosition,\n  position: LbPosition\n) {\n  const [simulatedAmountX, simulatedAmountY] = rebalancePosition.totalAmounts();\n\n  expect(position.positionData.totalXAmount.toString()).toBe(\n    simulatedAmountX.toString()\n  );\n\n  expect(position.positionData.totalYAmount.toString()).toBe(\n    simulatedAmountY.toString()\n  );\n\n  expect(position.positionData.lowerBinId).toBe(\n    rebalancePosition.lowerBinId.toNumber()\n  );\n\n  expect(position.positionData.upperBinId).toBe(\n    rebalancePosition.upperBinId.toNumber()\n  );\n\n  expect(rebalancePosition.rebalancePositionBinData.length).toBe(\n    position.positionData.positionBinData.length\n  );\n\n  for (let i = 0; i < position.positionData.positionBinData.length; i++) {\n    const simBinData = rebalancePosition.rebalancePositionBinData[i];\n    const binData = position.positionData.positionBinData[i];\n\n    expect(simBinData.binId).toBe(binData.binId);\n    expect(simBinData.amountX.toString()).toBe(binData.positionXAmount);\n    expect(simBinData.amountY.toString()).toBe(binData.positionYAmount);\n\n    expect(simBinData.claimableFeeXAmount.toString()).toBe(\n      binData.positionFeeXAmount\n    );\n    expect(simBinData.claimableFeeYAmount.toString()).toBe(\n      binData.positionFeeYAmount\n    );\n    expect(simBinData.claimableRewardAmount[0].toString()).toBe(\n      binData.positionRewardAmount[0]\n    );\n    expect(simBinData.claimableRewardAmount[1].toString()).toBe(\n      binData.positionRewardAmount[1]\n    );\n  }\n}\n\nexport async function swap(\n  swapForY: boolean,\n  inAmount: BN,\n  dlmm: DLMM,\n  keypair: Keypair\n) {\n  await dlmm.refetchStates();\n  const inToken = swapForY ? dlmm.lbPair.tokenXMint : dlmm.lbPair.tokenYMint;\n  const outToken = swapForY ? dlmm.lbPair.tokenYMint : dlmm.lbPair.tokenXMint;\n  const binArrays = await dlmm.getBinArrayForSwap(swapForY);\n  const { consumedInAmount } = await dlmm.swapQuote(\n    inAmount,\n    swapForY,\n    new BN(0),\n    binArrays,\n    true\n  );\n  const swapTx = await dlmm.swap({\n    lbPair: dlmm.pubkey,\n    inToken,\n    outToken,\n    inAmount: consumedInAmount,\n    minOutAmount: new BN(0),\n    binArraysPubkey: binArrays.map((binArray) => binArray.publicKey),\n    user: keypair.publicKey,\n  });\n  await sendAndConfirmTransaction(dlmm.program.provider.connection, swapTx, [\n    keypair,\n  ]);\n}\n\nexport function logPositionLiquidities(parsedPosition: PositionData) {\n  const { positionBinData } = parsedPosition;\n  const liquidities = [];\n  for (const data of positionBinData) {\n    if (new Decimal(data.binLiquidity).isZero()) {\n      liquidities.push([data.binId, 0]);\n      continue;\n    }\n    const liquidityX = new Decimal(data.positionXAmount).mul(\n      new Decimal(data.price)\n    );\n    const liquidityY = new Decimal(data.positionYAmount);\n    const liquidity = liquidityX.add(liquidityY);\n    liquidities.push([data.binId, liquidity.toNumber()]);\n  }\n  console.log(babar(liquidities));\n}\n\nexport function assertionWithTolerance(\n  actual: BN,\n  expected: BN,\n  tolerance: BN\n) {\n  try {\n    expect(actual.sub(expected).abs().lte(tolerance)).toBeTruthy();\n  } catch (originalError) {\n    const e = `E: ${originalError}. Assertion failed, actual: ${actual.toString()}, expected: ${expected.toString()}, tolerance: ${tolerance.toString()}`;\n    throw new Error(e);\n  }\n}\n\nexport function assertionWithPercentageTolerance(\n  actual: BN,\n  expected: BN,\n  tolerancePercentage: number\n) {\n  const tolerance = actual.sub(expected).abs().muln(100).div(actual);\n  try {\n    expect(tolerance.ltn(tolerancePercentage)).toBeTruthy();\n  } catch (originalError) {\n    const e = `E: ${originalError}. Assertion failed, actual: ${actual.toString()}, expected: ${expected.toString()}, tolerance percentage: ${tolerancePercentage}`;\n    throw new Error(e);\n  }\n}\n\nexport async function logLbPairLiquidities(\n  lbPair: PublicKey,\n  binStep: number,\n  program: Program<LbClmm>\n) {\n  const binArrays = await program.account.binArray.all([\n    {\n      memcmp: {\n        offset: 24,\n        bytes: lbPair.toBase58(),\n      },\n    },\n  ]);\n\n  binArrays.sort((a, b) => a.account.index.cmp(b.account.index));\n\n  const liquidities = [];\n  for (const binArray of binArrays) {\n    const [minBinId] = getBinArrayLowerUpperBinId(binArray.account.index);\n\n    for (const [idx, bin] of binArray.account.bins.entries()) {\n      const binId = minBinId.toNumber() + idx;\n\n      if (bin.liquiditySupply.isZero()) {\n        liquidities.push([binId, 0]);\n        continue;\n      }\n      const liquidityX = new Decimal(bin.amountX.toString()).mul(\n        getPriceOfBinByBinId(binId, binStep)\n      );\n      const liquidityY = new Decimal(bin.amountY.toString());\n      const liquidity = liquidityX.add(liquidityY);\n      liquidities.push([binId, liquidity.toNumber()]);\n    }\n  }\n\n  console.log(babar(liquidities));\n}\n\nexport enum OperatorPermission {\n  InitializePresetParameter,\n  ClosePresetParameter,\n  SetPairStatus,\n  UpdateFeeParameters,\n  SetActivationPoint,\n  InitializePermissionedPool,\n  InitializeTokenBadge,\n  CloseTokenBadge,\n  InitializeReward,\n  UpdateRewardFunder,\n  UpdateRewardDuration,\n  ResetTombstoneFields,\n  ClaimProtocolFee,\n  ZapProtocolFee,\n}\n\nexport function encodePermissions(permissions: OperatorPermission[]): BN {\n  return permissions.reduce((acc, perm) => {\n    return acc.or(new BN(1).shln(perm));\n  }, new BN(0));\n}\n\nexport async function createWhitelistOperator(\n  connection: Connection,\n  admin: Keypair,\n  whitelistOperator: PublicKey,\n  permissions: OperatorPermission[],\n  programId: PublicKey\n) {\n  const encodedPermissions = encodePermissions(permissions);\n  const program = createTestProgram(connection, programId, admin);\n  const operatorPda = deriveOperator(whitelistOperator, program.programId);\n\n  const operatorAccount = await connection.getAccountInfo(operatorPda);\n  if (operatorAccount) {\n    return operatorPda;\n  }\n\n  await program.methods\n    .createOperatorAccount(encodedPermissions)\n    .accountsPartial({\n      signer: admin.publicKey,\n      operator: operatorPda,\n      whitelistedSigner: whitelistOperator,\n      systemProgram: SystemProgram.programId,\n    })\n    .signers([admin])\n    .rpc();\n\n  return operatorPda;\n}\n"
  },
  {
    "path": "ts-client/src/test/ilm.test.ts",
    "content": "import { BN, Wallet, web3 } from \"@coral-xyz/anchor\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  ExtensionType,\n  TOKEN_2022_PROGRAM_ID,\n  TOKEN_PROGRAM_ID,\n  createInitializeMintInstruction,\n  createInitializeTransferFeeConfigInstruction,\n  createInitializeTransferHookInstruction,\n  createMint,\n  getMintLen,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  PublicKey,\n  SystemProgram,\n  Transaction,\n  sendAndConfirmTransaction,\n} from \"@solana/web3.js\";\nimport babar from \"babar\";\nimport Decimal from \"decimal.js\";\nimport fs from \"fs\";\nimport { FunctionType, LBCLMM_PROGRAM_IDS } from \"../dlmm/constants\";\nimport {\n  deriveCustomizablePermissionlessLbPair,\n  deriveTokenBadge,\n  getBinArrayLowerUpperBinId,\n  getPriceOfBinByBinId,\n} from \"../dlmm/helpers\";\nimport { DLMM } from \"../dlmm/index\";\nimport { ActivationType } from \"../dlmm/types\";\nimport {\n  createTransferHookCounterProgram,\n  TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n} from \"./external/program\";\nimport { createExtraAccountMetaListAndCounter } from \"./external/helper\";\nimport {\n  createTestProgram,\n  createWhitelistOperator,\n  OperatorPermission,\n} from \"./helper\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\n\nconst operator = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\nconst positionOwner = Keypair.generate();\nconst feeOwner = Keypair.generate();\nconst lockDuration = new BN(86400 * 31);\n\nconst programId = new PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\nconst program = createTestProgram(connection, programId, operator);\n\ndescribe(\"ILM test\", () => {\n  describe(\"WEN\", () => {\n    const baseKeypair = Keypair.generate();\n    const wenDecimal = 5;\n    const usdcDecimal = 6;\n    const feeBps = new BN(500);\n\n    let WEN: web3.PublicKey;\n    let USDC: web3.PublicKey;\n    let userWEN: web3.PublicKey;\n    let userUSDC: web3.PublicKey;\n    let pairKey: web3.PublicKey;\n    let pair: DLMM;\n\n    const toLamportMultiplier = new Decimal(10 ** (usdcDecimal - wenDecimal));\n\n    const minPrice = 0.000001;\n    const maxPrice = 0.00003;\n    const binStep = 100;\n    const curvature = 0.6;\n    const seedAmount = new BN(200_000_000_000);\n\n    const minBinId = DLMM.getBinIdFromPrice(\n      new Decimal(minPrice).mul(toLamportMultiplier),\n      binStep,\n      false\n    );\n\n    beforeAll(async () => {\n      WEN = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        wenDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      USDC = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        usdcDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      const userWenInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        WEN,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userWEN = userWenInfo.address;\n\n      const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        USDC,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userUSDC = userUsdcInfo.address;\n\n      await mintTo(\n        connection,\n        operator,\n        WEN,\n        userWEN,\n        operator.publicKey,\n        200_000_000_000 * 10 ** wenDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      await mintTo(\n        connection,\n        operator,\n        USDC,\n        userUSDC,\n        operator.publicKey,\n        1_000_000_000 * 10 ** usdcDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      const slot = await connection.getSlot();\n      const activationPoint = new BN(slot).add(new BN(100));\n\n      let rawTx = await DLMM.createCustomizablePermissionlessLbPair(\n        connection,\n        new BN(binStep),\n        WEN,\n        USDC,\n        new BN(minBinId.toString()),\n        feeBps,\n        ActivationType.Slot,\n        false, // No alpha vault. Set to true the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: https://github.com/MeteoraAg/alpha-vault-sdk initialize{Prorata|Fcfs}Vault method to create the alpha vault.\n        operator.publicKey,\n        activationPoint,\n        false,\n        {\n          cluster: \"localhost\",\n        }\n      );\n\n      let txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        operator,\n      ]).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n      console.log(\"Create permissioned LB pair\", txHash);\n\n      [pairKey] = deriveCustomizablePermissionlessLbPair(WEN, USDC, programId);\n\n      pair = await DLMM.create(connection, pairKey, {\n        cluster: \"localhost\",\n      });\n    });\n\n    it(\"seed liquidity\", async () => {\n      const currentSlot = await connection.getSlot();\n\n      const lockReleaseSlot = lockDuration.add(new BN(currentSlot));\n\n      const {\n        sendPositionOwnerTokenProveIxs,\n        initializeBinArraysAndPositionIxs,\n        addLiquidityIxs,\n      } = await pair.seedLiquidity(\n        positionOwner.publicKey,\n        seedAmount,\n        curvature,\n        minPrice,\n        maxPrice,\n        baseKeypair.publicKey,\n        operator.publicKey,\n        feeOwner.publicKey,\n        operator.publicKey,\n        lockReleaseSlot,\n        true\n      );\n\n      // Send token prove\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transaction = new Transaction({\n          feePayer: operator.publicKey,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...sendPositionOwnerTokenProveIxs);\n\n        await sendAndConfirmTransaction(connection, transaction, [operator]);\n      }\n\n      // Initialize all bin array and position, transaction order can be in sequence or not\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n        const transactions = [];\n\n        for (const groupIx of initializeBinArraysAndPositionIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator, baseKeypair];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const beforeTokenXBalance = await connection\n        .getTokenAccountBalance(userWEN)\n        .then((i) => new BN(i.value.amount));\n\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transactions = [];\n\n        // Deposit to positions created in above step. The add liquidity order can be in sequence or not.\n        for (const groupIx of addLiquidityIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const afterTokenXBalance = await connection\n        .getTokenAccountBalance(userWEN)\n        .then((i) => new BN(i.value.amount));\n\n      const actualDepositedAmount = beforeTokenXBalance.sub(afterTokenXBalance);\n      expect(actualDepositedAmount.toString()).toEqual(seedAmount.toString());\n\n      const positions = await pair.getPositionsByUserAndLbPair(\n        positionOwner.publicKey\n      );\n\n      const positionKeys = positions.userPositions.map((p) => p.publicKey);\n      const positionStates =\n        await pair.program.account.positionV2.fetchMultiple(positionKeys);\n\n      for (const state of positionStates) {\n        expect(state.feeOwner.toBase58()).toBe(feeOwner.publicKey.toBase58());\n        expect(state.owner.toBase58()).toBe(positionOwner.publicKey.toBase58());\n        expect(state.lockReleasePoint.toString()).toBe(\n          lockReleaseSlot.toString()\n        );\n      }\n\n      let binArrays = await pair.getBinArrays();\n      binArrays = binArrays.sort((a, b) =>\n        a.account.index.cmp(b.account.index)\n      );\n\n      const binLiquidities = binArrays\n        .map((ba) => {\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            ba.account.index\n          );\n          const binWithLiquidity: [number, number][] = [];\n          for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n            const binAmountX =\n              ba.account.bins[i - lowerBinId.toNumber()].amountX;\n            const binPrice = getPriceOfBinByBinId(i, pair.lbPair.binStep);\n            const liquidity = new Decimal(binAmountX.toString())\n              .mul(binPrice)\n              .floor()\n              .toNumber();\n            binWithLiquidity.push([i, liquidity]);\n          }\n          return binWithLiquidity;\n        })\n        .flat();\n\n      console.log(binLiquidities.filter((b) => b[1] > 0).reverse());\n      console.log(binLiquidities.filter((b) => b[1] > 0));\n      console.log(babar(binLiquidities));\n    });\n  });\n\n  describe(\"Shaky\", () => {\n    const baseKeypair = Keypair.generate();\n    const sharkyDecimal = 6;\n    const usdcDecimal = 6;\n    const feeBps = new BN(250);\n\n    let SHARKY: web3.PublicKey;\n    let USDC: web3.PublicKey;\n    let userSHAKY: web3.PublicKey;\n    let userUSDC: web3.PublicKey;\n    let pairKey: web3.PublicKey;\n    let pair: DLMM;\n\n    const toLamportMultiplier = new Decimal(\n      10 ** (usdcDecimal - sharkyDecimal)\n    );\n\n    const minPrice = 0.5;\n    const maxPrice = 1.62;\n    const binStep = 80;\n    const curvature = 1;\n    const seedAmount = new BN(5_000_000_000_000);\n\n    const minBinId = DLMM.getBinIdFromPrice(\n      new Decimal(minPrice).mul(toLamportMultiplier),\n      binStep,\n      false\n    );\n\n    beforeAll(async () => {\n      SHARKY = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        sharkyDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      USDC = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        usdcDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      const userShakyInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        SHARKY,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userSHAKY = userShakyInfo.address;\n\n      const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        USDC,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userUSDC = userUsdcInfo.address;\n\n      await mintTo(\n        connection,\n        operator,\n        SHARKY,\n        userSHAKY,\n        operator.publicKey,\n        200_000_000_000 * 10 ** sharkyDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      await mintTo(\n        connection,\n        operator,\n        USDC,\n        userUSDC,\n        operator.publicKey,\n        1_000_000_000 * 10 ** usdcDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      const slot = await connection.getSlot();\n      const activationPoint = new BN(slot).add(new BN(100));\n\n      let rawTx = await DLMM.createCustomizablePermissionlessLbPair(\n        connection,\n        new BN(binStep),\n        SHARKY,\n        USDC,\n        new BN(minBinId.toString()),\n        feeBps,\n        ActivationType.Slot,\n        false, // No alpha vault. Set to true the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: https://github.com/MeteoraAg/alpha-vault-sdk initialize{Prorata|Fcfs}Vault method to create the alpha vault.\n        operator.publicKey,\n        activationPoint,\n        false,\n        {\n          cluster: \"localhost\",\n        }\n      );\n\n      let txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        operator,\n      ]).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n      console.log(\"Create permissioned LB pair\", txHash);\n\n      [pairKey] = deriveCustomizablePermissionlessLbPair(\n        SHARKY,\n        USDC,\n        programId\n      );\n\n      pair = await DLMM.create(connection, pairKey, {\n        cluster: \"localhost\",\n      });\n    });\n\n    it(\"seed liquidity\", async () => {\n      const currentSlot = await connection.getSlot();\n\n      const lockReleaseSlot = new BN(currentSlot).add(lockDuration);\n\n      const {\n        sendPositionOwnerTokenProveIxs,\n        initializeBinArraysAndPositionIxs,\n        addLiquidityIxs,\n      } = await pair.seedLiquidity(\n        positionOwner.publicKey,\n        seedAmount,\n        curvature,\n        minPrice,\n        maxPrice,\n        baseKeypair.publicKey,\n        operator.publicKey,\n        feeOwner.publicKey,\n        operator.publicKey,\n        lockReleaseSlot,\n        true\n      );\n\n      // Send token prove\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transaction = new Transaction({\n          feePayer: operator.publicKey,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...sendPositionOwnerTokenProveIxs);\n\n        await sendAndConfirmTransaction(connection, transaction, [operator]);\n      }\n\n      // Initialize all bin array and position, transaction order can be in sequence or not\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n        const transactions = [];\n\n        for (const groupIx of initializeBinArraysAndPositionIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator, baseKeypair];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const beforeTokenXBalance = await connection\n        .getTokenAccountBalance(userSHAKY)\n        .then((i) => new BN(i.value.amount));\n\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transactions = [];\n\n        // Deposit to positions created in above step. The add liquidity order can be in sequence or not.\n        for (const groupIx of addLiquidityIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const afterTokenXBalance = await connection\n        .getTokenAccountBalance(userSHAKY)\n        .then((i) => new BN(i.value.amount));\n\n      const actualDepositedAmount = beforeTokenXBalance.sub(afterTokenXBalance);\n      expect(actualDepositedAmount.toString()).toEqual(seedAmount.toString());\n\n      const positions = await pair.getPositionsByUserAndLbPair(\n        positionOwner.publicKey\n      );\n\n      const positionKeys = positions.userPositions.map((p) => p.publicKey);\n      const positionStates =\n        await pair.program.account.positionV2.fetchMultiple(positionKeys);\n\n      for (const state of positionStates) {\n        expect(state.feeOwner.toBase58()).toBe(feeOwner.publicKey.toBase58());\n        expect(state.owner.toBase58()).toBe(positionOwner.publicKey.toBase58());\n        expect(state.lockReleasePoint.toString()).toBe(\n          lockReleaseSlot.toString()\n        );\n      }\n\n      let binArrays = await pair.getBinArrays();\n      binArrays = binArrays.sort((a, b) =>\n        a.account.index.cmp(b.account.index)\n      );\n\n      const binLiquidities = binArrays\n        .map((ba) => {\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            ba.account.index\n          );\n          const binWithLiquidity: [number, number][] = [];\n          for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n            const binAmountX =\n              ba.account.bins[i - lowerBinId.toNumber()].amountX;\n            const binPrice = getPriceOfBinByBinId(i, pair.lbPair.binStep);\n            const liquidity = new Decimal(binAmountX.toString())\n              .mul(binPrice)\n              .floor()\n              .toNumber();\n            binWithLiquidity.push([i, liquidity]);\n          }\n          return binWithLiquidity;\n        })\n        .flat();\n\n      console.log(binLiquidities.filter((b) => b[1] > 0).reverse());\n      console.log(binLiquidities.filter((b) => b[1] > 0));\n      console.log(babar(binLiquidities));\n    });\n  });\n\n  describe(\"Token 2022\", () => {\n    const baseKeypair = Keypair.generate();\n    const dummyDecimal = 6;\n    const usdcDecimal = 6;\n    const feeBps = new BN(250);\n\n    const transferFeeBps = 500; // 5%\n    const maxFee = BigInt(100_000) * BigInt(10 ** dummyDecimal);\n\n    const DUMMYKeypair = Keypair.generate();\n    let DUMMY: web3.PublicKey = DUMMYKeypair.publicKey;\n    let USDC: web3.PublicKey;\n    let userDUMMY: web3.PublicKey;\n    let userUSDC: web3.PublicKey;\n    let pairKey: web3.PublicKey;\n    let pair: DLMM;\n\n    const toLamportMultiplier = new Decimal(10 ** (usdcDecimal - dummyDecimal));\n\n    const minPrice = 0.5;\n    const maxPrice = 1.62;\n    const binStep = 80;\n    const curvature = 1;\n    const seedAmount = new BN(5_000_000_000_000);\n\n    const minBinId = DLMM.getBinIdFromPrice(\n      new Decimal(minPrice).mul(toLamportMultiplier),\n      binStep,\n      false\n    );\n\n    beforeAll(async () => {\n      const extensions = [\n        ExtensionType.TransferFeeConfig,\n        ExtensionType.TransferHook,\n      ];\n\n      const mintLen = getMintLen(extensions);\n      const minLamports = await connection.getMinimumBalanceForRentExemption(\n        mintLen\n      );\n\n      const createDummyTx = new Transaction()\n        .add(\n          SystemProgram.createAccount({\n            fromPubkey: operator.publicKey,\n            newAccountPubkey: DUMMYKeypair.publicKey,\n            space: mintLen,\n            lamports: minLamports,\n            programId: TOKEN_2022_PROGRAM_ID,\n          })\n        )\n        .add(\n          createInitializeTransferFeeConfigInstruction(\n            DUMMY,\n            operator.publicKey,\n            operator.publicKey,\n            transferFeeBps,\n            maxFee,\n            TOKEN_2022_PROGRAM_ID\n          )\n        )\n        .add(\n          createInitializeTransferHookInstruction(\n            DUMMY,\n            operator.publicKey,\n            TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n            TOKEN_2022_PROGRAM_ID\n          )\n        )\n        .add(\n          createInitializeMintInstruction(\n            DUMMY,\n            dummyDecimal,\n            operator.publicKey,\n            null,\n            TOKEN_2022_PROGRAM_ID\n          )\n        );\n\n      await sendAndConfirmTransaction(\n        connection,\n        createDummyTx,\n        [operator, DUMMYKeypair],\n        { commitment: \"confirmed\" }\n      );\n\n      const transferHookCounterProgram = createTransferHookCounterProgram(\n        new Wallet(operator),\n        TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n        connection\n      );\n\n      await createExtraAccountMetaListAndCounter(\n        transferHookCounterProgram,\n        DUMMY\n      );\n\n      USDC = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        usdcDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      const userDummyInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        DUMMY,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_2022_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userDUMMY = userDummyInfo.address;\n\n      await mintTo(\n        connection,\n        operator,\n        DUMMY,\n        userDUMMY,\n        operator,\n        BigInt(100_000_000_000_000) * BigInt(10 ** dummyDecimal),\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_2022_PROGRAM_ID\n      );\n\n      const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        USDC,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userUSDC = userUsdcInfo.address;\n\n      await mintTo(\n        connection,\n        operator,\n        USDC,\n        userUSDC,\n        operator.publicKey,\n        1_000_000_000 * 10 ** usdcDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      const [dummyTokenBadge] = deriveTokenBadge(DUMMY, program.programId);\n\n      const operatorPda = await createWhitelistOperator(\n        connection,\n        operator,\n        operator.publicKey,\n        [OperatorPermission.InitializeTokenBadge],\n        program.programId\n      );\n\n      await program.methods\n        .initializeTokenBadge()\n        .accountsPartial({\n          tokenBadge: dummyTokenBadge,\n          signer: operator.publicKey,\n          systemProgram: SystemProgram.programId,\n          tokenMint: DUMMY,\n          operator: operatorPda,\n        })\n        .rpc();\n\n      const slot = await connection.getSlot();\n      const activationPoint = new BN(slot).add(new BN(100));\n\n      let rawTx = await DLMM.createCustomizablePermissionlessLbPair2(\n        connection,\n        new BN(binStep),\n        DUMMY,\n        USDC,\n        new BN(minBinId.toString()),\n        feeBps,\n        ActivationType.Slot,\n        false, // No alpha vault. Set to true the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: https://github.com/MeteoraAg/alpha-vault-sdk initialize{Prorata|Fcfs}Vault method to create the alpha vault.\n        operator.publicKey,\n        activationPoint,\n        false,\n        {\n          cluster: \"localhost\",\n        }\n      );\n\n      let txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        operator,\n      ]).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n      console.log(\"Create permissioned LB pair\", txHash);\n\n      [pairKey] = deriveCustomizablePermissionlessLbPair(\n        DUMMY,\n        USDC,\n        programId\n      );\n\n      pair = await DLMM.create(connection, pairKey, {\n        cluster: \"localhost\",\n      });\n    });\n\n    it(\"seed liquidity\", async () => {\n      const currentSlot = await connection.getSlot();\n\n      const lockReleaseSlot = new BN(currentSlot).add(lockDuration);\n\n      const {\n        sendPositionOwnerTokenProveIxs,\n        initializeBinArraysAndPositionIxs,\n        addLiquidityIxs,\n      } = await pair.seedLiquidity(\n        positionOwner.publicKey,\n        seedAmount,\n        curvature,\n        minPrice,\n        maxPrice,\n        baseKeypair.publicKey,\n        operator.publicKey,\n        feeOwner.publicKey,\n        operator.publicKey,\n        lockReleaseSlot,\n        true\n      );\n\n      // Send token prove\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transaction = new Transaction({\n          feePayer: operator.publicKey,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...sendPositionOwnerTokenProveIxs);\n\n        await sendAndConfirmTransaction(connection, transaction, [operator]);\n      }\n\n      // Initialize all bin array and position, transaction order can be in sequence or not\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n        const transactions = [];\n\n        for (const groupIx of initializeBinArraysAndPositionIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator, baseKeypair];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const beforeTokenXBalance = await connection\n        .getTokenAccountBalance(pair.lbPair.reserveX)\n        .then((i) => new BN(i.value.amount));\n\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transactions = [];\n\n        // Deposit to positions created in above step. The add liquidity order can be in sequence or not.\n        for (const groupIx of addLiquidityIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const afterTokenXBalance = await connection\n        .getTokenAccountBalance(pair.lbPair.reserveX)\n        .then((i) => new BN(i.value.amount));\n\n      const actualDepositedAmount = afterTokenXBalance.sub(beforeTokenXBalance);\n      expect(actualDepositedAmount.toString()).toEqual(seedAmount.toString());\n\n      const positions = await pair.getPositionsByUserAndLbPair(\n        positionOwner.publicKey\n      );\n\n      const positionKeys = positions.userPositions.map((p) => p.publicKey);\n      const positionStates =\n        await pair.program.account.positionV2.fetchMultiple(positionKeys);\n\n      for (const state of positionStates) {\n        expect(state.feeOwner.toBase58()).toBe(feeOwner.publicKey.toBase58());\n        expect(state.owner.toBase58()).toBe(positionOwner.publicKey.toBase58());\n        expect(state.lockReleasePoint.toString()).toBe(\n          lockReleaseSlot.toString()\n        );\n      }\n\n      let binArrays = await pair.getBinArrays();\n      binArrays = binArrays.sort((a, b) =>\n        a.account.index.cmp(b.account.index)\n      );\n\n      const binLiquidities = binArrays\n        .map((ba) => {\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            ba.account.index\n          );\n          const binWithLiquidity: [number, number][] = [];\n          for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n            const binAmountX =\n              ba.account.bins[i - lowerBinId.toNumber()].amountX;\n            const binPrice = getPriceOfBinByBinId(i, pair.lbPair.binStep);\n            const liquidity = new Decimal(binAmountX.toString())\n              .mul(binPrice)\n              .floor()\n              .toNumber();\n            binWithLiquidity.push([i, liquidity]);\n          }\n          return binWithLiquidity;\n        })\n        .flat();\n\n      console.log(binLiquidities.filter((b) => b[1] > 0).reverse());\n      console.log(binLiquidities.filter((b) => b[1] > 0));\n      console.log(babar(binLiquidities));\n    });\n  });\n});\n\ndescribe(\"Edge test\", () => {\n  describe(\"Thin liquidity at the beginning of the curve\", () => {\n    const baseKeypair = Keypair.generate();\n    const feePayerKeypair = Keypair.generate();\n    const tokenDecimal = 8;\n    const usdcDecimal = 6;\n    const feeBps = new BN(500);\n\n    let TOKEN: web3.PublicKey;\n    let USDC: web3.PublicKey;\n    let userTOKEN: web3.PublicKey;\n    let userUSDC: web3.PublicKey;\n    let pairKey: web3.PublicKey;\n    let pair: DLMM;\n\n    const toLamportMultiplier = new Decimal(10 ** (usdcDecimal - tokenDecimal));\n\n    const minPrice = 0.0001;\n    const maxPrice = 0.006966448211669921;\n    const binStep = 100;\n    const curvature = 0.4;\n    const seedAmount = new BN(\"19600000\").mul(new BN(10 ** tokenDecimal));\n\n    const minBinId = DLMM.getBinIdFromPrice(\n      new Decimal(minPrice).mul(toLamportMultiplier),\n      binStep,\n      false\n    );\n\n    beforeAll(async () => {\n      await connection.requestAirdrop(\n        feePayerKeypair.publicKey,\n        10 * LAMPORTS_PER_SOL\n      );\n\n      TOKEN = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        tokenDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      USDC = await createMint(\n        connection,\n        operator,\n        operator.publicKey,\n        null,\n        usdcDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      const userTokenInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        TOKEN,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userTOKEN = userTokenInfo.address;\n\n      const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        operator,\n        USDC,\n        operator.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userUSDC = userUsdcInfo.address;\n\n      await mintTo(\n        connection,\n        operator,\n        TOKEN,\n        userTOKEN,\n        operator.publicKey,\n        200_000_000_000 * 10 ** tokenDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      await mintTo(\n        connection,\n        operator,\n        USDC,\n        userUSDC,\n        operator.publicKey,\n        1_000_000_000 * 10 ** usdcDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      const slot = await connection.getSlot();\n      const activationPoint = new BN(slot).add(new BN(100));\n\n      let rawTx = await DLMM.createCustomizablePermissionlessLbPair2(\n        connection,\n        new BN(binStep),\n        TOKEN,\n        USDC,\n        new BN(minBinId.toString()),\n        feeBps,\n        ActivationType.Slot,\n        false, // No alpha vault. Set to true the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: https://github.com/MeteoraAg/alpha-vault-sdk initialize{Prorata|Fcfs}Vault method to create the alpha vault.\n        operator.publicKey,\n        activationPoint,\n        false,\n        {\n          cluster: \"localhost\",\n        }\n      );\n\n      let txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        operator,\n      ]).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n      console.log(\"Create customlzable permissionless LB pair 2\", txHash);\n\n      [pairKey] = deriveCustomizablePermissionlessLbPair(\n        TOKEN,\n        USDC,\n        programId\n      );\n\n      pair = await DLMM.create(connection, pairKey, {\n        cluster: \"localhost\",\n      });\n    });\n\n    it(\"seed liquidity\", async () => {\n      const currentSlot = await connection.getSlot();\n\n      const lockReleaseSlot = lockDuration.add(new BN(currentSlot));\n\n      const {\n        sendPositionOwnerTokenProveIxs,\n        initializeBinArraysAndPositionIxs,\n        addLiquidityIxs,\n      } = await pair.seedLiquidity(\n        positionOwner.publicKey,\n        seedAmount,\n        curvature,\n        minPrice,\n        maxPrice,\n        baseKeypair.publicKey,\n        feePayerKeypair.publicKey,\n        feeOwner.publicKey,\n        operator.publicKey,\n        lockReleaseSlot,\n        true\n      );\n\n      // Send token prove\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transaction = new Transaction({\n          feePayer: operator.publicKey,\n          blockhash,\n          lastValidBlockHeight,\n        }).add(...sendPositionOwnerTokenProveIxs);\n\n        await sendAndConfirmTransaction(connection, transaction, [\n          feePayerKeypair,\n          operator,\n        ]);\n      }\n\n      // Initialize all bin array and position, transaction order can be in sequence or not\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n        const transactions = [];\n\n        for (const groupIx of initializeBinArraysAndPositionIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [feePayerKeypair, operator, baseKeypair];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const beforeTokenXBalance = await connection\n        .getTokenAccountBalance(userTOKEN)\n        .then((i) => new BN(i.value.amount));\n\n      {\n        const { blockhash, lastValidBlockHeight } =\n          await connection.getLatestBlockhash(\"confirmed\");\n\n        const transactions = [];\n\n        // Deposit to positions created in above step. The add liquidity order can be in sequence or not.\n        for (const groupIx of addLiquidityIxs) {\n          const tx = new Transaction({\n            feePayer: operator.publicKey,\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...groupIx);\n\n          const signers = [operator];\n\n          transactions.push(sendAndConfirmTransaction(connection, tx, signers));\n        }\n\n        await Promise.all(transactions)\n          .then((txs) => {\n            txs.map(console.log);\n          })\n          .catch((e) => {\n            console.error(e);\n            throw e;\n          });\n      }\n\n      const afterTokenXBalance = await connection\n        .getTokenAccountBalance(userTOKEN)\n        .then((i) => new BN(i.value.amount));\n\n      const actualDepositedAmount = beforeTokenXBalance.sub(afterTokenXBalance);\n      console.log(actualDepositedAmount.toString());\n      expect(actualDepositedAmount.toString()).toEqual(seedAmount.toString());\n\n      const positions = await pair.getPositionsByUserAndLbPair(\n        positionOwner.publicKey\n      );\n\n      const positionKeys = positions.userPositions.map((p) => p.publicKey);\n      const positionStates =\n        await pair.program.account.positionV2.fetchMultiple(positionKeys);\n\n      for (const state of positionStates) {\n        expect(state.feeOwner.toBase58()).toBe(feeOwner.publicKey.toBase58());\n        expect(state.owner.toBase58()).toBe(positionOwner.publicKey.toBase58());\n        expect(state.lockReleasePoint.toString()).toBe(\n          lockReleaseSlot.toString()\n        );\n      }\n\n      let binArrays = await pair.getBinArrays();\n      binArrays = binArrays.sort((a, b) =>\n        a.account.index.cmp(b.account.index)\n      );\n\n      const binLiquidities = binArrays\n        .map((ba) => {\n          const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(\n            ba.account.index\n          );\n          const binWithLiquidity: [number, number][] = [];\n          for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n            const binAmountX =\n              ba.account.bins[i - lowerBinId.toNumber()].amountX;\n            const binPrice = getPriceOfBinByBinId(i, pair.lbPair.binStep);\n            const liquidity = new Decimal(binAmountX.toString())\n              .mul(binPrice)\n              .floor()\n              .toNumber();\n            binWithLiquidity.push([i, liquidity]);\n          }\n          return binWithLiquidity;\n        })\n        .flat();\n\n      console.log(binLiquidities.filter((b) => b[1] > 0).reverse());\n      console.log(binLiquidities.filter((b) => b[1] > 0));\n      console.log(babar(binLiquidities));\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/oracle.test.ts",
    "content": "import BN from \"bn.js\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport Decimal from \"decimal.js\";\nimport {\n  DynamicOracle,\n  Observation,\n} from \"../dlmm/helpers/oracle/wrapper\";\nimport { Oracle } from \"../dlmm/types\";\nimport { getPriceOfBinByBinId } from \"../dlmm/helpers/weight\";\n\nfunction obs(\n  cumulative: number,\n  createdAt: number,\n  lastUpdatedAt: number\n): Observation {\n  return new Observation(\n    new BN(cumulative),\n    new BN(createdAt),\n    new BN(lastUpdatedAt)\n  );\n}\n\nconst UNINIT = obs(0, 0, 0);\n\nfunction createOracle(params: {\n  idx: number;\n  activeSize: number;\n  observations: Observation[];\n  binStep?: number;\n  currentActiveBinId?: number;\n  baseTokenDecimals?: number;\n  quoteTokenDecimals?: number;\n}): DynamicOracle {\n  const metadata = {\n    idx: new BN(params.idx),\n    activeSize: new BN(params.activeSize),\n    length: new BN(params.observations.length),\n  } as Oracle;\n\n  return new DynamicOracle(\n    PublicKey.default,\n    metadata,\n    params.observations,\n    params.binStep ?? 1,\n    new BN(params.currentActiveBinId ?? 100),\n    params.baseTokenDecimals ?? 9,\n    params.quoteTokenDecimals ?? 6\n  );\n}\n\ndescribe(\"DynamicOracle\", () => {\n  // Standard buffer: constant bin ID = 100, cumId(t) = 100 * t\n  // idx=2, activeSize=3 → earliest at obs[0] (nextIndex=0)\n  const standardObs = () => [\n    obs(10000, 100, 100), // t=100\n    obs(20000, 200, 200), // t=200\n    obs(30000, 300, 300), // t=300 (latest)\n  ];\n\n  describe(\"nextIndex\", () => {\n    it(\"wraps to 0 when idx is at last position\", () => {\n      const oracle = createOracle({\n        idx: 4,\n        activeSize: 5,\n        observations: [obs(0, 1, 1), obs(0, 1, 1), obs(0, 1, 1), obs(0, 1, 1), obs(0, 1, 1)],\n      });\n      expect(oracle.nextIndex()).toBe(0);\n    });\n\n    it(\"wraps with activeSize=1\", () => {\n      const oracle = createOracle({\n        idx: 0,\n        activeSize: 1,\n        observations: [obs(0, 1, 1)],\n      });\n      expect(oracle.nextIndex()).toBe(0);\n    });\n  });\n\n  describe(\"getEarliestSample / getLatestSample\", () => {\n    it(\"getLatestSample returns observations[idx]\", () => {\n      const oracle = createOracle({ idx: 1, activeSize: 3, observations: standardObs() });\n      expect(oracle.getLatestSample().cumulativeActiveBinId.toNumber()).toBe(20000);\n    });\n\n    it(\"getEarliestSample returns observations[nextIndex()]\", () => {\n      // idx=1, activeSize=3 → nextIndex=2\n      const oracle = createOracle({ idx: 1, activeSize: 3, observations: standardObs() });\n      expect(oracle.getEarliestSample().cumulativeActiveBinId.toNumber()).toBe(30000);\n    });\n\n    it(\"both return same observation when activeSize=1\", () => {\n      const oracle = createOracle({ idx: 0, activeSize: 1, observations: [obs(10, 100, 100)] });\n      expect(oracle.getEarliestSample()).toBe(oracle.getLatestSample());\n    });\n  });\n\n  describe(\"getEarliestTimestamp\", () => {\n    it(\"returns lastUpdatedAt when earliest is initialized\", () => {\n      const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n      // nextIndex=0, earliest=obs[0] with lastUpdatedAt=100\n      expect(oracle.getEarliestTimestamp().toNumber()).toBe(100);\n    });\n\n    it(\"returns null when earliest is uninitialized\", () => {\n      // idx=0, activeSize=2 → earliest=obs[1] which is UNINIT\n      const oracle = createOracle({ idx: 0, activeSize: 2, observations: [obs(10, 100, 100), UNINIT] });\n      expect(oracle.getEarliestTimestamp()).toBeNull();\n    });\n  });\n\n  describe(\"getMaxDuration\", () => {\n    it(\"returns currentTimestamp - earliest when valid\", () => {\n      const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n      expect(oracle.getMaxDuration(new BN(500)).toNumber()).toBe(400);\n    });\n\n    it(\"returns 0 when no initialized observations\", () => {\n      const oracle = createOracle({ idx: 0, activeSize: 2, observations: [UNINIT, UNINIT] });\n      expect(oracle.getMaxDuration(new BN(500)).toNumber()).toBe(0);\n    });\n\n    it(\"returns 0 when currentTimestamp <= earliest\", () => {\n      const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n      expect(oracle.getMaxDuration(new BN(100)).toNumber()).toBe(0);\n      expect(oracle.getMaxDuration(new BN(50)).toNumber()).toBe(0);\n    });\n  });\n\n  describe(\"findCumulativeActiveIdByTimestamp\", () => {\n    const activeId = new BN(100);\n\n    describe(\"null cases\", () => {\n      it(\"returns null when latest sample is uninitialized\", () => {\n        const oracle = createOracle({ idx: 0, activeSize: 1, observations: [UNINIT] });\n        expect(oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(100))).toBeNull();\n      });\n\n      it(\"returns null when timestamp is before earliest\", () => {\n        const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n        // earliest at t=100, query t=50\n        expect(oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(50))).toBeNull();\n      });\n    });\n\n    describe(\"forward extrapolation\", () => {\n      it(\"timestamp equals latest returns latest cumId\", () => {\n        const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n        // latest at t=300, cumId=30000. delta=0, so result=30000\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(300));\n        expect(result.toNumber()).toBe(30000);\n      });\n\n      it(\"timestamp after latest extrapolates with activeId\", () => {\n        const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n        // latest cumId=30000, t=300. query t=400. delta=100. result=30000 + 100*100 = 40000\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(400));\n        expect(result.toNumber()).toBe(40000);\n      });\n\n      it(\"extrapolation with negative activeId\", () => {\n        const oracle = createOracle({\n          idx: 2,\n          activeSize: 3,\n          observations: standardObs(),\n          currentActiveBinId: -50,\n        });\n        // latest cumId=30000, t=300. query t=500. delta=200. result=30000 + (-50)*200 = 20000\n        const result = oracle.findCumulativeActiveIdByTimestamp(new BN(-50), new BN(500));\n        expect(result.toNumber()).toBe(20000);\n      });\n    });\n\n    describe(\"interpolation\", () => {\n      it(\"timestamp exactly at a non-latest observation\", () => {\n        const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n        // Walk: (2,1). timestamp=200 >= obs[1].lastUpdatedAt=200? Yes.\n        // totalWeight=300-200=100, prevWeight=300-200=100, nextWeight=200-200=0\n        // result = (20000*100 + 30000*0) / 100 = 20000\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(200));\n        expect(result.toNumber()).toBe(20000);\n      });\n\n      it(\"timestamp at midpoint between two observations\", () => {\n        const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n        // Walk: (2,1). timestamp=250 >= obs[1].lastUpdatedAt=200? Yes.\n        // totalWeight=100, prevWeight=50, nextWeight=50\n        // result = (20000*50 + 30000*50) / 100 = 25000\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(250));\n        expect(result.toNumber()).toBe(25000);\n      });\n\n      it(\"circular buffer wraparound during walk\", () => {\n        // idx=1, activeSize=4 → walk: (1,0), (0,3), (3,2)\n        // earliest = obs[2] (nextIndex=2)\n        const observations = [\n          obs(100, 200, 200),  // obs[0]\n          obs(300, 400, 400),  // obs[1] (latest, idx=1)\n          obs(0, 100, 100),    // obs[2] (earliest, nextIndex=2)\n          obs(50, 150, 150),   // obs[3]\n        ];\n        const oracle = createOracle({ idx: 1, activeSize: 4, observations });\n\n        // Query timestamp=125 (between obs[2] at t=100 and obs[3] at t=150)\n        // Walk: (1,0): 125 >= obs[0].lastUpdatedAt=200? No.\n        //        (0,3): wrap. 125 >= obs[3].lastUpdatedAt=150? No.\n        //        (3,2): 125 >= obs[2].lastUpdatedAt=100? Yes.\n        // totalWeight=150-100=50, prevWeight=150-125=25, nextWeight=125-100=25\n        // result = (0*25 + 50*25) / 50 = 25\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(125));\n        expect(result.toNumber()).toBe(25);\n      });\n\n      it(\"negative cumulative values\", () => {\n        const observations = [\n          obs(-500, 100, 100), // obs[0] (earliest)\n          obs(-200, 200, 200), // obs[1] (latest)\n        ];\n        const oracle = createOracle({ idx: 1, activeSize: 2, observations });\n\n        // Query timestamp=150 (midpoint)\n        // Walk: (1,0). 150 >= obs[0].lastUpdatedAt=100? Yes.\n        // totalWeight=100, prevWeight=50, nextWeight=50\n        // result = (-500*50 + -200*50) / 100 = -35000 / 100 = -350\n        const result = oracle.findCumulativeActiveIdByTimestamp(activeId, new BN(150));\n        expect(result.toNumber()).toBe(-350);\n      });\n    });\n  });\n\n  describe(\"getActiveIdByTime\", () => {\n    it(\"constant active bin TWAP equals that bin ID\", () => {\n      // cumId(t) = 100*t. TWAP(100, 300) = (30000 - 10000) / 200 = 100\n      const oracle = createOracle({ idx: 2, activeSize: 3, observations: standardObs() });\n      const result = oracle.getActiveIdByTime(new BN(100), new BN(300));\n      expect(result.value.toNumber()).toBe(100);\n      expect(result.duration.toNumber()).toBe(200);\n    });\n  });\n\n  describe(\"getActiveId\", () => {\n    it(\"returns TWAP from earliest to currentTimestamp\", () => {\n      const oracle = createOracle({\n        idx: 2,\n        activeSize: 3,\n        observations: standardObs(),\n        currentActiveBinId: 100,\n      });\n      // earliest=100, currentTimestamp=400\n      // cumId(100)=10000, cumId(400)=30000+100*100=40000\n      // TWAP = (40000 - 10000) / 300 = 100\n      const result = oracle.getActiveId(new BN(400));\n      expect(result.value.toNumber()).toBe(100);\n      expect(result.duration.toNumber()).toBe(300);\n    });\n  });\n\n  describe(\"getPriceByTime\", () => {\n    it(\"positive bin ID produces correct price\", () => {\n      // TWAP bin ID = 100 with binStep=10\n      const oracle = createOracle({\n        idx: 2,\n        activeSize: 3,\n        observations: standardObs(),\n        binStep: 10,\n      });\n      const result = oracle.getPriceByTime(new BN(100), new BN(300));\n      const expectedPrice = getPriceOfBinByBinId(100, 10);\n      expect(result.value.eq(expectedPrice)).toBe(true);\n      expect(result.duration.toNumber()).toBe(200);\n    });\n  });\n\n  describe(\"getUiPriceByTime\", () => {\n    it(\"base=9 quote=6 applies multiplier and floors to quoteDecimals\", () => {\n      // TWAP bin ID = 100, binStep=10, base=9, quote=6\n      const oracle = createOracle({\n        idx: 2,\n        activeSize: 3,\n        observations: standardObs(),\n        binStep: 10,\n        baseTokenDecimals: 9,\n        quoteTokenDecimals: 6,\n      });\n      const result = oracle.getUiPriceByTime(new BN(100), new BN(300));\n\n      const rawPrice = getPriceOfBinByBinId(100, 10);\n      const uiMultiplier = new Decimal(10).pow(9 - 6);\n      const quoteAdjustment = new Decimal(10).pow(6);\n      const expectedUiPrice = rawPrice\n        .mul(uiMultiplier)\n        .mul(quoteAdjustment)\n        .floor()\n        .div(quoteAdjustment);\n\n      expect(result.value.eq(expectedUiPrice)).toBe(true);\n      expect(result.duration.toNumber()).toBe(200);\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/rebalance.test.ts",
    "content": "import { BN, web3 } from \"@coral-xyz/anchor\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  createMint,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n  TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  sendAndConfirmTransaction,\n  Transaction,\n} from \"@solana/web3.js\";\nimport fs from \"fs\";\nimport {\n  BASIS_POINT_MAX,\n  FunctionType,\n  LBCLMM_PROGRAM_IDS,\n} from \"../dlmm/constants\";\nimport IDL from \"../dlmm/idl/idl.json\";\nimport {\n  deriveLbPairWithPresetParamWithIndexKey,\n  derivePresetParameterWithIndex,\n} from \"../dlmm/helpers\";\nimport {\n  buildLiquidityStrategyParameters,\n  getLiquidityStrategyParameterBuilder,\n} from \"../dlmm/helpers/rebalance\";\nimport { DLMM } from \"../dlmm/index\";\nimport { LbPosition, StrategyType } from \"../dlmm/types\";\nimport {\n  assertEqRebalanceSimulationWithActualResult,\n  createTestProgram,\n  createWhitelistOperator,\n  OperatorPermission,\n} from \"./helper\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\nconst btcDecimal = 6;\nconst usdcDecimal = 6;\n\nconst CONSTANTS = Object.entries(IDL.constants);\nconst BIN_ARRAY_BITMAP_SIZE = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"BIN_ARRAY_BITMAP_SIZE\")[1].value\n);\nexport const MAX_BIN_PER_ARRAY = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"MAX_BIN_PER_ARRAY\")[1].value\n);\n\nconst DEFAULT_ACTIVE_ID = new BN(1);\nconst DEFAULT_BIN_STEP = new BN(10);\nconst DEFAULT_BASE_FACTOR_2 = new BN(4000);\n\nconst programId = new web3.PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\n\nlet BTC: web3.PublicKey;\nlet USDC: web3.PublicKey;\nlet lbPairPubkey: web3.PublicKey;\nlet userBTC: web3.PublicKey;\nlet userUSDC: web3.PublicKey;\nlet presetParamPda2: web3.PublicKey;\n\nconst strategySet: StrategyType[] = [\n  StrategyType.Spot,\n  StrategyType.BidAsk,\n  StrategyType.Curve,\n];\n\ndescribe(\"Rebalance\", () => {\n  beforeEach(async () => {\n    BTC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      btcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    USDC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      usdcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    const userBtcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      BTC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userBTC = userBtcInfo.address;\n\n    const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      USDC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userUSDC = userUsdcInfo.address;\n\n    await mintTo(\n      connection,\n      keypair,\n      BTC,\n      userBTC,\n      keypair.publicKey,\n      100_000_000 * 10 ** btcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    await mintTo(\n      connection,\n      keypair,\n      USDC,\n      userUSDC,\n      keypair.publicKey,\n      100_000_000 * 10 ** usdcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    const { presetParameter2 } = await DLMM.getAllPresetParameters(connection, {\n      cluster: \"localhost\",\n    });\n\n    const index = new BN(presetParameter2.length);\n\n    [presetParamPda2] = derivePresetParameterWithIndex(index, programId);\n\n    const program = createTestProgram(connection, programId, keypair);\n\n    const operatorPda = await createWhitelistOperator(\n      connection,\n      keypair,\n      keypair.publicKey,\n      [OperatorPermission.InitializePresetParameter],\n      programId\n    );\n\n    const presetParamState2 =\n      await program.account.presetParameter.fetchNullable(presetParamPda2);\n\n    if (!presetParamState2) {\n      await program.methods\n        .initializePresetParameter({\n          index: index.toNumber(),\n          binStep: DEFAULT_BIN_STEP.toNumber(),\n          baseFactor: DEFAULT_BASE_FACTOR_2.toNumber(),\n          functionType: FunctionType.LiquidityMining,\n          filterPeriod: 30,\n          decayPeriod: 600,\n          reductionFactor: 5000,\n          variableFeeControl: 40000,\n          protocolShare: 0,\n          maxVolatilityAccumulator: 350000,\n          baseFeePowerFactor: 0,\n        })\n        .accountsPartial({\n          signer: keypair.publicKey,\n          presetParameter: presetParamPda2,\n          systemProgram: web3.SystemProgram.programId,\n          operator: operatorPda,\n        })\n        .signers([keypair])\n        .rpc({\n          commitment: \"confirmed\",\n        });\n    }\n\n    let rawTx = await DLMM.createLbPair2(\n      connection,\n      keypair.publicKey,\n      BTC,\n      USDC,\n      presetParamPda2,\n      DEFAULT_ACTIVE_ID,\n      { cluster: \"localhost\" }\n    );\n    await sendAndConfirmTransaction(connection, rawTx, [keypair]);\n\n    [lbPairPubkey] = deriveLbPairWithPresetParamWithIndexKey(\n      presetParamPda2,\n      BTC,\n      USDC,\n      programId\n    );\n  });\n\n  it(\"Rebalance with only deposit and auto shrink position\", async () => {\n    const dlmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n\n    for (const strategy of strategySet) {\n      const positionKeypair = Keypair.generate();\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: positionKeypair.publicKey,\n        user: keypair.publicKey,\n        minBinId: dlmm.lbPair.activeId - 30,\n        maxBinId: dlmm.lbPair.activeId + 30,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        positionKeypair,\n        keypair,\n      ]);\n\n      const beforePositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const beforePosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      const strategyParamBuilder =\n        getLiquidityStrategyParameterBuilder(strategy);\n\n      const minDeltaId = new BN(-10);\n      const maxDeltaId = new BN(20);\n      const amountX = new BN(10_000_000);\n      const amountY = new BN(10_000_000);\n      const favorXInActiveBin = false;\n\n      const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        new BN(dlmm.lbPair.binStep),\n        favorXInActiveBin,\n        new BN(dlmm.lbPair.activeId),\n        strategyParamBuilder\n      );\n\n      const { simulationResult, rebalancePosition } =\n        await dlmm.simulateRebalancePosition(\n          positionKeypair.publicKey,\n          beforePosition.positionData,\n          true,\n          true,\n          [\n            {\n              x0,\n              y0,\n              deltaX,\n              deltaY,\n              minDeltaId,\n              maxDeltaId,\n              favorXInActiveBin,\n            },\n          ],\n          [\n            {\n              minBinId: new BN(beforePosition.positionData.lowerBinId),\n              maxBinId: new BN(beforePosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        );\n\n      const { initBinArrayInstructions, rebalancePositionInstruction } =\n        await dlmm.rebalancePosition(\n          { simulationResult, rebalancePosition },\n          new BN(0)\n        );\n\n      const { lastValidBlockHeight, blockhash } =\n        await connection.getLatestBlockhash();\n\n      await Promise.all(\n        initBinArrayInstructions.map((ix) => {\n          const transaction = new Transaction({\n            lastValidBlockHeight,\n            blockhash,\n          }).add(ix);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        })\n      );\n\n      const rebalanceTx = new Transaction({\n        lastValidBlockHeight,\n        blockhash,\n      }).add(...rebalancePositionInstruction);\n\n      await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]).then(\n        console.log\n      );\n\n      const afterPositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n      const afterPosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      assertEqRebalanceSimulationWithActualResult(\n        rebalancePosition,\n        afterPosition\n      );\n\n      const rentalChanges = new BN(afterPositionLamports).sub(\n        new BN(beforePositionLamports)\n      );\n\n      expect(rentalChanges.toString()).toBe(\n        simulationResult.rentalCostLamports.toString()\n      );\n\n      const [beforeWidth, afterWidth] = getBeforeAfterPositionWidth(\n        beforePosition,\n        afterPosition\n      );\n\n      expect(afterWidth).toBeLessThan(beforeWidth);\n      await dlmm.refetchStates();\n    }\n  });\n\n  it(\"Rebalance with single bin deposit\", async () => {\n    const dlmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n\n    for (const strategy of strategySet) {\n      const positionKeypair = Keypair.generate();\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: positionKeypair.publicKey,\n        user: keypair.publicKey,\n        minBinId: dlmm.lbPair.activeId - 30,\n        maxBinId: dlmm.lbPair.activeId + 30,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        positionKeypair,\n        keypair,\n      ]);\n\n      const beforePositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const beforePosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      const strategyParamBuilder =\n        getLiquidityStrategyParameterBuilder(strategy);\n\n      const minDeltaId = new BN(0);\n      const maxDeltaId = new BN(0);\n      const amountX = new BN(10_000_000);\n      const amountY = new BN(10_000_000);\n      const favorXInActiveBin = false;\n\n      const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        new BN(dlmm.lbPair.binStep),\n        favorXInActiveBin,\n        new BN(dlmm.lbPair.activeId),\n        strategyParamBuilder\n      );\n\n      const { simulationResult, rebalancePosition } =\n        await dlmm.simulateRebalancePosition(\n          positionKeypair.publicKey,\n          beforePosition.positionData,\n          true,\n          true,\n          [\n            {\n              x0,\n              y0,\n              deltaX,\n              deltaY,\n              minDeltaId,\n              maxDeltaId,\n              favorXInActiveBin,\n            },\n          ],\n          [\n            {\n              minBinId: new BN(beforePosition.positionData.lowerBinId),\n              maxBinId: new BN(beforePosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        );\n\n      const { initBinArrayInstructions, rebalancePositionInstruction } =\n        await dlmm.rebalancePosition(\n          { simulationResult, rebalancePosition },\n          new BN(0)\n        );\n\n      const { lastValidBlockHeight, blockhash } =\n        await connection.getLatestBlockhash();\n\n      await Promise.all(\n        initBinArrayInstructions.map((ix) => {\n          const transaction = new Transaction({\n            lastValidBlockHeight,\n            blockhash,\n          }).add(ix);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        })\n      );\n\n      const rebalanceTx = new Transaction({\n        lastValidBlockHeight,\n        blockhash,\n      }).add(...rebalancePositionInstruction);\n\n      await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]).then(\n        console.log\n      );\n\n      const afterPositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n      const afterPosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      assertEqRebalanceSimulationWithActualResult(\n        rebalancePosition,\n        afterPosition\n      );\n\n      const rentalChanges = new BN(afterPositionLamports).sub(\n        new BN(beforePositionLamports)\n      );\n\n      expect(rentalChanges.toString()).toBe(\n        simulationResult.rentalCostLamports.toString()\n      );\n\n      const [_beforeWidth, afterWidth] = getBeforeAfterPositionWidth(\n        beforePosition,\n        afterPosition\n      );\n\n      expect(afterWidth).toBe(1);\n      await dlmm.refetchStates();\n    }\n  });\n\n  it(\"Rebalance with only deposit and auto expand position\", async () => {\n    const dlmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n\n    for (const strategy of strategySet) {\n      const positionKeypair = Keypair.generate();\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: positionKeypair.publicKey,\n        user: keypair.publicKey,\n        minBinId: dlmm.lbPair.activeId - 30,\n        maxBinId: dlmm.lbPair.activeId + 30,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        positionKeypair,\n        keypair,\n      ]);\n\n      const beforePositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const beforePosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      const minDeltaId = new BN(-50);\n      const maxDeltaId = new BN(50);\n      const amountX = new BN(10_000_000);\n      const amountY = new BN(10_000_000);\n      const favorXInActiveBin = false;\n\n      const strategyParamBuilder =\n        getLiquidityStrategyParameterBuilder(strategy);\n      const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        new BN(dlmm.lbPair.binStep),\n        favorXInActiveBin,\n        new BN(dlmm.lbPair.activeId),\n        strategyParamBuilder\n      );\n\n      const { simulationResult, rebalancePosition } =\n        await dlmm.simulateRebalancePosition(\n          positionKeypair.publicKey,\n          beforePosition.positionData,\n          true,\n          true,\n          [\n            {\n              minDeltaId,\n              maxDeltaId,\n              x0,\n              y0,\n              deltaX,\n              deltaY,\n              favorXInActiveBin,\n            },\n          ],\n          [\n            {\n              minBinId: new BN(beforePosition.positionData.lowerBinId),\n              maxBinId: new BN(beforePosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        );\n\n      const { initBinArrayInstructions, rebalancePositionInstruction } =\n        await dlmm.rebalancePosition(\n          { simulationResult, rebalancePosition },\n          new BN(0)\n        );\n\n      const { lastValidBlockHeight, blockhash } =\n        await connection.getLatestBlockhash();\n\n      await Promise.all(\n        initBinArrayInstructions.map((ix) => {\n          const transaction = new Transaction({\n            lastValidBlockHeight,\n            blockhash,\n          }).add(ix);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        })\n      );\n\n      const rebalanceTx = new Transaction({\n        lastValidBlockHeight,\n        blockhash,\n      }).add(...rebalancePositionInstruction);\n\n      await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]);\n\n      const afterPositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n      const afterPosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      assertEqRebalanceSimulationWithActualResult(\n        rebalancePosition,\n        afterPosition\n      );\n\n      const rentalChanges = new BN(afterPositionLamports).sub(\n        new BN(beforePositionLamports)\n      );\n\n      expect(rentalChanges.toString()).toBe(\n        simulationResult.rentalCostLamports.toString()\n      );\n\n      const [beforeWidth, afterWidth] = getBeforeAfterPositionWidth(\n        beforePosition,\n        afterPosition\n      );\n\n      expect(afterWidth).toBeGreaterThan(beforeWidth);\n      await dlmm.refetchStates();\n    }\n  });\n\n  it(\"Rebalance with claim fee + withdraw + deposit and auto shrink position\", async () => {\n    const dlmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n\n    for (const strategy of strategySet) {\n      const positionKeypair = Keypair.generate();\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: positionKeypair.publicKey,\n        user: keypair.publicKey,\n        minBinId: dlmm.lbPair.activeId - 30,\n        maxBinId: dlmm.lbPair.activeId + 30,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        positionKeypair,\n        keypair,\n      ]);\n\n      console.log(\"Deposit and generate swap fees\");\n      {\n        const beforePosition = await dlmm.getPosition(\n          positionKeypair.publicKey\n        );\n\n        const minDeltaId = new BN(beforePosition.positionData.lowerBinId).subn(\n          dlmm.lbPair.activeId\n        );\n        const maxDeltaId = new BN(beforePosition.positionData.upperBinId).subn(\n          dlmm.lbPair.activeId\n        );\n\n        const amountX = new BN(100_000_000);\n        const amountY = new BN(100_000_000);\n        const favorXInActiveBin = false;\n\n        const strategyParamBuilder =\n          getLiquidityStrategyParameterBuilder(strategy);\n        const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n          amountX,\n          amountY,\n          minDeltaId,\n          maxDeltaId,\n          new BN(dlmm.lbPair.binStep),\n          favorXInActiveBin,\n          new BN(dlmm.lbPair.activeId),\n          strategyParamBuilder\n        );\n\n        const { simulationResult, rebalancePosition } =\n          await dlmm.simulateRebalancePosition(\n            positionKeypair.publicKey,\n            beforePosition.positionData,\n            true,\n            true,\n            [\n              {\n                minDeltaId,\n                maxDeltaId,\n                x0,\n                y0,\n                deltaX,\n                deltaY,\n                favorXInActiveBin,\n              },\n            ],\n            [\n              {\n                minBinId: new BN(beforePosition.positionData.lowerBinId),\n                maxBinId: new BN(beforePosition.positionData.upperBinId),\n                bps: new BN(BASIS_POINT_MAX),\n              },\n            ]\n          );\n\n        const { initBinArrayInstructions, rebalancePositionInstruction } =\n          await dlmm.rebalancePosition(\n            { simulationResult, rebalancePosition },\n            new BN(0)\n          );\n\n        const { lastValidBlockHeight, blockhash } =\n          await connection.getLatestBlockhash();\n\n        await Promise.all(\n          initBinArrayInstructions.map((ix) => {\n            const transaction = new Transaction({\n              lastValidBlockHeight,\n              blockhash,\n            }).add(ix);\n\n            return sendAndConfirmTransaction(connection, transaction, [\n              keypair,\n            ]);\n          })\n        );\n\n        const rebalanceTx = new Transaction({\n          lastValidBlockHeight,\n          blockhash,\n        }).add(...rebalancePositionInstruction);\n\n        await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]);\n\n        for (const swapXToY of [true, false]) {\n          const binArraysForSwap = await dlmm.getBinArrayForSwap(swapXToY, 3);\n\n          const [inToken, outToken] = swapXToY\n            ? [dlmm.lbPair.tokenXMint, dlmm.lbPair.tokenYMint]\n            : [dlmm.lbPair.tokenYMint, dlmm.lbPair.tokenXMint];\n\n          const inAmount = new BN(100_000);\n\n          const { outAmount, binArraysPubkey } = dlmm.swapQuote(\n            inAmount,\n            swapXToY,\n            new BN(0),\n            binArraysForSwap,\n            true\n          );\n\n          const swapTx = await dlmm.swap({\n            inToken,\n            outToken,\n            inAmount,\n            minOutAmount: new BN(0),\n            binArraysPubkey,\n            user: keypair.publicKey,\n            lbPair: dlmm.pubkey,\n          });\n\n          await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n        }\n      }\n\n      console.log(\"Rebalance\");\n      let beforePosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      const minDeltaId = new BN(beforePosition.positionData.lowerBinId)\n        .subn(dlmm.lbPair.activeId)\n        .addn(10);\n      const maxDeltaId = new BN(beforePosition.positionData.upperBinId)\n        .subn(dlmm.lbPair.activeId)\n        .subn(10);\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const favorXInActiveBin = false;\n\n      const strategyParamBuilder =\n        getLiquidityStrategyParameterBuilder(strategy);\n      const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        new BN(dlmm.lbPair.binStep),\n        favorXInActiveBin,\n        new BN(dlmm.lbPair.activeId),\n        strategyParamBuilder\n      );\n\n      // Rebalance\n      const { simulationResult, rebalancePosition } =\n        await dlmm.simulateRebalancePosition(\n          positionKeypair.publicKey,\n          beforePosition.positionData,\n          true,\n          true,\n          [\n            {\n              x0,\n              y0,\n              deltaX,\n              deltaY,\n              maxDeltaId,\n              minDeltaId,\n              favorXInActiveBin,\n            },\n          ],\n          [\n            {\n              minBinId: new BN(beforePosition.positionData.lowerBinId),\n              maxBinId: new BN(beforePosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        );\n\n      const beforePositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const { initBinArrayInstructions, rebalancePositionInstruction } =\n        await dlmm.rebalancePosition(\n          { simulationResult, rebalancePosition },\n          new BN(0)\n        );\n\n      const { lastValidBlockHeight, blockhash } =\n        await connection.getLatestBlockhash();\n\n      await Promise.all(\n        initBinArrayInstructions.map((ix) => {\n          const transaction = new Transaction({\n            lastValidBlockHeight,\n            blockhash,\n          }).add(ix);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        })\n      );\n\n      const rebalanceTx = new Transaction({\n        lastValidBlockHeight,\n        blockhash,\n      }).add(...rebalancePositionInstruction);\n\n      await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]);\n\n      const afterPositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const afterPosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      assertEqRebalanceSimulationWithActualResult(\n        rebalancePosition,\n        afterPosition\n      );\n\n      const rentalChanges = new BN(afterPositionLamports).sub(\n        new BN(beforePositionLamports)\n      );\n\n      expect(rentalChanges.toString()).toBe(\n        simulationResult.rentalCostLamports.toString()\n      );\n\n      const [beforeWidth, afterWidth] = getBeforeAfterPositionWidth(\n        beforePosition,\n        afterPosition\n      );\n\n      expect(afterWidth).toBeLessThan(beforeWidth);\n\n      // Clean up\n      await dlmm\n        .simulateRebalancePosition(\n          positionKeypair.publicKey,\n          afterPosition.positionData,\n          true,\n          true,\n          [],\n          [\n            {\n              minBinId: new BN(afterPosition.positionData.lowerBinId),\n              maxBinId: new BN(afterPosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        )\n        .then(async ({ rebalancePosition, simulationResult }) => {\n          const { initBinArrayInstructions: _, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0)\n            );\n\n          const { blockhash, lastValidBlockHeight } =\n            await connection.getLatestBlockhash();\n\n          const transaction = new Transaction({\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...rebalancePositionInstruction);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        });\n\n      await dlmm.refetchStates();\n    }\n  });\n\n  it(\"Rebalance with claim fee + withdraw + deposit and auto expand position\", async () => {\n    const dlmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n    for (const strategy of strategySet) {\n      const positionKeypair = Keypair.generate();\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: positionKeypair.publicKey,\n        user: keypair.publicKey,\n        minBinId: dlmm.lbPair.activeId - 30,\n        maxBinId: dlmm.lbPair.activeId + 30,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        positionKeypair,\n        keypair,\n      ]);\n\n      console.log(\"Deposit and generate swap fees\");\n      {\n        const beforePosition = await dlmm.getPosition(\n          positionKeypair.publicKey\n        );\n\n        const minDeltaId = new BN(beforePosition.positionData.lowerBinId).subn(\n          dlmm.lbPair.activeId\n        );\n        const maxDeltaId = new BN(beforePosition.positionData.upperBinId).subn(\n          dlmm.lbPair.activeId\n        );\n        const amountX = new BN(100_000_000);\n        const amountY = new BN(100_000_000);\n        const favorXInActiveBin = false;\n\n        const strategyParamBuilder =\n          getLiquidityStrategyParameterBuilder(strategy);\n        const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n          amountX,\n          amountY,\n          minDeltaId,\n          maxDeltaId,\n          new BN(dlmm.lbPair.binStep),\n          favorXInActiveBin,\n          new BN(dlmm.lbPair.activeId),\n          strategyParamBuilder\n        );\n\n        const { simulationResult, rebalancePosition } =\n          await dlmm.simulateRebalancePosition(\n            positionKeypair.publicKey,\n            beforePosition.positionData,\n            true,\n            true,\n            [\n              {\n                x0,\n                y0,\n                deltaX,\n                deltaY,\n                maxDeltaId,\n                minDeltaId,\n                favorXInActiveBin,\n              },\n            ],\n            [\n              {\n                minBinId: new BN(beforePosition.positionData.lowerBinId),\n                maxBinId: new BN(beforePosition.positionData.upperBinId),\n                bps: new BN(BASIS_POINT_MAX),\n              },\n            ]\n          );\n\n        const { initBinArrayInstructions, rebalancePositionInstruction } =\n          await dlmm.rebalancePosition(\n            { simulationResult, rebalancePosition },\n            new BN(0)\n          );\n\n        const { lastValidBlockHeight, blockhash } =\n          await connection.getLatestBlockhash();\n\n        await Promise.all(\n          initBinArrayInstructions.map((ix) => {\n            const transaction = new Transaction({\n              lastValidBlockHeight,\n              blockhash,\n            }).add(ix);\n\n            return sendAndConfirmTransaction(connection, transaction, [\n              keypair,\n            ]);\n          })\n        );\n\n        const rebalanceTx = new Transaction({\n          lastValidBlockHeight,\n          blockhash,\n        }).add(...rebalancePositionInstruction);\n\n        await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]);\n\n        for (const swapXToY of [true, false]) {\n          const binArraysForSwap = await dlmm.getBinArrayForSwap(swapXToY, 3);\n\n          const [inToken, outToken] = swapXToY\n            ? [dlmm.lbPair.tokenXMint, dlmm.lbPair.tokenYMint]\n            : [dlmm.lbPair.tokenYMint, dlmm.lbPair.tokenXMint];\n\n          const inAmount = new BN(100_000);\n\n          const { outAmount, binArraysPubkey } = dlmm.swapQuote(\n            inAmount,\n            swapXToY,\n            new BN(0),\n            binArraysForSwap,\n            true\n          );\n\n          const swapTx = await dlmm.swap({\n            inToken,\n            outToken,\n            inAmount,\n            minOutAmount: new BN(0),\n            binArraysPubkey,\n            user: keypair.publicKey,\n            lbPair: dlmm.pubkey,\n          });\n\n          await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n        }\n      }\n\n      console.log(\"Rebalance\");\n      let beforePosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      const minDeltaId = new BN(beforePosition.positionData.lowerBinId)\n        .subn(dlmm.lbPair.activeId)\n        .subn(10);\n      const maxDeltaId = new BN(beforePosition.positionData.upperBinId)\n        .subn(dlmm.lbPair.activeId)\n        .addn(10);\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const favorXInActiveBin = false;\n\n      const strategyParamBuilder =\n        getLiquidityStrategyParameterBuilder(strategy);\n      const { x0, y0, deltaX, deltaY } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        new BN(dlmm.lbPair.binStep),\n        favorXInActiveBin,\n        new BN(dlmm.lbPair.activeId),\n        strategyParamBuilder\n      );\n\n      // Rebalance\n      const { simulationResult, rebalancePosition } =\n        await dlmm.simulateRebalancePosition(\n          positionKeypair.publicKey,\n          beforePosition.positionData,\n          true,\n          true,\n          [\n            {\n              x0,\n              y0,\n              deltaX,\n              deltaY,\n              maxDeltaId,\n              minDeltaId,\n              favorXInActiveBin,\n            },\n          ],\n          [\n            {\n              minBinId: new BN(beforePosition.positionData.lowerBinId),\n              maxBinId: new BN(beforePosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        );\n\n      const beforePositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const { initBinArrayInstructions, rebalancePositionInstruction } =\n        await dlmm.rebalancePosition(\n          { simulationResult, rebalancePosition },\n          new BN(0)\n        );\n\n      const { lastValidBlockHeight, blockhash } =\n        await connection.getLatestBlockhash();\n\n      await Promise.all(\n        initBinArrayInstructions.map((ix) => {\n          const transaction = new Transaction({\n            lastValidBlockHeight,\n            blockhash,\n          }).add(ix);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        })\n      );\n\n      const rebalanceTx = new Transaction({\n        lastValidBlockHeight,\n        blockhash,\n      }).add(...rebalancePositionInstruction);\n\n      await sendAndConfirmTransaction(connection, rebalanceTx, [keypair]);\n\n      const afterPositionLamports = await connection\n        .getAccountInfo(positionKeypair.publicKey)\n        .then((account) => account.lamports);\n\n      const afterPosition = await dlmm.getPosition(positionKeypair.publicKey);\n\n      assertEqRebalanceSimulationWithActualResult(\n        rebalancePosition,\n        afterPosition\n      );\n\n      const rentalChanges = new BN(afterPositionLamports).sub(\n        new BN(beforePositionLamports)\n      );\n\n      expect(rentalChanges.toString()).toBe(\n        simulationResult.rentalCostLamports.toString()\n      );\n\n      const [beforeWidth, afterWidth] = getBeforeAfterPositionWidth(\n        beforePosition,\n        afterPosition\n      );\n\n      expect(afterWidth).toBeGreaterThan(beforeWidth);\n\n      // Clean up\n      await dlmm\n        .simulateRebalancePosition(\n          positionKeypair.publicKey,\n          afterPosition.positionData,\n          true,\n          true,\n          [],\n          [\n            {\n              minBinId: new BN(afterPosition.positionData.lowerBinId),\n              maxBinId: new BN(afterPosition.positionData.upperBinId),\n              bps: new BN(BASIS_POINT_MAX),\n            },\n          ]\n        )\n        .then(async ({ rebalancePosition, simulationResult }) => {\n          const { initBinArrayInstructions: _, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0)\n            );\n\n          const { blockhash, lastValidBlockHeight } =\n            await connection.getLatestBlockhash();\n\n          const transaction = new Transaction({\n            blockhash,\n            lastValidBlockHeight,\n          }).add(...rebalancePositionInstruction);\n\n          return sendAndConfirmTransaction(connection, transaction, [keypair]);\n        });\n\n      await dlmm.refetchStates();\n    }\n  });\n});\n\ndescribe(\"Rebalance with strategy\", () => {\n  it(\"Balanced strategy\", async () => {});\n});\n\nfunction getBeforeAfterPositionWidth(\n  beforePosition: LbPosition,\n  afterPosition: LbPosition\n) {\n  const beforeWidth =\n    beforePosition.positionData.upperBinId -\n    beforePosition.positionData.lowerBinId +\n    1;\n  const afterWidth =\n    afterPosition.positionData.upperBinId -\n    afterPosition.positionData.lowerBinId +\n    1;\n\n  return [beforeWidth, afterWidth];\n}\n"
  },
  {
    "path": "ts-client/src/test/rebalance_parameter_builder.test.ts",
    "content": "import babar from \"babar\";\nimport BN from \"bn.js\";\nimport { SCALE_OFFSET } from \"../dlmm/constants\";\nimport { getQPriceFromId } from \"../dlmm/helpers/math\";\nimport {\n  AmountIntoBin,\n  buildLiquidityStrategyParameters,\n  getLiquidityStrategyParameterBuilder,\n  suggestBalancedXParametersFromY,\n  suggestBalancedYParametersFromX,\n  toAmountIntoBins,\n} from \"../dlmm/helpers/rebalance\";\nimport { StrategyType } from \"../dlmm/types\";\nimport { assertionWithTolerance } from \"./helper\";\n\nfunction assertBinDepositResult(\n  activeId: BN,\n  minDeltaId: BN,\n  maxDeltaId: BN,\n  favorXInActiveBin: boolean,\n  amountInBins: AmountIntoBin[],\n  amountX: BN,\n  amountY: BN,\n  tolerance: BN\n) {\n  const minBinId = activeId.add(minDeltaId);\n  const maxBinId = activeId.add(maxDeltaId);\n\n  let totalAmountX = new BN(0);\n  let totalAmountY = new BN(0);\n\n  for (let i = 0; i < amountInBins.length; i++) {\n    const { binId, amountX, amountY } = amountInBins[i];\n\n    // 1. Check bin range\n    expect(binId.gte(minBinId)).toBeTruthy();\n    expect(binId.lte(maxBinId)).toBeTruthy();\n\n    // 2. Check amount\n    if (binId.lt(activeId)) {\n      expect(amountY.gt(new BN(0))).toBeTruthy();\n      expect(amountX.isZero()).toBeTruthy();\n    } else if (binId.gt(activeId)) {\n      expect(amountX.gt(new BN(0))).toBeTruthy();\n      expect(amountY.isZero()).toBeTruthy();\n    } else {\n      if (favorXInActiveBin) {\n        expect(amountX.gt(new BN(0))).toBeTruthy();\n        expect(amountY.isZero()).toBeTruthy();\n      } else {\n        expect(amountY.gt(new BN(0))).toBeTruthy();\n        expect(amountX.isZero()).toBeTruthy();\n      }\n    }\n\n    totalAmountX = totalAmountX.add(amountX);\n    totalAmountY = totalAmountY.add(amountY);\n  }\n\n  // 3. Assert total amount\n  assertionWithTolerance(totalAmountX, amountX, tolerance);\n  assertionWithTolerance(totalAmountY, amountY, tolerance);\n}\n\nfunction logLiquidityInfo(\n  amountX: BN,\n  amountY: BN,\n  amountInBins: AmountIntoBin[],\n  binStep: BN\n) {\n  const { totalAmountX, totalAmountY } = amountInBins.reduce(\n    (total, { amountX, amountY }) => {\n      return {\n        totalAmountX: total.totalAmountX.add(amountX),\n        totalAmountY: total.totalAmountY.add(amountY),\n      };\n    },\n    { totalAmountX: new BN(0), totalAmountY: new BN(0) }\n  );\n\n  console.log(\n    \"Total amount X\",\n    totalAmountX.toString(),\n    \"Amount X\",\n    amountX.toString()\n  );\n  console.log(\n    \"Total amount Y\",\n    totalAmountY.toString(),\n    \"Amount Y\",\n    amountY.toString()\n  );\n\n  const liquidities = amountInBins.map(({ amountX, amountY, binId }) => {\n    const qPrice = getQPriceFromId(binId, binStep);\n    return amountX.mul(qPrice).shrn(SCALE_OFFSET).add(amountY).toString();\n  });\n\n  console.log(babar(liquidities.map((liq, idx) => [idx, Number(liq)])));\n  console.log(\"Liquidity distribution\", JSON.stringify(liquidities));\n}\n\ndescribe(\"Rebalance liquidity parameter builder\", () => {\n  const activeId = new BN(1000);\n  const binStep = new BN(10);\n\n  describe(\"Spot\", () => {\n    const builder = getLiquidityStrategyParameterBuilder(StrategyType.Spot);\n\n    it(\"Bid side\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = true;\n\n      const { deltaY, y0, deltaX, x0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Bid side and suggest ask side parameters\", () => {\n      let amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      let maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = true;\n\n      const { deltaY, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      maxDeltaId = maxDeltaId.add(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        base: x0,\n        delta: deltaX,\n        amountX: suggestedAmountX,\n      } = suggestBalancedXParametersFromY(\n        y0,\n        deltaY,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountX = suggestedAmountX;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side and suggest bid side parameters\", () => {\n      const amountX = new BN(100_000_000);\n      let amountY = new BN(0);\n      let minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, x0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      minDeltaId = minDeltaId.sub(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        base: y0,\n        delta: deltaY,\n        amountY: suggestedAmountY,\n      } = suggestBalancedYParametersFromX(\n        x0,\n        deltaX,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountY = suggestedAmountY;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Bid side involve active bin\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(0);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side involve active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(0);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Both side with X in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Both side with Y in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n  });\n\n  describe(\"Curve\", () => {\n    const builder = getLiquidityStrategyParameterBuilder(StrategyType.Curve);\n\n    it(\"Bid side\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Bid side and suggest ask side parameters\", () => {\n      let amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      let maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = true;\n\n      const { deltaY, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      maxDeltaId = maxDeltaId.add(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        base: x0,\n        delta: deltaX,\n        amountX: suggestedAmountX,\n      } = suggestBalancedXParametersFromY(\n        y0,\n        deltaY,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountX = suggestedAmountX;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side and suggest bid side parameters\", () => {\n      const amountX = new BN(100_000_000);\n      let amountY = new BN(0);\n      let minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, x0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      minDeltaId = minDeltaId.sub(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        base: y0,\n        delta: deltaY,\n        amountY: suggestedAmountY,\n      } = suggestBalancedYParametersFromX(\n        x0,\n        deltaX,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountY = suggestedAmountY;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Bid side involve active bin\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(0);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Ask side involve active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(0);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Both side with X in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n\n    it(\"Both side with Y in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(50)\n      );\n    });\n  });\n\n  describe(\"BidAsk\", () => {\n    const builder = getLiquidityStrategyParameterBuilder(StrategyType.BidAsk);\n\n    it(\"Bid side\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(2000)\n      );\n    });\n\n    it(\"Bid side far away from active bin\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(1200).neg();\n      const maxDeltaId = new BN(1000).neg();\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(20_000)\n      );\n    });\n\n    it(\"Bid side suggest ask side parameters\", () => {\n      let amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      let maxDeltaId = new BN(1).neg();\n      const favorXInActiveBin = true;\n\n      const { deltaY, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      maxDeltaId = maxDeltaId.add(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        delta: deltaX,\n        base: x0,\n        amountX: suggestedAmountX,\n      } = suggestBalancedXParametersFromY(\n        y0,\n        deltaY,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountX = suggestedAmountX;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(2000)\n      );\n    });\n\n    it(\"Ask side\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(1000)\n      );\n    });\n\n    it(\"Ask side far away from active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(1000);\n      const maxDeltaId = new BN(1200);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(20_000)\n      );\n    });\n\n    it(\"Ask side suggest bid side parameters\", () => {\n      const amountX = new BN(100_000_000);\n      let amountY = new BN(0);\n      let minDeltaId = new BN(1);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = false;\n\n      const { deltaX, x0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      minDeltaId = minDeltaId.sub(maxDeltaId.sub(minDeltaId).addn(1));\n\n      const {\n        delta: deltaY,\n        base: y0,\n        amountY: suggestedAmountY,\n      } = suggestBalancedYParametersFromX(\n        x0,\n        deltaX,\n        minDeltaId,\n        maxDeltaId,\n        activeId,\n        binStep,\n        favorXInActiveBin,\n        builder\n      );\n\n      amountY = suggestedAmountY;\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(1000)\n      );\n    });\n\n    it(\"Bid side involve active bin\", () => {\n      const amountX = new BN(0);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(60).neg();\n      const maxDeltaId = new BN(0);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(2000)\n      );\n    });\n\n    it(\"Ask side involve active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(0);\n      const minDeltaId = new BN(0);\n      const maxDeltaId = new BN(60);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(1000)\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n    });\n\n    it(\"Both side with X in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = true;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(1000)\n      );\n    });\n\n    it(\"Both side with Y in active bin\", () => {\n      const amountX = new BN(100_000_000);\n      const amountY = new BN(100_000_000);\n      const minDeltaId = new BN(30).neg();\n      const maxDeltaId = new BN(30);\n      const favorXInActiveBin = false;\n\n      const { deltaX, deltaY, x0, y0 } = buildLiquidityStrategyParameters(\n        amountX,\n        amountY,\n        minDeltaId,\n        maxDeltaId,\n        binStep,\n        favorXInActiveBin,\n        activeId,\n        builder\n      );\n\n      const amountInBins = toAmountIntoBins(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        deltaX,\n        deltaY,\n        x0,\n        y0,\n        binStep,\n        favorXInActiveBin\n      );\n\n      logLiquidityInfo(amountX, amountY, amountInBins, binStep);\n\n      assertBinDepositResult(\n        activeId,\n        minDeltaId,\n        maxDeltaId,\n        favorXInActiveBin,\n        amountInBins,\n        amountX,\n        amountY,\n        new BN(1000)\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/rebalance_with_strategy.test.ts",
    "content": "import { BN, web3 } from \"@coral-xyz/anchor\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  createMint,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n  TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  sendAndConfirmTransaction,\n  Transaction,\n} from \"@solana/web3.js\";\nimport fs from \"fs\";\nimport {\n  BASIS_POINT_MAX,\n  FunctionType,\n  LBCLMM_PROGRAM_IDS,\n} from \"../dlmm/constants\";\nimport IDL from \"../dlmm/idl/idl.json\";\nimport {\n  deriveLbPairWithPresetParamWithIndexKey,\n  derivePresetParameterWithIndex,\n  Opt,\n} from \"../dlmm/helpers\";\nimport { DLMM } from \"../dlmm/index\";\nimport { StrategyType } from \"../dlmm/types\";\nimport {\n  assertEqRebalanceSimulationWithActualResult,\n  assertionWithPercentageTolerance,\n  assertionWithTolerance,\n  createTestProgram,\n  createWhitelistOperator,\n  logPositionLiquidities,\n  OperatorPermission,\n  swap,\n} from \"./helper\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\nconst btcDecimal = 6;\nconst usdcDecimal = 6;\n\nconst CONSTANTS = Object.entries(IDL.constants);\nexport const MAX_BIN_PER_ARRAY = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"MAX_BIN_PER_ARRAY\")[1].value\n);\n\nconst DEFAULT_ACTIVE_ID = new BN(1);\nconst DEFAULT_BIN_STEP = new BN(10);\nconst DEFAULT_BASE_FACTOR_2 = new BN(4000);\n\nconst programId = new web3.PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\nconst opt: Opt = { cluster: \"localhost\" };\n\nlet BTC: web3.PublicKey;\nlet USDC: web3.PublicKey;\nlet lbPairPubkey: web3.PublicKey;\nlet userBTC: web3.PublicKey;\nlet userUSDC: web3.PublicKey;\nlet presetParamPda2: web3.PublicKey;\nlet position: web3.PublicKey;\n\nasync function closeAndCreateNewPositionWithSpotLiquidity(\n  dlmm: DLMM,\n  owner: Keypair\n) {\n  if (position) {\n    const positionState = await dlmm.program.account.positionV2.fetch(position);\n    const dlmm2 = await DLMM.create(\n      dlmm.program.provider.connection,\n      positionState.lbPair,\n      opt\n    );\n\n    const txs = await dlmm2.removeLiquidity({\n      user: owner.publicKey,\n      position,\n      fromBinId: positionState.lowerBinId,\n      toBinId: positionState.upperBinId,\n      shouldClaimAndClose: true,\n      bps: new BN(BASIS_POINT_MAX),\n    });\n\n    await Promise.all(\n      txs.map((tx) => sendAndConfirmTransaction(connection, tx, [owner]))\n    );\n  }\n  console.log(\"Create empty position\");\n  const positionKp = Keypair.generate();\n  position = positionKp.publicKey;\n\n  const lowerBinId = DEFAULT_ACTIVE_ID.subn(34);\n  const upperBinId = DEFAULT_ACTIVE_ID.addn(34);\n\n  let rawTx = await dlmm.createEmptyPosition({\n    positionPubKey: position,\n    minBinId: lowerBinId.toNumber(),\n    maxBinId: upperBinId.toNumber(),\n    user: keypair.publicKey,\n  });\n\n  await sendAndConfirmTransaction(connection, rawTx, [positionKp, keypair]);\n\n  const positionState = await dlmm.program.account.positionV2.fetch(position);\n\n  rawTx = await dlmm.addLiquidityByStrategy({\n    positionPubKey: position,\n    totalXAmount: new BN(1_000_000_000),\n    totalYAmount: new BN(1_000_000_000),\n    strategy: {\n      strategyType: StrategyType.Spot,\n      minBinId: positionState.lowerBinId,\n      maxBinId: positionState.upperBinId,\n    },\n    user: keypair.publicKey,\n    slippage: 0,\n  });\n\n  await sendAndConfirmTransaction(connection, rawTx, [keypair]);\n}\n\ndescribe(\"Rebalance with strategy\", () => {\n  beforeEach(async () => {\n    BTC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      btcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    USDC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      usdcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    const userBtcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      BTC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userBTC = userBtcInfo.address;\n\n    const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      USDC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userUSDC = userUsdcInfo.address;\n\n    await mintTo(\n      connection,\n      keypair,\n      BTC,\n      userBTC,\n      keypair.publicKey,\n      100_000_000 * 10 ** btcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    await mintTo(\n      connection,\n      keypair,\n      USDC,\n      userUSDC,\n      keypair.publicKey,\n      100_000_000 * 10 ** usdcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    const { presetParameter2 } = await DLMM.getAllPresetParameters(\n      connection,\n      opt\n    );\n\n    const index = new BN(presetParameter2.length);\n\n    [presetParamPda2] = derivePresetParameterWithIndex(index, programId);\n\n    const program = createTestProgram(connection, programId, keypair);\n\n    const operatorPda = await createWhitelistOperator(\n      connection,\n      keypair,\n      keypair.publicKey,\n      [OperatorPermission.InitializePresetParameter],\n      programId\n    );\n\n    const presetParamState2 =\n      await program.account.presetParameter.fetchNullable(presetParamPda2);\n\n    if (!presetParamState2) {\n      await program.methods\n        .initializePresetParameter({\n          index: index.toNumber(),\n          binStep: DEFAULT_BIN_STEP.toNumber(),\n          baseFactor: DEFAULT_BASE_FACTOR_2.toNumber(),\n          functionType: FunctionType.LiquidityMining,\n          filterPeriod: 30,\n          decayPeriod: 600,\n          reductionFactor: 5000,\n          variableFeeControl: 40000,\n          protocolShare: 0,\n          maxVolatilityAccumulator: 350000,\n          baseFeePowerFactor: 0,\n        })\n        .accountsPartial({\n          signer: keypair.publicKey,\n          presetParameter: presetParamPda2,\n          systemProgram: web3.SystemProgram.programId,\n          operator: operatorPda,\n        })\n        .signers([keypair])\n        .rpc({\n          commitment: \"confirmed\",\n        });\n    }\n\n    console.log(\"Create lb pair\");\n    let rawTx = await DLMM.createLbPair2(\n      connection,\n      keypair.publicKey,\n      BTC,\n      USDC,\n      presetParamPda2,\n      DEFAULT_ACTIVE_ID,\n      opt\n    );\n    await sendAndConfirmTransaction(connection, rawTx, [keypair]);\n\n    [lbPairPubkey] = deriveLbPairWithPresetParamWithIndexKey(\n      presetParamPda2,\n      BTC,\n      USDC,\n      programId\n    );\n\n    const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n  });\n\n  describe(\"Balanced strategy\", () => {\n    it(\"Without adjust liquidity\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(0),\n              new BN(0),\n              new BN(0),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          expect(afterUsdcBalance.gte(beforeUsdcBalance)).toBeTruthy();\n          expect(afterBtcBalance.gte(beforeBtcBalance)).toBeTruthy();\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Deposit more at bid side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(0),\n              new BN(100_000_000),\n              new BN(0),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          expect(afterUsdcBalance.lt(beforeUsdcBalance)).toBeTruthy();\n          expect(afterBtcBalance.gte(beforeBtcBalance)).toBeTruthy();\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Deposit more at ask side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(100_000_000),\n              new BN(0),\n              new BN(0),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          expect(afterUsdcBalance.gte(beforeUsdcBalance)).toBeTruthy();\n          expect(afterBtcBalance.lt(beforeBtcBalance)).toBeTruthy();\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Deposit more at both side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(100_000_000),\n              new BN(100_000_000),\n              new BN(0),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          expect(afterUsdcBalance.lt(beforeUsdcBalance)).toBeTruthy();\n          expect(afterBtcBalance.lt(beforeBtcBalance)).toBeTruthy();\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Withdraw more at bid side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(0),\n              new BN(0),\n              new BN(0),\n              new BN(5000)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const minPositionYAmountWithdrawn = new BN(\n            parsedPosition.positionData.totalYAmount\n          )\n            .mul(new BN(5000))\n            .div(new BN(BASIS_POINT_MAX));\n\n          expect(afterUsdcBalance.gt(beforeUsdcBalance)).toBeTruthy();\n          const usdcDiff = afterUsdcBalance.sub(beforeUsdcBalance);\n          expect(usdcDiff.gte(minPositionYAmountWithdrawn)).toBeTruthy();\n\n          assertionWithTolerance(\n            afterBtcBalance,\n            beforeBtcBalance,\n            new BN(1000)\n          );\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Withdraw more at ask side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(0),\n              new BN(0),\n              new BN(5000),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const positionWithdrawnXAMount = new BN(\n            parsedPosition.positionData.totalXAmount\n          )\n            .muln(5000)\n            .divn(10000);\n\n          const btcDiff = afterBtcBalance.sub(beforeBtcBalance);\n\n          assertionWithPercentageTolerance(\n            btcDiff,\n            positionWithdrawnXAMount,\n            0.05\n          );\n          assertionWithTolerance(\n            afterUsdcBalance,\n            beforeUsdcBalance,\n            new BN(1000)\n          );\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"Withdraw more at both side\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        for (const swapForY of [true, false]) {\n          console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n          await swap(swapForY, new BN(250_000_000), dlmm, keypair);\n          await dlmm.refetchStates();\n          console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n          let parsedPosition = await dlmm.getPosition(position);\n\n          let beforeBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let beforeBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          const { rebalancePosition, simulationResult } =\n            await dlmm.simulateRebalancePositionWithBalancedStrategy(\n              position,\n              parsedPosition.positionData,\n              strategy,\n              new BN(0),\n              new BN(5000),\n              new BN(5000),\n              new BN(0)\n            );\n\n          const { initBinArrayInstructions, rebalancePositionInstruction } =\n            await dlmm.rebalancePosition(\n              { rebalancePosition, simulationResult },\n              new BN(0),\n              keypair.publicKey,\n              0\n            );\n\n          let latestBlockHash = await connection.getLatestBlockhash();\n\n          await Promise.all(\n            initBinArrayInstructions.map((ix) =>\n              sendAndConfirmTransaction(\n                connection,\n                new Transaction({ ...latestBlockHash }).add(ix),\n                [keypair]\n              )\n            )\n          );\n\n          latestBlockHash = await connection.getLatestBlockhash();\n\n          const beforeUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const beforeBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          await sendAndConfirmTransaction(\n            connection,\n            new Transaction({ ...latestBlockHash }).add(\n              ...rebalancePositionInstruction\n            ),\n            [keypair]\n          );\n\n          const afterUsdcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userUSDC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const afterBtcBalance = await dlmm.program.provider.connection\n            .getTokenAccountBalance(userBTC)\n            .then((acc) => new BN(acc.value.amount));\n\n          const positionWithdrawnXAMount = new BN(\n            parsedPosition.positionData.totalXAmount\n          )\n            .muln(5000)\n            .divn(10000);\n\n          const positionWithdrawnYAMount = new BN(\n            parsedPosition.positionData.totalYAmount\n          )\n            .muln(5000)\n            .divn(10000);\n\n          const btcDiff = afterBtcBalance.sub(beforeBtcBalance);\n          const usdcDiff = afterUsdcBalance.sub(beforeUsdcBalance);\n\n          assertionWithPercentageTolerance(\n            btcDiff,\n            positionWithdrawnXAMount,\n            0.05\n          );\n          assertionWithPercentageTolerance(\n            usdcDiff,\n            positionWithdrawnYAMount,\n            0.05\n          );\n\n          console.log(\"Before liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n          parsedPosition = await dlmm.getPosition(position);\n          console.log(\"After liquidity\");\n          logPositionLiquidities(parsedPosition.positionData);\n\n          let afterBinPerBidSide =\n            dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n          let afterBinPerAskSide =\n            parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n          expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n          expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n          assertEqRebalanceSimulationWithActualResult(\n            rebalancePosition,\n            parsedPosition\n          );\n        }\n      }\n    });\n\n    it(\"DCA buy\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n        await swap(true, new BN(250_000_000), dlmm, keypair);\n        await dlmm.refetchStates();\n        console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n        let parsedPosition = await dlmm.getPosition(position);\n\n        let beforeBinPerBidSide =\n          dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n        let beforeBinPerAskSide =\n          parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n        const { rebalancePosition, simulationResult } =\n          await dlmm.simulateRebalancePositionWithBalancedStrategy(\n            position,\n            parsedPosition.positionData,\n            strategy,\n            new BN(0),\n            new BN(0),\n            new BN(10000),\n            new BN(0)\n          );\n\n        const { initBinArrayInstructions, rebalancePositionInstruction } =\n          await dlmm.rebalancePosition(\n            { rebalancePosition, simulationResult },\n            new BN(0),\n            keypair.publicKey,\n            0\n          );\n\n        let latestBlockHash = await connection.getLatestBlockhash();\n\n        await Promise.all(\n          initBinArrayInstructions.map((ix) =>\n            sendAndConfirmTransaction(\n              connection,\n              new Transaction({ ...latestBlockHash }).add(ix),\n              [keypair]\n            )\n          )\n        );\n\n        latestBlockHash = await connection.getLatestBlockhash();\n\n        await sendAndConfirmTransaction(\n          connection,\n          new Transaction({ ...latestBlockHash }).add(\n            ...rebalancePositionInstruction\n          ),\n          [keypair]\n        );\n\n        console.log(\"Before liquidity\");\n        logPositionLiquidities(parsedPosition.positionData);\n        parsedPosition = await dlmm.getPosition(position);\n        console.log(\"After liquidity\");\n        logPositionLiquidities(parsedPosition.positionData);\n\n        expect(\n          new BN(parsedPosition.positionData.totalXAmount)\n            .add(new BN(parsedPosition.positionData.feeX))\n            .isZero()\n        ).toBeTruthy();\n\n        let afterBinPerBidSide =\n          dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n        let afterBinPerAskSide =\n          parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n        expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n        expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n        assertEqRebalanceSimulationWithActualResult(\n          rebalancePosition,\n          parsedPosition\n        );\n      }\n    });\n\n    it(\"DCA sell\", async () => {\n      for (const strategy of [\n        StrategyType.Spot,\n        StrategyType.Curve,\n        StrategyType.BidAsk,\n      ]) {\n        const dlmm = await DLMM.create(connection, lbPairPubkey, opt);\n        await closeAndCreateNewPositionWithSpotLiquidity(dlmm, keypair);\n        console.log(`Before swap active id ${dlmm.lbPair.activeId}`);\n        await swap(false, new BN(250_000_000), dlmm, keypair);\n        await dlmm.refetchStates();\n        console.log(`After swap active id ${dlmm.lbPair.activeId}`);\n\n        let parsedPosition = await dlmm.getPosition(position);\n\n        let beforeBinPerBidSide =\n          dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n        let beforeBinPerAskSide =\n          parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n        const { rebalancePosition, simulationResult } =\n          await dlmm.simulateRebalancePositionWithBalancedStrategy(\n            position,\n            parsedPosition.positionData,\n            strategy,\n            new BN(0),\n            new BN(0),\n            new BN(0),\n            new BN(10000)\n          );\n\n        const { initBinArrayInstructions, rebalancePositionInstruction } =\n          await dlmm.rebalancePosition(\n            { rebalancePosition, simulationResult },\n            new BN(0),\n            keypair.publicKey,\n            0\n          );\n\n        let latestBlockHash = await connection.getLatestBlockhash();\n\n        await Promise.all(\n          initBinArrayInstructions.map((ix) =>\n            sendAndConfirmTransaction(\n              connection,\n              new Transaction({ ...latestBlockHash }).add(ix),\n              [keypair]\n            )\n          )\n        );\n\n        latestBlockHash = await connection.getLatestBlockhash();\n\n        await sendAndConfirmTransaction(\n          connection,\n          new Transaction({ ...latestBlockHash }).add(\n            ...rebalancePositionInstruction\n          ),\n          [keypair]\n        );\n\n        console.log(\"Before liquidity\");\n        logPositionLiquidities(parsedPosition.positionData);\n        parsedPosition = await dlmm.getPosition(position);\n        console.log(\"After liquidity\");\n        logPositionLiquidities(parsedPosition.positionData);\n\n        expect(\n          new BN(parsedPosition.positionData.totalYAmount)\n            .add(new BN(parsedPosition.positionData.feeY))\n            .isZero()\n        ).toBeTruthy();\n\n        let afterBinPerBidSide =\n          dlmm.lbPair.activeId - parsedPosition.positionData.lowerBinId;\n        let afterBinPerAskSide =\n          parsedPosition.positionData.upperBinId - dlmm.lbPair.activeId;\n\n        expect(beforeBinPerBidSide).not.toBe(beforeBinPerAskSide);\n        expect(afterBinPerBidSide).toBe(afterBinPerAskSide);\n\n        assertEqRebalanceSimulationWithActualResult(\n          rebalancePosition,\n          parsedPosition\n        );\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/sdk.test.ts",
    "content": "import { BN, web3 } from \"@coral-xyz/anchor\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  createMint,\n  getAssociatedTokenAddressSync,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n  NATIVE_MINT,\n  TOKEN_PROGRAM_ID,\n  transfer,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  PublicKey,\n  sendAndConfirmTransaction,\n} from \"@solana/web3.js\";\nimport Decimal from \"decimal.js\";\nimport fs from \"fs\";\nimport {\n  DEFAULT_BIN_PER_POSITION,\n  FunctionType,\n  LBCLMM_PROGRAM_IDS,\n} from \"../dlmm/constants\";\nimport IDL from \"../dlmm/idl/idl.json\";\nimport {\n  binIdToBinArrayIndex,\n  deriveBinArray,\n  deriveLbPair2,\n  deriveOracle,\n  derivePermissionLbPair,\n  derivePresetParameter2,\n  deriveReserve,\n} from \"../dlmm/helpers\";\nimport { computeBaseFactorFromFeeBps } from \"../dlmm/helpers/math\";\nimport { wrapPosition } from \"../dlmm/helpers/positions\";\nimport { DLMM } from \"../dlmm/index\";\nimport { ActivationType, ChunkCallbackInfo, GetPositionsOpt, PairType, StrategyType } from \"../dlmm/types\";\nimport {\n  createTestProgram,\n  createWhitelistOperator,\n  OperatorPermission,\n} from \"./helper\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\nconst btcDecimal = 8;\nconst usdcDecimal = 6;\n\nconst CONSTANTS = Object.entries(IDL.constants);\nconst BIN_ARRAY_BITMAP_SIZE = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"BIN_ARRAY_BITMAP_SIZE\")[1].value\n);\nexport const MAX_BIN_PER_ARRAY = new BN(\n  CONSTANTS.find(([k, v]) => v.name == \"MAX_BIN_PER_ARRAY\")[1].value\n);\n\nconst ACTIVE_ID_OUT_OF_RANGE = BIN_ARRAY_BITMAP_SIZE.addn(1);\nconst DEFAULT_ACTIVE_ID = new BN(5660);\nconst DEFAULT_BIN_STEP = new BN(10);\nconst DEFAULT_BASE_FACTOR = new BN(10000);\nconst DEFAULT_BASE_FACTOR_2 = new BN(4000);\n\nconst programId = new web3.PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\n\nlet BTC: web3.PublicKey;\nlet USDC: web3.PublicKey;\nlet lbClmm: DLMM;\nlet lbClmmWithBitMapExt: DLMM;\nlet lbPairPubkey: web3.PublicKey;\nlet lbPairWithBitMapExtPubkey: web3.PublicKey;\nlet userBTC: web3.PublicKey;\nlet userUSDC: web3.PublicKey;\nlet presetParamPda: web3.PublicKey;\nlet presetParamPda2: web3.PublicKey;\n\nconst positionKeypair = Keypair.generate();\n\nfunction assertAmountWithPrecision(\n  actualAmount: number,\n  expectedAmount: number,\n  precisionPercent: number\n) {\n  if (expectedAmount == 0 && actualAmount == 0) {\n    return;\n  }\n  let maxAmount, minAmount;\n  if (expectedAmount > actualAmount) {\n    maxAmount = expectedAmount;\n    minAmount = actualAmount;\n  } else {\n    maxAmount = actualAmount;\n    minAmount = expectedAmount;\n  }\n  let diff = ((maxAmount - minAmount) * 100) / maxAmount;\n  expect(diff).toBeLessThan(precisionPercent);\n}\n\ndescribe(\"SDK test\", () => {\n  beforeAll(async () => {\n    BTC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      btcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    USDC = await createMint(\n      connection,\n      keypair,\n      keypair.publicKey,\n      null,\n      usdcDecimal,\n      Keypair.generate(),\n      null,\n      TOKEN_PROGRAM_ID\n    );\n\n    const userBtcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      BTC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userBTC = userBtcInfo.address;\n\n    const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      USDC,\n      keypair.publicKey,\n      false,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID\n    );\n    userUSDC = userUsdcInfo.address;\n\n    await mintTo(\n      connection,\n      keypair,\n      BTC,\n      userBTC,\n      keypair.publicKey,\n      100_000_000 * 10 ** btcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    await mintTo(\n      connection,\n      keypair,\n      USDC,\n      userUSDC,\n      keypair.publicKey,\n      100_000_000 * 10 ** usdcDecimal,\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID\n    );\n\n    [lbPairPubkey] = deriveLbPair2(\n      BTC,\n      USDC,\n      DEFAULT_BIN_STEP,\n      DEFAULT_BASE_FACTOR,\n      programId\n    );\n    [lbPairWithBitMapExtPubkey] = deriveLbPair2(\n      NATIVE_MINT,\n      USDC,\n      DEFAULT_BIN_STEP,\n      DEFAULT_BASE_FACTOR_2,\n      programId\n    );\n    [presetParamPda] = derivePresetParameter2(\n      DEFAULT_BIN_STEP,\n      DEFAULT_BASE_FACTOR,\n      programId\n    );\n    [presetParamPda2] = derivePresetParameter2(\n      DEFAULT_BIN_STEP,\n      DEFAULT_BASE_FACTOR_2,\n      programId\n    );\n\n    const program = createTestProgram(connection, programId, keypair);\n\n    const operatorPda = await createWhitelistOperator(\n      connection,\n      keypair,\n      keypair.publicKey,\n      [OperatorPermission.InitializePresetParameter],\n      programId\n    );\n\n    const presetParamState =\n      await program.account.presetParameter.fetchNullable(presetParamPda);\n\n    if (!presetParamState) {\n      await program.methods\n        .initializePresetParameter({\n          index: 0,\n          binStep: DEFAULT_BIN_STEP.toNumber(),\n          baseFactor: DEFAULT_BASE_FACTOR.toNumber(),\n          functionType: FunctionType.LiquidityMining,\n          filterPeriod: 30,\n          decayPeriod: 600,\n          reductionFactor: 5000,\n          variableFeeControl: 40000,\n          protocolShare: 0,\n          maxVolatilityAccumulator: 350000,\n          baseFeePowerFactor: 0,\n        })\n        .accountsPartial({\n          signer: keypair.publicKey,\n          presetParameter: presetParamPda,\n          systemProgram: web3.SystemProgram.programId,\n          operator: operatorPda,\n        })\n        .signers([keypair])\n        .rpc({\n          commitment: \"confirmed\",\n        });\n    }\n\n    const presetParamState2 =\n      await program.account.presetParameter.fetchNullable(presetParamPda2);\n\n    if (!presetParamState2) {\n      await program.methods\n        .initializePresetParameter({\n          index: 0,\n          binStep: DEFAULT_BIN_STEP.toNumber(),\n          baseFactor: DEFAULT_BASE_FACTOR_2.toNumber(),\n          functionType: FunctionType.LiquidityMining,\n          filterPeriod: 30,\n          decayPeriod: 600,\n          reductionFactor: 5000,\n          variableFeeControl: 40000,\n          protocolShare: 0,\n          maxVolatilityAccumulator: 350000,\n          baseFeePowerFactor: 0,\n        })\n        .accountsPartial({\n          signer: keypair.publicKey,\n          presetParameter: presetParamPda2,\n          systemProgram: web3.SystemProgram.programId,\n          operator: operatorPda,\n        })\n        .signers([keypair])\n        .rpc({\n          commitment: \"confirmed\",\n        });\n    }\n  });\n\n  describe(\"Permissioned lb pair\", () => {\n    const baseKeypair = Keypair.generate();\n\n    let pairKey: PublicKey;\n    let pair: DLMM;\n    let customFeeOwnerPosition: PublicKey;\n\n    const customFeeOwnerPositionFeeOwner = Keypair.generate();\n    const customFeeOwnerPositionOwner = Keypair.generate();\n\n    const normalPosition = Keypair.generate();\n    const normalPositionOwner = keypair.publicKey;\n\n    const btcInAmount = new BN(1).mul(new BN(10 ** btcDecimal));\n    const usdcInAmount = new BN(24000).mul(new BN(10 ** usdcDecimal));\n\n    beforeAll(async () => {\n      await connection.requestAirdrop(\n        customFeeOwnerPositionOwner.publicKey,\n        2 * LAMPORTS_PER_SOL\n      );\n\n      const feeBps = new BN(50);\n      const protocolFeeBps = new BN(50);\n\n      try {\n        const program = createTestProgram(connection, programId, keypair);\n\n        const operatorPda = await createWhitelistOperator(\n          connection,\n          keypair,\n          keypair.publicKey,\n          [OperatorPermission.InitializePermissionedPool],\n          programId\n        );\n\n        [pairKey] = derivePermissionLbPair(\n          baseKeypair.publicKey,\n          BTC,\n          USDC,\n          DEFAULT_BIN_STEP,\n          programId\n        );\n\n        const [reserveX] = deriveReserve(BTC, pairKey, programId);\n        const [reserveY] = deriveReserve(USDC, pairKey, programId);\n\n        const [oracle] = deriveOracle(pairKey, program.programId);\n\n        const [baseFactor, basePowerFactor] = computeBaseFactorFromFeeBps(\n          DEFAULT_BIN_STEP,\n          feeBps\n        );\n\n        const initPermissionPairTx = await program.methods\n          .initializePermissionLbPair({\n            activeId: DEFAULT_ACTIVE_ID.toNumber(),\n            binStep: DEFAULT_BIN_STEP.toNumber(),\n            baseFactor: baseFactor.toNumber(),\n            baseFeePowerFactor: basePowerFactor.toNumber(),\n            activationType: ActivationType.Slot,\n            protocolShare: protocolFeeBps.toNumber(),\n          })\n          .accountsPartial({\n            base: baseKeypair.publicKey,\n            lbPair: pairKey,\n            binArrayBitmapExtension: program.programId,\n            tokenMintX: BTC,\n            tokenMintY: USDC,\n            reserveX,\n            reserveY,\n            oracle,\n            signer: keypair.publicKey,\n            tokenBadgeX: program.programId,\n            tokenBadgeY: program.programId,\n            tokenProgramX: TOKEN_PROGRAM_ID,\n            tokenProgramY: TOKEN_PROGRAM_ID,\n            program: program.programId,\n            operator: operatorPda,\n          })\n          .transaction();\n\n        await sendAndConfirmTransaction(connection, initPermissionPairTx, [\n          keypair,\n          baseKeypair,\n        ]);\n\n        pair = await DLMM.create(connection, pairKey, {\n          cluster: \"localhost\",\n        });\n\n        const pairState = pair.lbPair;\n        expect(pairState.pairType).toBe(PairType.Permissioned);\n      } catch (error) {\n        console.log(JSON.parse(JSON.stringify(error)));\n        throw error;\n      }\n    });\n\n    it(\"initialize position and add liquidity both side\", async () => {\n      const program = pair.program;\n      const baseKeypair = Keypair.generate();\n      const width = DEFAULT_BIN_PER_POSITION;\n      const lowerBinId = DEFAULT_ACTIVE_ID.sub(width.div(new BN(2)));\n\n      const lowerBinIdBytes = lowerBinId.isNeg()\n        ? lowerBinId.toTwos(32).toArrayLike(Buffer, \"le\", 4)\n        : lowerBinId.toArrayLike(Buffer, \"le\", 4);\n\n      const widthBytes = width.isNeg()\n        ? width.toTwos(32).toArrayLike(Buffer, \"le\", 4)\n        : width.toArrayLike(Buffer, \"le\", 4);\n\n      [customFeeOwnerPosition] = PublicKey.findProgramAddressSync(\n        [\n          Buffer.from(\"position\"),\n          pair.pubkey.toBuffer(),\n          baseKeypair.publicKey.toBuffer(),\n          lowerBinIdBytes,\n          widthBytes,\n        ],\n        pair.program.programId\n      );\n\n      const operatorTokenX = await getOrCreateAssociatedTokenAccount(\n        connection,\n        keypair,\n        BTC,\n        keypair.publicKey\n      );\n\n      const ownerTokenX = await getOrCreateAssociatedTokenAccount(\n        connection,\n        keypair,\n        BTC,\n        customFeeOwnerPositionOwner.publicKey\n      );\n\n      await transfer(\n        connection,\n        keypair,\n        operatorTokenX.address,\n        ownerTokenX.address,\n        keypair,\n        BigInt(1)\n      );\n\n      console.log(\"Initialize position by operator\");\n\n      const initializePositionByOperatorTx = await program.methods\n        .initializePositionByOperator(\n          lowerBinId.toNumber(),\n          width.toNumber(),\n          customFeeOwnerPositionFeeOwner.publicKey,\n          new BN(0)\n        )\n        .accountsPartial({\n          lbPair: pair.pubkey,\n          position: customFeeOwnerPosition,\n          base: baseKeypair.publicKey,\n          operator: keypair.publicKey,\n          operatorTokenX: operatorTokenX.address,\n          ownerTokenX: ownerTokenX.address,\n          owner: customFeeOwnerPositionOwner.publicKey,\n          program: program.programId,\n          payer: keypair.publicKey,\n        })\n        .transaction();\n\n      await sendAndConfirmTransaction(\n        connection,\n        initializePositionByOperatorTx,\n        [keypair, baseKeypair]\n      ).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n\n      await pair.refetchStates();\n\n      const position = await program.account.positionV2.fetch(\n        customFeeOwnerPosition\n      );\n\n      console.log(\"Add liquidity by strategy\");\n\n      let addLiquidityTx = await pair.addLiquidityByStrategy({\n        positionPubKey: customFeeOwnerPosition,\n        totalXAmount: new BN(0),\n        totalYAmount: usdcInAmount,\n        strategy: {\n          strategyType: StrategyType.Spot,\n          minBinId: position.lowerBinId,\n          maxBinId: pair.lbPair.activeId - 1,\n        },\n        user: keypair.publicKey,\n        slippage: 0,\n      });\n\n      await sendAndConfirmTransaction(connection, addLiquidityTx, [keypair]);\n\n      addLiquidityTx = await pair.addLiquidityByStrategy({\n        positionPubKey: customFeeOwnerPosition,\n        totalXAmount: btcInAmount,\n        totalYAmount: new BN(0),\n        strategy: {\n          strategyType: StrategyType.Spot,\n          minBinId: pair.lbPair.activeId,\n          maxBinId: position.upperBinId,\n        },\n        user: keypair.publicKey,\n        slippage: 0,\n      });\n\n      await pair.refetchStates();\n    });\n\n    it(\"Normal position add only buy side\", async () => {\n      const minBinId =\n        pair.lbPair.activeId - DEFAULT_BIN_PER_POSITION.toNumber();\n      const maxBinId = pair.lbPair.activeId - 1;\n\n      const initPositionAddLiquidityTx =\n        await pair.initializePositionAndAddLiquidityByStrategy({\n          positionPubKey: normalPosition.publicKey,\n          totalXAmount: new BN(0),\n          totalYAmount: usdcInAmount,\n          strategy: {\n            strategyType: StrategyType.Spot,\n            maxBinId,\n            minBinId,\n          },\n          user: keypair.publicKey,\n          slippage: 0,\n        });\n\n      await sendAndConfirmTransaction(connection, initPositionAddLiquidityTx, [\n        keypair,\n        normalPosition,\n      ]);\n\n      const positionAccount = await connection.getAccountInfo(\n        normalPosition.publicKey\n      );\n\n      const position = wrapPosition(\n        pair.program,\n        normalPosition.publicKey,\n        positionAccount\n      );\n\n      const lowerBinId = position.lowerBinId();\n      const upperBinId = position.upperBinId();\n      const share = position.liquidityShares();\n\n      for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n        const idx = i - lowerBinId.toNumber();\n        if (i < pair.lbPair.activeId) {\n          expect(share[idx].isZero()).toBeFalsy();\n        } else {\n          expect(share[idx].isZero()).toBeTruthy();\n        }\n      }\n    });\n\n    it(\"update activation point\", async () => {\n      try {\n        const currentSlot = await connection.getSlot();\n        const activationPoint = new BN(currentSlot + 10);\n        const rawTx = await pair.setActivationPoint(new BN(currentSlot + 10));\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n        console.log(\"Update activation point\", txHash);\n        expect(txHash).not.toBeNull();\n\n        await pair.refetchStates();\n\n        const pairState = pair.lbPair;\n        expect(pairState.activationPoint.eq(activationPoint)).toBeTruthy();\n      } catch (error) {\n        console.log(JSON.parse(JSON.stringify(error)));\n      }\n    });\n\n    it(\"normal position add liquidity both side with full position width after activation\", async () => {\n      while (true) {\n        const currentSlot = await connection.getSlot();\n        if (currentSlot >= pair.lbPair.activationPoint.toNumber()) {\n          break;\n        } else {\n          await new Promise((res) => setTimeout(res, 1000));\n        }\n      }\n\n      const positionV2 = await pair.program.account.positionV2.fetch(\n        normalPosition.publicKey\n      );\n\n      const addLiquidityTx = await pair.addLiquidityByStrategy({\n        positionPubKey: normalPosition.publicKey,\n        totalXAmount: btcInAmount,\n        totalYAmount: usdcInAmount,\n        strategy: {\n          strategyType: StrategyType.Spot,\n          minBinId: positionV2.lowerBinId,\n          maxBinId: positionV2.upperBinId,\n        },\n        user: keypair.publicKey,\n        slippage: 0,\n      });\n\n      await sendAndConfirmTransaction(connection, addLiquidityTx, [keypair]);\n\n      const positionAccount = await connection.getAccountInfo(\n        normalPosition.publicKey\n      );\n\n      const position = wrapPosition(\n        pair.program,\n        normalPosition.publicKey,\n        positionAccount\n      );\n\n      const lowerBinId = position.lowerBinId();\n      const upperBinId = position.upperBinId();\n      const share = position.liquidityShares();\n\n      for (let i = lowerBinId.toNumber(); i <= upperBinId.toNumber(); i++) {\n        const idx = i - lowerBinId.toNumber();\n        expect(share[idx].isZero()).toBeFalsy();\n      }\n    });\n\n    it(\"remove liquidity from position with custom owner, capital to position owner, but fee to fee owner\", async () => {\n      const activeBinArrayIdx = binIdToBinArrayIndex(\n        new BN(pair.lbPair.activeId)\n      );\n      const [activeBinArray] = deriveBinArray(\n        pair.pubkey,\n        activeBinArrayIdx,\n        pair.program.programId\n      );\n\n      let swapTx = await pair.swap({\n        inAmount: new BN(10000000),\n        outToken: USDC,\n        minOutAmount: new BN(0),\n        user: keypair.publicKey,\n        inToken: BTC,\n        lbPair: pair.pubkey,\n        binArraysPubkey: [activeBinArray],\n      });\n\n      await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n      swapTx = await pair.swap({\n        inAmount: new BN(100).mul(new BN(10 ** usdcDecimal)),\n        outToken: BTC,\n        minOutAmount: new BN(0),\n        user: keypair.publicKey,\n        inToken: USDC,\n        lbPair: pair.pubkey,\n        binArraysPubkey: [activeBinArray],\n      });\n\n      await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n      const ownerTokenXAta = getAssociatedTokenAddressSync(\n        pair.tokenX.publicKey,\n        customFeeOwnerPositionOwner.publicKey\n      );\n      const ownerTokenYAta = getAssociatedTokenAddressSync(\n        pair.tokenY.publicKey,\n        customFeeOwnerPositionOwner.publicKey\n      );\n      const feeOwnerTokenXAta = getAssociatedTokenAddressSync(\n        pair.tokenX.publicKey,\n        customFeeOwnerPositionFeeOwner.publicKey\n      );\n      const feeOwnerTokenYAta = getAssociatedTokenAddressSync(\n        pair.tokenY.publicKey,\n        customFeeOwnerPositionFeeOwner.publicKey\n      );\n\n      const [\n        beforeOwnerTokenX,\n        beforeOwnerTokenY,\n        beforeFeeOwnerTokenX,\n        beforeFeeOwnerTokenY,\n      ] = await Promise.all([\n        connection\n          .getTokenAccountBalance(ownerTokenXAta)\n          .then((b) => new BN(b.value.amount))\n          .catch((_) => new BN(0)),\n        connection\n          .getTokenAccountBalance(ownerTokenYAta)\n          .then((b) => new BN(b.value.amount))\n          .catch((_) => new BN(0)),\n        connection\n          .getTokenAccountBalance(feeOwnerTokenXAta)\n          .then((b) => new BN(b.value.amount))\n          .catch((_) => new BN(0)),\n        connection\n          .getTokenAccountBalance(feeOwnerTokenYAta)\n          .then((b) => new BN(b.value.amount))\n          .catch((_) => new BN(0)),\n      ]);\n\n      const positionV2 = await pair.program.account.positionV2.fetch(\n        customFeeOwnerPosition\n      );\n\n      const removeLiquidityTx = await pair.removeLiquidity({\n        user: customFeeOwnerPositionOwner.publicKey,\n        fromBinId: positionV2.lowerBinId,\n        toBinId: positionV2.upperBinId,\n        position: customFeeOwnerPosition,\n        bps: new BN(10_000),\n        shouldClaimAndClose: true,\n      });\n\n      if (Array.isArray(removeLiquidityTx)) {\n        for (const tx of removeLiquidityTx) {\n          const txHash = await sendAndConfirmTransaction(connection, tx, [\n            customFeeOwnerPositionOwner,\n          ]);\n          console.log(txHash);\n        }\n      } else {\n        const txHash = await sendAndConfirmTransaction(\n          connection,\n          removeLiquidityTx,\n          [customFeeOwnerPositionOwner]\n        );\n        console.log(txHash);\n      }\n\n      const [\n        afterOwnerTokenX,\n        afterOwnerTokenY,\n        afterFeeOwnerTokenX,\n        afterFeeOwnerTokenY,\n      ] = await Promise.all([\n        connection\n          .getTokenAccountBalance(ownerTokenXAta)\n          .then((b) => new BN(b.value.amount)),\n        connection\n          .getTokenAccountBalance(ownerTokenYAta)\n          .then((b) => new BN(b.value.amount)),\n        connection\n          .getTokenAccountBalance(feeOwnerTokenXAta)\n          .then((b) => new BN(b.value.amount)),\n        connection\n          .getTokenAccountBalance(feeOwnerTokenYAta)\n          .then((b) => new BN(b.value.amount)),\n      ]);\n\n      expect(\n        afterOwnerTokenX.sub(beforeOwnerTokenX).toNumber()\n      ).toBeGreaterThan(0);\n      expect(\n        afterOwnerTokenY.sub(beforeOwnerTokenY).toNumber()\n      ).toBeGreaterThan(0);\n      expect(\n        afterFeeOwnerTokenX.sub(beforeFeeOwnerTokenX).toNumber()\n      ).toBeGreaterThan(0);\n      expect(\n        afterFeeOwnerTokenY.sub(beforeFeeOwnerTokenY).toNumber()\n      ).toBeGreaterThan(0);\n    });\n\n    it(\"remove liquidity from position, capital and fee to position owner\", async () => {\n      await pair.refetchStates();\n\n      const positionState = await pair\n        .getPositionsByUserAndLbPair(normalPositionOwner)\n        .then((positions) => {\n          return positions.userPositions.find((p) =>\n            p.publicKey.equals(normalPosition.publicKey)\n          );\n        });\n\n      const fullAmountX = new Decimal(\n        positionState.positionData.feeX.toString()\n      )\n        .add(positionState.positionData.totalXAmount)\n        .floor();\n\n      const fullAmountY = new Decimal(\n        positionState.positionData.feeY.toString()\n      )\n        .add(positionState.positionData.totalYAmount)\n        .floor();\n\n      const ownerTokenXAta = getAssociatedTokenAddressSync(\n        pair.tokenX.publicKey,\n        normalPositionOwner\n      );\n      const ownerTokenYAta = getAssociatedTokenAddressSync(\n        pair.tokenY.publicKey,\n        normalPositionOwner\n      );\n\n      const [beforeOwnerTokenX, beforeOwnerTokenY] = await Promise.all([\n        connection\n          .getTokenAccountBalance(ownerTokenXAta)\n          .then((b) => new BN(b.value.amount)),\n        connection\n          .getTokenAccountBalance(ownerTokenYAta)\n          .then((b) => new BN(b.value.amount)),\n      ]);\n\n      const positionV2 = await pair.program.account.positionV2.fetch(\n        normalPosition.publicKey\n      );\n\n      const removeLiquidityTx = await pair.removeLiquidity({\n        user: keypair.publicKey,\n        fromBinId: positionV2.lowerBinId,\n        toBinId: positionV2.upperBinId,\n        position: normalPosition.publicKey,\n        bps: new BN(10_000),\n        shouldClaimAndClose: true,\n      });\n\n      if (Array.isArray(removeLiquidityTx)) {\n        for (const tx of removeLiquidityTx) {\n          const txHash = await sendAndConfirmTransaction(connection, tx, [\n            keypair,\n          ]);\n          console.log(txHash);\n        }\n      } else {\n        const txHash = await sendAndConfirmTransaction(\n          connection,\n          removeLiquidityTx,\n          [keypair]\n        );\n        console.log(txHash);\n      }\n\n      const [afterOwnerTokenX, afterOwnerTokenY] = await Promise.all([\n        connection\n          .getTokenAccountBalance(ownerTokenXAta)\n          .then((b) => new BN(b.value.amount)),\n        connection\n          .getTokenAccountBalance(ownerTokenYAta)\n          .then((b) => new BN(b.value.amount)),\n      ]);\n\n      const amountX = afterOwnerTokenX.sub(beforeOwnerTokenX);\n      const amountY = afterOwnerTokenY.sub(beforeOwnerTokenY);\n\n      expect(fullAmountX.toString()).toBe(amountX.toString());\n      expect(fullAmountY.toString()).toBe(amountY.toString());\n    });\n  });\n\n  it(\"create LB pair\", async () => {\n    try {\n      const rawTx = await DLMM.createLbPair(\n        connection,\n        keypair.publicKey,\n        BTC,\n        USDC,\n        new BN(DEFAULT_BIN_STEP),\n        new BN(DEFAULT_BASE_FACTOR),\n        presetParamPda,\n        DEFAULT_ACTIVE_ID,\n        { cluster: \"localhost\" }\n      );\n      const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        keypair,\n      ]);\n      expect(txHash).not.toBeNull();\n      console.log(\"Create LB pair\", txHash);\n    } catch (error) {\n      console.log(JSON.parse(JSON.stringify(error)));\n    }\n  });\n\n  it(\"fetch all preset parameter\", async () => {\n    const { presetParameter } = await DLMM.getAllPresetParameters(connection, {\n      cluster: \"localhost\",\n    });\n\n    expect(presetParameter.length).toBeGreaterThan(0);\n  });\n\n  it(\"create LB pair with bitmap extension\", async () => {\n    try {\n      const rawTx = await DLMM.createLbPair(\n        connection,\n        keypair.publicKey,\n        NATIVE_MINT,\n        USDC,\n        new BN(DEFAULT_BIN_STEP),\n        new BN(DEFAULT_BASE_FACTOR_2),\n        presetParamPda2,\n        ACTIVE_ID_OUT_OF_RANGE,\n        { cluster: \"localhost\" }\n      );\n      const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        keypair,\n      ]);\n      expect(txHash).not.toBeNull();\n      console.log(\"Create LB pair with bitmap extension\", txHash);\n    } catch (error) {\n      console.log(\"🚀 ~ it ~ error:\", JSON.parse(JSON.stringify(error)));\n    }\n  });\n\n  it(\"create LBCLMM instance\", async () => {\n    [lbClmm] = await DLMM.createMultiple(connection, [lbPairPubkey], {\n      cluster: \"localhost\",\n    });\n    expect(lbClmm).not.toBeNull();\n    expect(lbClmm).toBeInstanceOf(DLMM);\n    expect(lbClmm.tokenX.publicKey.toBase58()).toBe(BTC.toBase58());\n    expect(lbClmm.tokenY.publicKey.toBase58()).toBe(USDC.toBase58());\n\n    lbClmm = await DLMM.create(connection, lbPairPubkey, {\n      cluster: \"localhost\",\n    });\n    expect(lbClmm).not.toBeNull();\n    expect(lbClmm).toBeInstanceOf(DLMM);\n    expect(lbClmm.tokenX.publicKey.toBase58()).toBe(BTC.toBase58());\n    expect(lbClmm.tokenY.publicKey.toBase58()).toBe(USDC.toBase58());\n  });\n\n  it(\"create LBCLMM instance with bitmap extension\", async () => {\n    [lbClmmWithBitMapExt] = await DLMM.createMultiple(\n      connection,\n      [lbPairWithBitMapExtPubkey],\n      { cluster: \"localhost\" }\n    );\n    expect(lbClmmWithBitMapExt).not.toBeNull();\n    expect(lbClmmWithBitMapExt).toBeInstanceOf(DLMM);\n    expect(lbClmmWithBitMapExt.tokenX.publicKey.toBase58()).toBe(\n      NATIVE_MINT.toBase58()\n    );\n    expect(lbClmmWithBitMapExt.tokenY.publicKey.toBase58()).toBe(\n      USDC.toBase58()\n    );\n\n    lbClmmWithBitMapExt = await DLMM.create(\n      connection,\n      lbPairWithBitMapExtPubkey,\n      { cluster: \"localhost\" }\n    );\n    expect(lbClmmWithBitMapExt).not.toBeNull();\n    expect(lbClmmWithBitMapExt).toBeInstanceOf(DLMM);\n    expect(lbClmmWithBitMapExt.tokenX.publicKey.toBase58()).toBe(\n      NATIVE_MINT.toBase58()\n    );\n    expect(lbClmmWithBitMapExt.tokenY.publicKey.toBase58()).toBe(\n      USDC.toBase58()\n    );\n  });\n\n  it(\"fetch created lb pair\", async () => {\n    expect(lbClmm.lbPair).not.toBeNull();\n    expect(lbClmm.lbPair.tokenXMint.toBase58()).toBe(BTC.toBase58());\n    expect(lbClmm.lbPair.tokenYMint.toBase58()).toBe(USDC.toBase58());\n    expect(lbClmm.lbPair.activeId).toBe(DEFAULT_ACTIVE_ID.toNumber());\n    expect(lbClmm.lbPair.binStep).toBe(DEFAULT_BIN_STEP.toNumber());\n  });\n\n  it(\"fetch all lb pair\", async () => {\n    const lbPairs = await DLMM.getLbPairs(connection, { cluster: \"localhost\" });\n    expect(lbPairs.length).toBeGreaterThan(0);\n    expect(\n      lbPairs.find((lps) => lps.publicKey.toBase58() == lbPairPubkey.toBase58())\n    ).not.toBeUndefined();\n  });\n\n  it(\"initialize position and add liquidity to non exists bin arrays\", async () => {\n    await lbClmm.refetchStates();\n    const btcInAmount = new BN(1).mul(new BN(10 ** btcDecimal));\n    const usdcInAmount = new BN(24000).mul(new BN(10 ** usdcDecimal));\n\n    const minBinId = lbClmm.lbPair.activeId - 5;\n    const maxBinId = lbClmm.lbPair.activeId + 5;\n\n    const rawTxs = await lbClmm.initializePositionAndAddLiquidityByStrategy({\n      user: keypair.publicKey,\n      positionPubKey: positionKeypair.publicKey,\n      totalXAmount: btcInAmount,\n      totalYAmount: usdcInAmount,\n      strategy: {\n        minBinId,\n        maxBinId,\n        strategyType: StrategyType.Curve,\n      },\n    });\n\n    if (Array.isArray(rawTxs)) {\n      for (const rawTx of rawTxs) {\n        // Do not alter the order of the signers. Some weird bug from solana where it keep throwing error about positionKeypair has no balance.\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n          positionKeypair,\n        ]);\n        expect(txHash).not.toBeNull();\n        console.log(\"Create bin arrays, position, and add liquidity\", txHash);\n      }\n    } else {\n      // console.log(rawTxs.instructions);\n      const txHash = await sendAndConfirmTransaction(connection, rawTxs, [\n        keypair,\n        positionKeypair,\n      ]);\n      expect(txHash).not.toBeNull();\n      console.log(\"Create bin arrays, position, and add liquidity\", txHash);\n    }\n\n    const positionState = await lbClmm.program.account.positionV2.fetch(\n      positionKeypair.publicKey\n    );\n\n    const lbPairPositionsMap = await DLMM.getAllLbPairPositionsByUser(\n      connection,\n      keypair.publicKey,\n      {\n        cluster: \"localhost\",\n      }\n    );\n    const positions = lbPairPositionsMap.get(lbPairPubkey.toBase58());\n    const position = positions.lbPairPositionsData.find(({ publicKey }) =>\n      publicKey.equals(positionKeypair.publicKey)\n    );\n    const { positionData } = position;\n\n    expect(+positionData.totalXAmount).toBeLessThan(btcInAmount.toNumber());\n\n    assertAmountWithPrecision(\n      +positionData.totalXAmount,\n      btcInAmount.toNumber(),\n      5\n    );\n    expect(+positionData.totalYAmount).toBeLessThan(usdcInAmount.toNumber());\n    assertAmountWithPrecision(\n      +positionData.totalYAmount,\n      usdcInAmount.toNumber(),\n      5\n    );\n\n    expect(positionData.positionBinData.length).toBe(\n      positionState.upperBinId - positionState.lowerBinId + 1\n    );\n\n    const positionBinWithLiquidity = positionData.positionBinData.filter(\n      (p) => p.positionLiquidity != \"0\"\n    );\n    expect(positionBinWithLiquidity.length).toBe(maxBinId - minBinId + 1);\n  });\n\n  it(\"get user positions in pool\", async () => {\n    const positions = await lbClmm.getPositionsByUserAndLbPair(\n      keypair.publicKey\n    );\n    expect(positions.userPositions.length).toBeGreaterThan(0);\n    expect(\n      positions.userPositions.find(\n        (ps) => ps.publicKey.toBase58() == positionKeypair.publicKey.toBase58()\n      )\n    ).not.toBeUndefined();\n  });\n\n  describe(\"getPositionsByUserAndLbPair with GetPositionsOpt\", () => {\n    const additionalPositions: PublicKey[] = [];\n    const NUM_ADDITIONAL_POSITIONS = 4; // Create 4 more positions (total 5 with existing one)\n\n    beforeAll(async () => {\n      // Create additional positions to test chunking\n      console.log(`Creating ${NUM_ADDITIONAL_POSITIONS} additional positions for chunking test...`);\n\n      for (let i = 0; i < NUM_ADDITIONAL_POSITIONS; i++) {\n        const newPositionKeypair = Keypair.generate();\n\n        // Each position covers different bin ranges\n        const minBinId = lbClmm.lbPair.activeId - 15 - (i * 5);\n        const maxBinId = lbClmm.lbPair.activeId - 5 - (i * 5);\n\n        const btcAmount = new BN(100).mul(new BN(10 ** btcDecimal));\n        const usdcAmount = new BN(2400).mul(new BN(10 ** usdcDecimal));\n\n        try {\n          const rawTxs = await lbClmm.initializePositionAndAddLiquidityByStrategy({\n            user: keypair.publicKey,\n            positionPubKey: newPositionKeypair.publicKey,\n            totalXAmount: btcAmount,\n            totalYAmount: usdcAmount,\n            strategy: {\n              minBinId,\n              maxBinId,\n              strategyType: StrategyType.Spot,\n            },\n          });\n\n          if (Array.isArray(rawTxs)) {\n            for (const rawTx of rawTxs) {\n              await sendAndConfirmTransaction(connection, rawTx, [\n                keypair,\n                newPositionKeypair,\n              ]);\n            }\n          } else {\n            await sendAndConfirmTransaction(connection, rawTxs, [\n              keypair,\n              newPositionKeypair,\n            ]);\n          }\n\n          additionalPositions.push(newPositionKeypair.publicKey);\n          console.log(`Created additional position ${i + 1}/${NUM_ADDITIONAL_POSITIONS}`);\n        } catch (error) {\n          console.log(JSON.parse(JSON.stringify(error)));\n          throw error;\n        }\n\n        await lbClmm.refetchStates();\n      }\n\n      console.log(`Successfully created ${additionalPositions.length} additional positions`);\n    });\n\n    it(\"should fetch positions with callback and verify chunking\", async () => {\n      const chunkSize = 2;\n      const callbackData: {\n        accountsCount: number;\n        progress: ChunkCallbackInfo;\n      }[] = [];\n\n      const opt: GetPositionsOpt = {\n        chunkSize,\n        onChunkFetched: (accounts, progress) => {\n          callbackData.push({\n            accountsCount: accounts.length,\n            progress: { ...progress },\n          });\n          console.log(\n            `Chunk ${progress.chunksLoaded}/${progress.totalChunks}: ` +\n            `${accounts.length} accounts, ${progress.accountsLoaded}/${progress.totalAccounts} total`\n          );\n        },\n        isParallelExecution: false,\n      };\n\n      const result = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        opt\n      );\n\n      // Should have positions (original + additional)\n      const totalPositions = 1 + additionalPositions.length;\n      expect(result.userPositions.length).toBe(totalPositions);\n\n      // Should have multiple chunks\n      const expectedChunks = Math.ceil(totalPositions / chunkSize);\n      expect(callbackData.length).toBe(expectedChunks);\n\n      // Verify progress info\n      for (let i = 0; i < callbackData.length; i++) {\n        const { progress, accountsCount } = callbackData[i];\n        expect(accountsCount).toBeLessThanOrEqual(chunkSize);\n        expect(progress.chunksLoaded).toBe(i + 1);\n        expect(progress.totalChunks).toBe(expectedChunks);\n        expect(progress.totalAccounts).toBe(totalPositions);\n      }\n\n      // Final callback should show all accounts loaded\n      const lastCallback = callbackData[callbackData.length - 1];\n      expect(lastCallback.progress.accountsLoaded).toBe(totalPositions);\n\n      console.log(\"\\n=== Chunking Proof ===\");\n      console.log(`Total positions: ${totalPositions}`);\n      console.log(`Chunk size: ${chunkSize}`);\n      console.log(`Number of chunks: ${callbackData.length}`);\n      console.log(\"=====================\\n\");\n    });\n\n    it(\"should accumulate progress correctly in sequential mode\", async () => {\n      const chunkSize = 1;\n      const progressHistory: ChunkCallbackInfo[] = [];\n\n      const opt: GetPositionsOpt = {\n        chunkSize,\n        onChunkFetched: (_, progress) => {\n          progressHistory.push({ ...progress });\n        },\n        isParallelExecution: false,\n      };\n\n      const result = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        opt\n      );\n\n      const totalPositions = result.userPositions.length;\n      expect(progressHistory.length).toBe(totalPositions);\n\n      // Verify cumulative progress\n      for (let i = 0; i < progressHistory.length; i++) {\n        const progress = progressHistory[i];\n        expect(progress.chunksLoaded).toBe(i + 1);\n        expect(progress.accountsLoaded).toBe(i + 1);\n        expect(progress.totalChunks).toBe(totalPositions);\n        expect(progress.totalAccounts).toBe(totalPositions);\n      }\n    });\n\n    it(\"should return same positions for sequential and parallel execution\", async () => {\n      const chunkSize = 2;\n\n      const sequentialResult = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        { chunkSize, isParallelExecution: false }\n      );\n\n      const parallelResult = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        { chunkSize, isParallelExecution: true }\n      );\n\n      expect(sequentialResult.userPositions.length).toBe(\n        parallelResult.userPositions.length\n      );\n\n      const sequentialPubkeys = new Set(\n        sequentialResult.userPositions.map((p) => p.publicKey.toBase58())\n      );\n      const parallelPubkeys = new Set(\n        parallelResult.userPositions.map((p) => p.publicKey.toBase58())\n      );\n\n      expect(sequentialPubkeys).toEqual(parallelPubkeys);\n    });\n\n    it(\"should handle chunkSize larger than total positions\", async () => {\n      const chunkSize = 1000;\n      let callbackCount = 0;\n\n      const opt: GetPositionsOpt = {\n        chunkSize,\n        onChunkFetched: (accounts, progress) => {\n          callbackCount++;\n          expect(progress.totalChunks).toBe(1);\n        },\n        isParallelExecution: false,\n      };\n\n      const result = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        opt\n      );\n\n      expect(callbackCount).toBe(1);\n      expect(result.userPositions.length).toBeGreaterThan(0);\n    });\n\n    it(\"should not call callback for user with no positions\", async () => {\n      const randomUser = Keypair.generate().publicKey;\n      let callbackCalled = false;\n\n      const opt: GetPositionsOpt = {\n        chunkSize: 2,\n        onChunkFetched: () => {\n          callbackCalled = true;\n        },\n      };\n\n      const result = await lbClmm.getPositionsByUserAndLbPair(randomUser, opt);\n\n      expect(result.userPositions.length).toBe(0);\n      expect(callbackCalled).toBe(false);\n    });\n\n    it(\"should return valid position data in callbacks\", async () => {\n      const chunkSize = 2;\n      const callbackPubkeys: string[] = [];\n\n      const opt: GetPositionsOpt = {\n        chunkSize,\n        onChunkFetched: (accounts) => {\n          accounts.forEach((acc) => {\n            expect(acc.pubkey).toBeInstanceOf(PublicKey);\n            expect(acc.account).toBeDefined();\n            expect(acc.account.data).toBeDefined();\n            callbackPubkeys.push(acc.pubkey.toBase58());\n          });\n        },\n        isParallelExecution: false,\n      };\n\n      const result = await lbClmm.getPositionsByUserAndLbPair(\n        keypair.publicKey,\n        opt\n      );\n\n      expect(callbackPubkeys.length).toBe(result.userPositions.length);\n\n      // Verify no duplicates\n      const uniquePubkeys = new Set(callbackPubkeys);\n      expect(uniquePubkeys.size).toBe(callbackPubkeys.length);\n\n      // Verify result matches callback data\n      const resultPubkeys = result.userPositions.map((p) => p.publicKey.toBase58());\n      expect(resultPubkeys.sort()).toEqual(callbackPubkeys.sort());\n    });\n  });\n\n  it(\"fetch all bin arrays of the lb pair\", async () => {\n    const binArrays = await lbClmm.getBinArrays();\n    for (const binArray of binArrays) {\n      expect(binArray.account.lbPair.toBase58()).toBe(lbPairPubkey.toBase58());\n    }\n\n    const { userPositions } = await lbClmm.getPositionsByUserAndLbPair(\n      keypair.publicKey\n    );\n    expect(userPositions.length).toBeGreaterThan(0);\n\n    userPositions.forEach((position) => {\n      expect(position.positionData.positionBinData.length).toBeGreaterThan(0);\n    });\n  });\n\n  describe(\"Swap within active bin\", () => {\n    describe(\"Swap exact in\", () => {\n      let btcInAmount: BN;\n      let usdcInAmount: BN;\n      let quotedOutAmount: BN;\n      let actualOutAmount: BN;\n      let binArraysPubkeyForSwap: PublicKey[];\n\n      beforeEach(async () => {\n        await lbClmm.refetchStates();\n      });\n\n      it(\"quote X -> Y\", async () => {\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId\n        );\n\n        const activeBin = bins.bins.pop();\n\n        const btcAmountToSwapHalfUsdcOfActiveBin = new BN(\n          activeBin.yAmount.div(new BN(2)).toNumber() /\n            Number.parseFloat(activeBin.price)\n        );\n\n        btcInAmount = btcAmountToSwapHalfUsdcOfActiveBin;\n\n        const binArrays = await lbClmm.getBinArrays();\n        const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =\n          lbClmm.swapQuote(btcInAmount, true, new BN(0), binArrays);\n        expect(outAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        // Swap within active bin has no price impact\n        expect(priceImpact.isZero()).toBeTruthy();\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedOutAmount = outAmount;\n      });\n\n      it(\"swap X -> Y\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swap({\n          inAmount: btcInAmount,\n          outToken: USDC,\n          minOutAmount: new BN(0),\n          user: keypair.publicKey,\n          inToken: BTC,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap X -> Y\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.lt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.gt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterUsdc.sub(beforeUsdc);\n      });\n\n      it(\"quote matches actual swap result (X -> Y)\", () => {\n        expect(actualOutAmount.toString()).toBe(quotedOutAmount.toString());\n      });\n\n      it(\"quote Y -> X\", async () => {\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId\n        );\n\n        const activeBin = bins.bins.pop();\n\n        const usdcAmountToSwapHalfBtcOfActiveBin = new BN(\n          activeBin.xAmount.div(new BN(2)).toNumber() *\n            Number.parseFloat(activeBin.price)\n        );\n\n        usdcInAmount = usdcAmountToSwapHalfBtcOfActiveBin;\n        const binArrays = await lbClmm.getBinArrays();\n        const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =\n          lbClmm.swapQuote(usdcInAmount, false, new BN(0), binArrays);\n        expect(outAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        // Swap within active bin has no price impact\n        expect(priceImpact.isZero()).toBeTruthy();\n        // TODO: Now we disable protocol we. Re-enable it back later.\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedOutAmount = outAmount;\n      });\n\n      it(\"swap Y -> X\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swap({\n          inAmount: usdcInAmount,\n          outToken: BTC,\n          minOutAmount: new BN(0),\n          user: keypair.publicKey,\n          inToken: USDC,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap Y -> X\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.gt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.lt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterBtc.sub(beforeBtc);\n      });\n\n      it(\"quote matches actual swap result (Y -> X)\", () => {\n        expect(actualOutAmount.toString()).toBe(quotedOutAmount.toString());\n      });\n    });\n\n    describe(\"Swap exact out\", () => {\n      let outAmount: BN;\n      let quotedInAmount: BN;\n      let binArraysPubkeyForSwap: PublicKey[];\n      let quotedMaxInAmount: BN;\n      let quotedInFee: BN;\n      let actualOutAmount: BN;\n      let actualInAmount: BN;\n\n      beforeEach(async () => {\n        await lbClmm.refetchStates();\n      });\n\n      it(\"quote X -> Y\", async () => {\n        outAmount = new BN(0);\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId\n        );\n\n        const activeBin = bins.bins.pop();\n        const halfTokenYAmount = new BN(activeBin.yAmount.div(new BN(2)));\n        outAmount = halfTokenYAmount;\n        const binArrays = await lbClmm.getBinArrays();\n\n        const {\n          fee,\n          inAmount,\n          maxInAmount,\n          protocolFee,\n          binArraysPubkey,\n          priceImpact,\n        } = lbClmm.swapQuoteExactOut(outAmount, true, new BN(5), binArrays);\n\n        expect(inAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n        expect(priceImpact.toNumber()).toBe(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedMaxInAmount = maxInAmount;\n        quotedInFee = fee;\n        quotedInAmount = inAmount;\n      });\n\n      it(\"swap X -> Y\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swapExactOut({\n          maxInAmount: quotedMaxInAmount.add(quotedInFee),\n          inToken: BTC,\n          outToken: USDC,\n          outAmount,\n          user: keypair.publicKey,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap X -> Y\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.lt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.gt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterUsdc.sub(beforeUsdc);\n        actualInAmount = beforeBtc.sub(afterBtc);\n      });\n\n      it(\"quote matches actual swap result (X -> Y)\", () => {\n        expect(actualOutAmount.toString()).toBe(outAmount.toString());\n        expect(actualInAmount.toString()).toBe(quotedInAmount.toString());\n      });\n\n      it(\"quote Y -> X\", async () => {\n        outAmount = new BN(0);\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId\n        );\n\n        const activeBin = bins.bins.pop();\n        const halfTokenXAmount = new BN(activeBin.xAmount.div(new BN(2)));\n        outAmount = halfTokenXAmount;\n        const binArrays = await lbClmm.getBinArrays();\n\n        const {\n          fee,\n          inAmount,\n          maxInAmount,\n          protocolFee,\n          binArraysPubkey,\n          priceImpact,\n        } = lbClmm.swapQuoteExactOut(outAmount, false, new BN(5), binArrays);\n\n        expect(inAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n        expect(priceImpact.toNumber()).toBe(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedMaxInAmount = maxInAmount;\n        quotedInFee = fee;\n        quotedInAmount = inAmount;\n      });\n\n      it(\"swap Y -> X\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swapExactOut({\n          maxInAmount: quotedMaxInAmount.add(quotedInFee),\n          inToken: USDC,\n          outToken: BTC,\n          outAmount,\n          user: keypair.publicKey,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]).catch((err) => {\n          console.error(err);\n          throw err;\n        });\n\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap Y -> X\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.gt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.lt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterBtc.sub(beforeBtc);\n        actualInAmount = beforeUsdc.sub(afterUsdc);\n      });\n\n      it(\"quote matches actual swap result (Y -> X)\", () => {\n        expect(actualOutAmount.toString()).toBe(outAmount.toString());\n        expect(actualInAmount.toString()).toBe(quotedInAmount.toString());\n      });\n    });\n  });\n\n  describe(\"Swap with 2 bin\", () => {\n    describe(\"Swap exact in\", () => {\n      let btcInAmount: BN;\n      let usdcInAmount: BN;\n      let quotedOutAmount: BN;\n      let actualOutAmount: BN;\n      let binArraysPubkeyForSwap: PublicKey[];\n\n      beforeEach(async () => {\n        await lbClmm.refetchStates();\n      });\n\n      it(\"quote X -> Y\", async () => {\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId - 1,\n          lbClmm.lbPair.activeId\n        );\n\n        const beforeActiveBin = bins.bins.pop();\n        const activeBin = bins.bins.pop();\n\n        const btcAmountToCrossBin =\n          activeBin.yAmount.toNumber() / Number.parseFloat(activeBin.price) +\n          beforeActiveBin.yAmount.div(new BN(2)).toNumber() /\n            Number.parseFloat(activeBin.price);\n\n        btcInAmount = new BN(btcAmountToCrossBin + 1);\n\n        const binArrays = await lbClmm.getBinArrays();\n        const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =\n          lbClmm.swapQuote(btcInAmount, true, new BN(0), binArrays);\n        expect(outAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        // Swap with crossing bins has price impact\n        expect(!priceImpact.isZero()).toBeTruthy();\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedOutAmount = outAmount;\n      });\n\n      it(\"swap X -> Y\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swap({\n          inAmount: btcInAmount,\n          outToken: USDC,\n          minOutAmount: new BN(0),\n          user: keypair.publicKey,\n          inToken: BTC,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap X -> Y\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.lt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.gt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterUsdc.sub(beforeUsdc);\n      });\n\n      it(\"quote matches actual swap result (X -> Y)\", () => {\n        expect(actualOutAmount.toString()).toBe(quotedOutAmount.toString());\n      });\n\n      it(\"quote Y -> X\", async () => {\n        const bins = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId + 1\n        );\n\n        const activeBin = bins.bins.pop();\n        const afterActiveBin = bins.bins.pop();\n\n        const usdcAmountToCrossBin =\n          activeBin.xAmount.toNumber() * Number.parseFloat(activeBin.price) +\n          afterActiveBin.xAmount.div(new BN(2)).toNumber() *\n            Number.parseFloat(afterActiveBin.price);\n        usdcInAmount = new BN(usdcAmountToCrossBin + 1);\n\n        const binArrays = await lbClmm.getBinArrays();\n        const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =\n          lbClmm.swapQuote(usdcInAmount, false, new BN(0), binArrays);\n        expect(outAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        // Swap with crossing bins has price impact\n        expect(!priceImpact.isZero()).toBeTruthy();\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedOutAmount = outAmount;\n      });\n\n      it(\"swap Y -> X\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swap({\n          inAmount: usdcInAmount,\n          outToken: BTC,\n          minOutAmount: new BN(0),\n          user: keypair.publicKey,\n          inToken: USDC,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap Y -> X\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.gt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.lt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterBtc.sub(beforeBtc);\n      });\n\n      it(\"quote matches actual swap result (Y -> X)\", () => {\n        expect(actualOutAmount.toString()).toBe(quotedOutAmount.toString());\n      });\n    });\n\n    describe(\"Swap exact out\", () => {\n      let outAmount: BN;\n      let quotedInAmount: BN;\n      let binArraysPubkeyForSwap: PublicKey[];\n      let quotedMaxInAmount: BN;\n      let quotedInFee: BN;\n      let actualOutAmount: BN;\n      let actualInAmount: BN;\n\n      beforeEach(async () => {\n        await lbClmm.refetchStates();\n      });\n\n      it(\"quote X -> Y\", async () => {\n        outAmount = new BN(0);\n        const { bins } = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId - 1,\n          lbClmm.lbPair.activeId\n        );\n\n        const sortedBins = bins.sort((a, b) => b.binId - a.binId);\n\n        const activeBin = sortedBins.pop();\n        outAmount = outAmount.add(activeBin.yAmount);\n        const beforeActiveBin = sortedBins.pop();\n        outAmount = outAmount.add(beforeActiveBin.yAmount.div(new BN(2)));\n\n        const binArrays = await lbClmm.getBinArrays();\n\n        const {\n          fee,\n          inAmount,\n          maxInAmount,\n          protocolFee,\n          binArraysPubkey,\n          priceImpact,\n        } = lbClmm.swapQuoteExactOut(outAmount, true, new BN(5), binArrays);\n\n        expect(inAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n        expect(priceImpact.toNumber()).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedMaxInAmount = maxInAmount;\n        quotedInFee = fee;\n        quotedInAmount = inAmount;\n      });\n\n      it(\"swap X -> Y\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swapExactOut({\n          maxInAmount: quotedMaxInAmount.add(quotedInFee),\n          inToken: BTC,\n          outToken: USDC,\n          outAmount,\n          user: keypair.publicKey,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap X -> Y\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.lt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.gt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterUsdc.sub(beforeUsdc);\n        actualInAmount = beforeBtc.sub(afterBtc);\n      });\n\n      it(\"quote matches actual swap result (X -> Y)\", () => {\n        expect(actualOutAmount.toString()).toBe(outAmount.toString());\n        expect(actualInAmount.toString()).toBe(quotedInAmount.toString());\n      });\n\n      it(\"quote Y -> X\", async () => {\n        outAmount = new BN(0);\n        const { bins } = await lbClmm.getBinsBetweenLowerAndUpperBound(\n          lbClmm.lbPair.activeId,\n          lbClmm.lbPair.activeId + 1\n        );\n\n        const sortedBins = bins.sort((a, b) => a.binId - b.binId);\n\n        const activeBin = sortedBins.pop();\n        outAmount = outAmount.add(activeBin.xAmount);\n        const afterActiveBin = sortedBins.pop();\n        outAmount = outAmount.add(afterActiveBin.xAmount.div(new BN(2)));\n\n        const binArrays = await lbClmm.getBinArrays();\n\n        const {\n          fee,\n          inAmount,\n          maxInAmount,\n          protocolFee,\n          binArraysPubkey,\n          priceImpact,\n        } = lbClmm.swapQuoteExactOut(outAmount, false, new BN(5), binArrays);\n\n        expect(inAmount.toString()).not.toEqual(\"0\");\n        expect(fee.toString()).not.toEqual(\"0\");\n        expect(protocolFee.toString()).toEqual(\"0\");\n        expect(binArraysPubkey.length).toBeGreaterThan(0);\n        expect(priceImpact.toNumber()).toBeGreaterThan(0);\n\n        binArraysPubkeyForSwap = binArraysPubkey;\n        quotedMaxInAmount = maxInAmount;\n        quotedInFee = fee;\n        quotedInAmount = inAmount;\n      });\n\n      it(\"swap Y -> X\", async () => {\n        const [beforeBtc, beforeUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        const rawTx = await lbClmm.swapExactOut({\n          maxInAmount: quotedMaxInAmount.add(quotedInFee),\n          inToken: USDC,\n          outToken: BTC,\n          outAmount,\n          user: keypair.publicKey,\n          lbPair: lbPairPubkey,\n          binArraysPubkey: binArraysPubkeyForSwap,\n        });\n\n        const txHash = await sendAndConfirmTransaction(connection, rawTx, [\n          keypair,\n        ]);\n\n        expect(txHash).not.toBeNull();\n        console.log(\"Swap Y -> X\", txHash);\n\n        const [afterBtc, afterUsdc] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userBTC)\n            .then((ta) => new BN(ta.value.amount)),\n          connection\n            .getTokenAccountBalance(userUSDC)\n            .then((ta) => new BN(ta.value.amount)),\n        ]);\n\n        expect(afterBtc.gt(beforeBtc)).toBeTruthy();\n        expect(afterUsdc.lt(beforeUsdc)).toBeTruthy();\n\n        actualOutAmount = afterBtc.sub(beforeBtc);\n        actualInAmount = beforeUsdc.sub(afterUsdc);\n      });\n\n      it(\"quote matches actual swap result (Y -> X)\", () => {\n        expect(actualOutAmount.toString()).toBe(outAmount.toString());\n        expect(actualInAmount.toString()).toBe(quotedInAmount.toString());\n      });\n    });\n  });\n});\n\ndescribe(\"SDK Test with Mainnet RPC\", () => {\n  let mainnetRpc: string =\n    process.env.RPC || \"https://api.mainnet-beta.solana.com\";\n  let connection: Connection;\n\n  beforeAll(async () => {\n    connection = new Connection(mainnetRpc);\n  });\n\n  it(\"quote X -> Y with maxExtraBinArrays\", async () => {\n    const pair = new PublicKey(\"5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6\");\n    const lbPair = await DLMM.create(connection, pair);\n    const swapForY = true;\n    const inAmount = new BN(1 * 10 ** 9);\n    const allowedSlippage = new BN(2);\n    const isPartialFill = false;\n\n    const binArrays = await lbPair.getBinArrayForSwap(swapForY);\n    expect(binArrays.length).toBeGreaterThan(1);\n    let quote = lbPair.swapQuote(\n      inAmount,\n      swapForY,\n      allowedSlippage,\n      binArrays,\n      isPartialFill,\n      0\n    );\n    expect(quote.binArraysPubkey.length).toEqual(1);\n    const binArrayToSwapPubkey = quote.binArraysPubkey[0];\n    const binArrayToSwap = await lbPair.program.account.binArray.fetch(\n      binArrayToSwapPubkey\n    );\n\n    quote = lbPair.swapQuote(\n      inAmount,\n      swapForY,\n      allowedSlippage,\n      binArrays,\n      isPartialFill,\n      3\n    );\n    expect(quote.binArraysPubkey.length).toEqual(4);\n\n    // expect binArrays are in correct order\n    expect(quote.binArraysPubkey[0]).toEqual(binArrayToSwapPubkey);\n\n    let lastBinArrayIdx = binArrayToSwap.index;\n    for (let i = 1; i < binArrays.length; i++) {\n      let assertBinArrayPubkey = quote.binArraysPubkey[i];\n\n      const assertBinArray = await lbPair.program.account.binArray.fetch(\n        assertBinArrayPubkey\n      );\n      if (swapForY) {\n        expect(assertBinArray.index).toEqual(lastBinArrayIdx.sub(new BN(1)));\n      } else {\n        expect(assertBinArray.index).toEqual(lastBinArrayIdx.add(new BN(1)));\n      }\n\n      lastBinArrayIdx = assertBinArray.index;\n    }\n  });\n\n  it(\"quote Y -> X with maxExtraBinArrays\", async () => {\n    const pair = new PublicKey(\"5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6\");\n    const lbPair = await DLMM.create(connection, pair);\n    const swapForY = true;\n    const inAmount = new BN(1_000 * 10 ** 6);\n    const allowedSlippage = new BN(2);\n    const isPartialFill = false;\n\n    const binArrays = await lbPair.getBinArrayForSwap(swapForY);\n    expect(binArrays.length).toBeGreaterThan(1);\n    let quote = lbPair.swapQuote(\n      inAmount,\n      swapForY,\n      allowedSlippage,\n      binArrays,\n      isPartialFill,\n      0\n    );\n    expect(quote.binArraysPubkey.length).toEqual(1);\n\n    const binArrayToSwapPubkey = quote.binArraysPubkey[0];\n    const binArrayToSwap = await lbPair.program.account.binArray.fetch(\n      binArrayToSwapPubkey\n    );\n\n    quote = lbPair.swapQuote(\n      inAmount,\n      swapForY,\n      allowedSlippage,\n      binArrays,\n      isPartialFill,\n      3\n    );\n    expect(quote.binArraysPubkey.length).toEqual(4);\n\n    // expect binArrays are in correct order\n    expect(quote.binArraysPubkey[0]).toEqual(binArrayToSwapPubkey);\n\n    let lastBinArrayIdx = binArrayToSwap.index;\n    for (let i = 1; i < binArrays.length; i++) {\n      let assertBinArrayPubkey = quote.binArraysPubkey[i];\n\n      const assertBinArray = await lbPair.program.account.binArray.fetch(\n        assertBinArrayPubkey\n      );\n      if (swapForY) {\n        expect(assertBinArray.index).toEqual(lastBinArrayIdx.sub(new BN(1)));\n      } else {\n        expect(assertBinArray.index).toEqual(lastBinArrayIdx.add(new BN(1)));\n      }\n\n      lastBinArrayIdx = assertBinArray.index;\n    }\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/sdk_token2022.test.ts",
    "content": "import { Wallet } from \"@coral-xyz/anchor\";\nimport { SYSTEM_PROGRAM_ID } from \"@coral-xyz/anchor/dist/cjs/native/system\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  createInitializeMintInstruction,\n  createInitializeTransferFeeConfigInstruction,\n  createInitializeTransferHookInstruction,\n  ExtensionType,\n  getAssociatedTokenAddressSync,\n  getMintLen,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n  NATIVE_MINT,\n  TOKEN_2022_PROGRAM_ID,\n  TOKEN_PROGRAM_ID,\n  unpackAccount,\n} from \"@solana/spl-token\";\nimport {\n  AccountInfo,\n  AddressLookupTableProgram,\n  Cluster,\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  PublicKey,\n  sendAndConfirmTransaction,\n  SystemProgram,\n  Transaction,\n  TransactionMessage,\n  VersionedTransaction,\n} from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport fs from \"fs\";\nimport { DLMM } from \"../dlmm\";\nimport {\n  BASIS_POINT_MAX,\n  DEFAULT_BIN_PER_POSITION,\n  FunctionType,\n  LBCLMM_PROGRAM_IDS,\n  POSITION_MAX_LENGTH,\n} from \"../dlmm/constants\";\nimport {\n  binIdToBinArrayIndex,\n  deriveBinArray,\n  deriveCustomizablePermissionlessLbPair,\n  deriveEventAuthority,\n  deriveLbPairWithPresetParamWithIndexKey,\n  deriveOperator,\n  derivePresetParameterWithIndex,\n  deriveRewardVault,\n  deriveTokenBadge,\n  toAmountsBothSideByStrategy,\n  wrapSOLInstruction,\n} from \"../dlmm/helpers\";\nimport {\n  calculateTransferFeeExcludedAmount,\n  getExtraAccountMetasForTransferHook,\n} from \"../dlmm/helpers/token_2022\";\nimport {\n  ActivationType,\n  MEMO_PROGRAM_ID,\n  ResizeSide,\n  StrategyType,\n} from \"../dlmm/types\";\nimport { createExtraAccountMetaListAndCounter } from \"./external/helper\";\nimport {\n  createTransferHookCounterProgram,\n  TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n} from \"./external/program\";\nimport {\n  createTestProgram,\n  createWhitelistOperator,\n  logLbPairLiquidities,\n  OperatorPermission,\n} from \"./helper\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\",\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer)),\n);\n\nconst btcDecimal = 9;\nconst solDecimal = 9;\nconst metDecimal = 6;\n\nconst BTCKeypair = Keypair.generate();\nconst METKeypair = Keypair.generate();\n\nconst BTC2022 = BTCKeypair.publicKey;\nconst SOL = NATIVE_MINT;\nconst MET2022 = METKeypair.publicKey;\n\nconst transferFeeBps = 500; // 5%\nconst maxFee = BigInt(100_000) * BigInt(10 ** btcDecimal);\n\nlet presetParameter2Key: PublicKey;\nlet pairKey: PublicKey;\n\nconst program = createTestProgram(\n  connection,\n  new PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]),\n  keypair,\n);\n\nconst nonExtendedPositionKeypair0 = Keypair.generate();\nconst nonExtendedPositionKeypair1 = Keypair.generate();\n\nconst extendedPositionKeypair0 = Keypair.generate();\n\nconst MAX_ALLOWED_LAMPORT_LOSS = 500;\n\ntype Opt = {\n  cluster?: Cluster | \"localhost\";\n  programId?: PublicKey;\n  skipSolWrappingOperation?: boolean;\n};\n\nconst opt: Opt = {\n  cluster: \"localhost\",\n  skipSolWrappingOperation: true,\n};\n\ndescribe(\"SDK token2022 test\", () => {\n  // Token setup\n  beforeAll(async () => {\n    const airdropSig = await connection.requestAirdrop(\n      keypair.publicKey,\n      200 * LAMPORTS_PER_SOL,\n    );\n    await connection.confirmTransaction(airdropSig, \"confirmed\");\n\n    const userWsolAccount = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      SOL,\n      keypair.publicKey,\n      true,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID,\n    );\n\n    const wrapSolIx = await wrapSOLInstruction(\n      keypair.publicKey,\n      userWsolAccount.address,\n      BigInt(100) * BigInt(10 ** solDecimal),\n    );\n\n    const wrapSolTx = new Transaction({\n      ...(await connection.getLatestBlockhash(\"confirmed\")),\n      feePayer: keypair.publicKey,\n    }).add(...wrapSolIx);\n\n    await sendAndConfirmTransaction(connection, wrapSolTx, [keypair], {\n      commitment: \"confirmed\",\n    });\n\n    const extensions = [\n      ExtensionType.TransferFeeConfig,\n      ExtensionType.TransferHook,\n    ];\n\n    const mintLen = getMintLen(extensions);\n    const minLamports =\n      await connection.getMinimumBalanceForRentExemption(mintLen);\n\n    const createBtcTx = new Transaction()\n      .add(\n        SystemProgram.createAccount({\n          fromPubkey: keypair.publicKey,\n          newAccountPubkey: BTCKeypair.publicKey,\n          space: mintLen,\n          lamports: minLamports,\n          programId: TOKEN_2022_PROGRAM_ID,\n        }),\n      )\n      .add(\n        createInitializeTransferFeeConfigInstruction(\n          BTC2022,\n          keypair.publicKey,\n          keypair.publicKey,\n          transferFeeBps,\n          maxFee,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      )\n      .add(\n        createInitializeTransferHookInstruction(\n          BTC2022,\n          keypair.publicKey,\n          TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      )\n      .add(\n        createInitializeMintInstruction(\n          BTC2022,\n          btcDecimal,\n          keypair.publicKey,\n          null,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      );\n\n    await sendAndConfirmTransaction(\n      connection,\n      createBtcTx,\n      [keypair, BTCKeypair],\n      { commitment: \"confirmed\" },\n    );\n\n    const transferHookCounterProgram = createTransferHookCounterProgram(\n      new Wallet(keypair),\n      TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n      connection,\n    );\n\n    await createExtraAccountMetaListAndCounter(\n      transferHookCounterProgram,\n      BTC2022,\n    );\n\n    const userBtcAccount = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      BTC2022,\n      keypair.publicKey,\n      true,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_2022_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID,\n    );\n\n    const userBtcAta = userBtcAccount.address;\n\n    await mintTo(\n      connection,\n      keypair,\n      BTC2022,\n      userBtcAta,\n      keypair,\n      BigInt(1_000_000_000) * BigInt(10 ** btcDecimal),\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_2022_PROGRAM_ID,\n    );\n\n    const createMetTx = new Transaction()\n      .add(\n        SystemProgram.createAccount({\n          fromPubkey: keypair.publicKey,\n          newAccountPubkey: METKeypair.publicKey,\n          space: mintLen,\n          lamports: minLamports,\n          programId: TOKEN_2022_PROGRAM_ID,\n        }),\n      )\n      .add(\n        createInitializeTransferFeeConfigInstruction(\n          MET2022,\n          keypair.publicKey,\n          keypair.publicKey,\n          transferFeeBps,\n          maxFee,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      )\n      .add(\n        createInitializeTransferHookInstruction(\n          MET2022,\n          keypair.publicKey,\n          TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      )\n      .add(\n        createInitializeMintInstruction(\n          MET2022,\n          metDecimal,\n          keypair.publicKey,\n          null,\n          TOKEN_2022_PROGRAM_ID,\n        ),\n      );\n\n    await sendAndConfirmTransaction(\n      connection,\n      createMetTx,\n      [keypair, METKeypair],\n      { commitment: \"confirmed\" },\n    );\n\n    await createExtraAccountMetaListAndCounter(\n      transferHookCounterProgram,\n      MET2022,\n    );\n\n    const userMetAccount = await getOrCreateAssociatedTokenAccount(\n      connection,\n      keypair,\n      MET2022,\n      keypair.publicKey,\n      true,\n      \"confirmed\",\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_2022_PROGRAM_ID,\n      ASSOCIATED_TOKEN_PROGRAM_ID,\n    );\n\n    const userMetAta = userMetAccount.address;\n\n    await mintTo(\n      connection,\n      keypair,\n      MET2022,\n      userMetAta,\n      keypair,\n      BigInt(1_000_000_000) * BigInt(10 ** metDecimal),\n      [],\n      {\n        commitment: \"confirmed\",\n      },\n      TOKEN_2022_PROGRAM_ID,\n    );\n  });\n\n  // DLMM related setup\n  beforeAll(async () => {\n    const presetParameter2 = await program.account.presetParameter2.all();\n    const idx = presetParameter2.length;\n\n    [presetParameter2Key] = derivePresetParameterWithIndex(\n      new BN(idx),\n      program.programId,\n    );\n\n    const operatorPda = await createWhitelistOperator(\n      connection,\n      keypair,\n      keypair.publicKey,\n      [\n        OperatorPermission.InitializePresetParameter,\n        OperatorPermission.InitializeTokenBadge,\n        OperatorPermission.InitializeReward,\n      ],\n      program.programId,\n    );\n\n    await program.methods\n      .initializePresetParameter({\n        index: idx,\n        binStep: 10,\n        baseFactor: 10_000,\n        functionType: FunctionType.LiquidityMining,\n        filterPeriod: 30,\n        decayPeriod: 600,\n        reductionFactor: 5000,\n        variableFeeControl: 40000,\n        protocolShare: 0,\n        maxVolatilityAccumulator: 350000,\n        baseFeePowerFactor: 1,\n      })\n      .accountsPartial({\n        presetParameter: presetParameter2Key,\n        signer: keypair.publicKey,\n        systemProgram: SystemProgram.programId,\n        operator: operatorPda,\n      })\n      .rpc();\n\n    const [btcTokenBadge] = deriveTokenBadge(BTC2022, program.programId);\n\n    await program.methods\n      .initializeTokenBadge()\n      .accountsPartial({\n        tokenBadge: btcTokenBadge,\n        signer: keypair.publicKey,\n        systemProgram: SystemProgram.programId,\n        tokenMint: BTC2022,\n        operator: operatorPda,\n      })\n      .rpc();\n\n    const [metTokenBadge] = deriveTokenBadge(MET2022, program.programId);\n\n    await program.methods\n      .initializeTokenBadge()\n      .accountsPartial({\n        tokenBadge: metTokenBadge,\n        signer: keypair.publicKey,\n        systemProgram: SystemProgram.programId,\n        tokenMint: MET2022,\n        operator: operatorPda,\n      })\n      .rpc();\n  });\n\n  it(\"getAllPresetParameters return created preset parameter 2\", async () => {\n    const { presetParameter2 } = await DLMM.getAllPresetParameters(\n      connection,\n      opt,\n    );\n\n    expect(presetParameter2.length).toBeGreaterThan(0);\n  });\n\n  describe(\"Pair\", () => {\n    it(\"createLbPair2 with token 2022\", async () => {\n      const activeId = new BN(0);\n\n      const createLbPair2Tx = await DLMM.createLbPair2(\n        connection,\n        keypair.publicKey,\n        BTC2022,\n        SOL,\n        presetParameter2Key,\n        activeId,\n        opt,\n      );\n\n      await sendAndConfirmTransaction(connection, createLbPair2Tx, [keypair], {\n        commitment: \"confirmed\",\n      });\n\n      [pairKey] = deriveLbPairWithPresetParamWithIndexKey(\n        presetParameter2Key,\n        BTC2022,\n        SOL,\n        program.programId,\n      );\n\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const feeInfo = dlmm.getFeeInfo();\n      expect(feeInfo.baseFeeRatePercentage.toNumber()).toBe(1);\n      expect(dlmm.lbPair.binStep).toBe(10);\n    });\n\n    it(\"createCustomizablePermissionlessLbPair2 with token 2022\", async () => {\n      const binStep = new BN(1);\n      const activeId = new BN(0);\n      const feeBps = new BN(150);\n\n      const createCustomizablePermissionlessLbPair2Tx =\n        await DLMM.createCustomizablePermissionlessLbPair2(\n          connection,\n          binStep,\n          BTC2022,\n          SOL,\n          activeId,\n          feeBps,\n          ActivationType.Timestamp,\n          false,\n          keypair.publicKey,\n          null,\n          false,\n          opt,\n        );\n\n      await sendAndConfirmTransaction(\n        connection,\n        createCustomizablePermissionlessLbPair2Tx,\n        [keypair],\n      );\n\n      const [pairKey] = deriveCustomizablePermissionlessLbPair(\n        BTC2022,\n        SOL,\n        program.programId,\n      );\n\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const feeInfo = dlmm.getFeeInfo();\n      expect(feeInfo.baseFeeRatePercentage.toNumber()).toBe(1.5);\n      expect(feeInfo.protocolFeePercentage.toNumber()).toBe(20);\n    });\n\n    it(\"getPairPubkeyIfExists return pair permissionless pair pubkey\", async () => {\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const pairPubkey = await DLMM.getPairPubkeyIfExists(\n        connection,\n        dlmm.lbPair.tokenXMint,\n        dlmm.lbPair.tokenYMint,\n        new BN(dlmm.lbPair.binStep),\n        new BN(dlmm.lbPair.parameters.baseFactor),\n        new BN(dlmm.lbPair.parameters.baseFeePowerFactor),\n        opt,\n      );\n\n      expect(pairPubkey.toBase58()).toBe(pairKey.toBase58());\n    });\n\n    it(\"createMultiple works\", async () => {\n      const lbPairs = await DLMM.getLbPairs(connection, opt);\n\n      const dlmms = await DLMM.createMultiple(\n        connection,\n        lbPairs.map((x) => x.publicKey),\n        opt,\n      );\n\n      for (let i = 0; i < lbPairs.length; i++) {\n        const dlmm = dlmms[i];\n        const lbPair = lbPairs[i];\n\n        expect(dlmm.pubkey.toBase58()).toBe(lbPair.publicKey.toBase58());\n        expect(dlmm.tokenX.publicKey.toBase58()).toBe(\n          lbPair.account.tokenXMint.toBase58(),\n        );\n        expect(dlmm.tokenY.publicKey.toBase58()).toBe(\n          lbPair.account.tokenYMint.toBase58(),\n        );\n      }\n    });\n  });\n\n  describe(\"Empty position management\", () => {\n    beforeAll(async () => {\n      const rewardIndex = new BN(0);\n      const rewardDuration = new BN(300);\n      const fundingReward = new BN(\n        (BigInt(1_000_000) * BigInt(10 ** metDecimal)).toString(),\n      );\n\n      const funder = keypair.publicKey;\n\n      const [rewardVault] = deriveRewardVault(\n        pairKey,\n        rewardIndex,\n        program.programId,\n      );\n\n      const metAccount = await connection.getAccountInfo(MET2022);\n\n      const [tokenBadge] = deriveTokenBadge(MET2022, program.programId);\n\n      const operatorPda = deriveOperator(keypair.publicKey, program.programId);\n\n      await program.methods\n        .initializeReward(rewardIndex, rewardDuration, funder)\n        .accountsPartial({\n          lbPair: pairKey,\n          rewardMint: MET2022,\n          rewardVault,\n          signer: keypair.publicKey,\n          tokenBadge,\n          tokenProgram: metAccount.owner,\n          systemProgram: SystemProgram.programId,\n          operator: operatorPda,\n        })\n        .rpc();\n\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n      const activeBinArrayIndex = binIdToBinArrayIndex(\n        new BN(dlmm.lbPair.activeId),\n      );\n      const activeBinArrayKey = deriveBinArray(\n        dlmm.pubkey,\n        activeBinArrayIndex,\n        dlmm.program.programId,\n      )[0];\n\n      const initActiveBinArrayIxs = await dlmm.initializeBinArrays(\n        [activeBinArrayIndex],\n        funder,\n      );\n\n      const { blockhash, lastValidBlockHeight } =\n        await connection.getLatestBlockhash(\"confirmed\");\n\n      const tx = new Transaction({\n        blockhash,\n        lastValidBlockHeight,\n      }).add(...initActiveBinArrayIxs);\n\n      await sendAndConfirmTransaction(connection, tx, [keypair]);\n\n      const metTransferHookAccountMetas =\n        await getExtraAccountMetasForTransferHook(\n          connection,\n          MET2022,\n          metAccount,\n        );\n\n      const metAtaKey = getAssociatedTokenAddressSync(\n        MET2022,\n        funder,\n        true,\n        metAccount.owner,\n      );\n\n      await program.methods\n        .fundReward(rewardIndex, fundingReward, true, {\n          slices: [\n            {\n              accountsType: {\n                transferHookReward: {},\n              },\n              length: metTransferHookAccountMetas.length,\n            },\n          ],\n        })\n        .accountsPartial({\n          lbPair: pairKey,\n          rewardMint: MET2022,\n          rewardVault,\n          funder,\n          binArray: activeBinArrayKey,\n          funderTokenAccount: metAtaKey,\n          tokenProgram: metAccount.owner,\n        })\n        .remainingAccounts(metTransferHookAccountMetas)\n        .rpc();\n    });\n\n    it(\"createEmptyPosition\", async () => {\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const minBinId = -30;\n      const maxBinId = 30;\n\n      const createPositionAndBinArraysTx = await dlmm.createEmptyPosition({\n        positionPubKey: nonExtendedPositionKeypair0.publicKey,\n        minBinId,\n        maxBinId,\n        user: keypair.publicKey,\n      });\n\n      await sendAndConfirmTransaction(\n        connection,\n        createPositionAndBinArraysTx,\n        [keypair, nonExtendedPositionKeypair0],\n      );\n\n      const position = await dlmm.getPosition(\n        nonExtendedPositionKeypair0.publicKey,\n      );\n      expect(position.publicKey.toBase58()).toBe(\n        nonExtendedPositionKeypair0.publicKey.toBase58(),\n      );\n\n      const { positionData } = position;\n      expect(positionData.lowerBinId).toBe(minBinId);\n      expect(positionData.upperBinId).toBe(maxBinId);\n\n      const binCount = maxBinId - minBinId + 1;\n      expect(positionData.positionBinData.length).toBe(binCount);\n    });\n\n    it(\"createExtendedEmptyPosition\", async () => {\n      const positionKp = Keypair.generate();\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const minBinId = -30;\n      const maxBinId = minBinId + 1400 - 1;\n\n      const createAndExtendPositionTx = await dlmm.createExtendedEmptyPosition(\n        minBinId,\n        maxBinId,\n        positionKp.publicKey,\n        keypair.publicKey,\n      );\n\n      createAndExtendPositionTx.sign(keypair, positionKp);\n\n      await connection\n        .sendRawTransaction(createAndExtendPositionTx.serialize())\n        .then((sig) => {\n          return connection.confirmTransaction(sig);\n        });\n\n      const position = await dlmm.getPosition(positionKp.publicKey);\n      expect(position.publicKey.toBase58()).toBe(\n        positionKp.publicKey.toBase58(),\n      );\n\n      const { positionData } = position;\n      expect(positionData.lowerBinId).toBe(minBinId);\n      expect(positionData.upperBinId).toBe(maxBinId);\n\n      const binCount = maxBinId - minBinId + 1;\n      expect(positionData.positionBinData.length).toBe(binCount);\n    });\n\n    it(\"quote extend position\", async () => {\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const minBinId =\n        dlmm.lbPair.activeId - POSITION_MAX_LENGTH.toNumber() / 2;\n      const maxBinId = minBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1;\n      const extendedMaxBinId = minBinId + POSITION_MAX_LENGTH.toNumber() - 1;\n\n      const initPositionTx = await dlmm.createEmptyPosition({\n        positionPubKey: extendedPositionKeypair0.publicKey,\n        minBinId,\n        maxBinId,\n        user: keypair.publicKey,\n      });\n\n      await sendAndConfirmTransaction(connection, initPositionTx, [\n        extendedPositionKeypair0,\n        keypair,\n      ]);\n\n      const lengthToIncrease = new BN(extendedMaxBinId - maxBinId);\n\n      const beforePositionRental = await connection\n        .getAccountInfo(extendedPositionKeypair0.publicKey)\n        .then((account) =>\n          new Decimal(account.lamports).div(new Decimal(LAMPORTS_PER_SOL)),\n        );\n\n      const { positionExtendCost } = await dlmm.quoteExtendPosition(\n        new BN(minBinId),\n        new BN(maxBinId),\n        lengthToIncrease,\n      );\n\n      const extendPositionTxs = await dlmm.increasePositionLength(\n        extendedPositionKeypair0.publicKey,\n        ResizeSide.Upper,\n        lengthToIncrease,\n        keypair.publicKey,\n        true,\n      );\n\n      await Promise.all(\n        extendPositionTxs.map((tx) =>\n          sendAndConfirmTransaction(connection, tx, [keypair]),\n        ),\n      );\n\n      const afterPositionRental = await connection\n        .getAccountInfo(extendedPositionKeypair0.publicKey)\n        .then((account) =>\n          new Decimal(account.lamports).div(new Decimal(LAMPORTS_PER_SOL)),\n        );\n\n      const rentalCost = afterPositionRental.sub(beforePositionRental);\n      expect(rentalCost.toString()).toBe(positionExtendCost.toString());\n    });\n  });\n\n  const generateSwapFees = async () => {\n    const dlmm = await DLMM.create(connection, pairKey, opt);\n\n    // Generate some swap fees\n    const inAmount = new BN(1);\n    for (const [inToken, outToken] of [\n      [dlmm.tokenX, dlmm.tokenY],\n      [dlmm.tokenY, dlmm.tokenX],\n    ]) {\n      const binArraysPubkey = await dlmm\n        .getBinArrayForSwap(inToken.publicKey.equals(dlmm.tokenX.publicKey), 3)\n        .then((b) => b.map((b) => b.publicKey));\n\n      const swapTx = await dlmm.swap({\n        inToken: inToken.publicKey,\n        outToken: outToken.publicKey,\n        inAmount: inAmount.mul(new BN(10 ** inToken.mint.decimals)),\n        minOutAmount: new BN(0),\n        user: keypair.publicKey,\n        lbPair: pairKey,\n        binArraysPubkey,\n      });\n\n      await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n      await dlmm.refetchStates();\n    }\n  };\n\n  const assertUserTokenBalanceWithDelta = (\n    beforeAccount: AccountInfo<Buffer>,\n    afterAccount: AccountInfo<Buffer>,\n    expectedAmount: BN,\n    allowedLamportLoss?: number,\n  ) => {\n    const before = unpackAccount(\n      PublicKey.default,\n      beforeAccount,\n      beforeAccount.owner,\n    );\n\n    const after = unpackAccount(\n      PublicKey.default,\n      afterAccount,\n      afterAccount.owner,\n    );\n\n    const delta =\n      before.amount > after.amount\n        ? before.amount - after.amount\n        : after.amount - before.amount;\n\n    const deltaBn = new BN(delta.toString());\n    if (allowedLamportLoss) {\n      const diff = expectedAmount.sub(deltaBn);\n      expect(diff.lt(new BN(allowedLamportLoss))).toBeTruthy();\n    } else {\n      expect(deltaBn.toString()).toBe(expectedAmount.toString());\n    }\n  };\n\n  describe(\"Non extended position\", () => {\n    afterAll(async () => {\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n\n      const positions = await Promise.all(\n        [nonExtendedPositionKeypair0, nonExtendedPositionKeypair1].map(\n          (positionKeypairs) => {\n            return dlmm.getPosition(positionKeypairs.publicKey).catch((e) => {\n              // console.error(e);\n              return null;\n            });\n          },\n        ),\n      );\n\n      const nonEmptyPositions = positions.filter(Boolean).filter((position) => {\n        const amountX = new BN(position.positionData.totalXAmount.toString());\n        const amountY = new BN(position.positionData.totalYAmount.toString());\n        return !amountX.isZero() || !amountY.isZero();\n      });\n\n      const withdrawAll = nonEmptyPositions.map((position) => {\n        return dlmm.removeLiquidity({\n          user: position.positionData.owner,\n          position: position.publicKey,\n          fromBinId: position.positionData.lowerBinId,\n          toBinId: position.positionData.upperBinId,\n          bps: new BN(BASIS_POINT_MAX),\n          shouldClaimAndClose: false,\n          skipUnwrapSOL: true,\n        });\n      });\n\n      const withdrawAllTx = await Promise.all(withdrawAll);\n\n      await Promise.all(\n        withdrawAllTx.flat().map((tx) => {\n          return sendAndConfirmTransaction(connection, tx, [keypair]);\n        }),\n      );\n    });\n\n    describe(\"Add liquidity\", () => {\n      it(\"Add liquidity by strategy\", async () => {\n        const totalXAmount = new BN(5).mul(new BN(10 ** btcDecimal));\n        const totalYAmount = new BN(5).mul(new BN(10 ** solDecimal));\n\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        let position = await dlmm.getPosition(\n          nonExtendedPositionKeypair0.publicKey,\n        );\n\n        const activeBinInfo = await dlmm.getActiveBin();\n\n        const computedInBinAmount = toAmountsBothSideByStrategy(\n          dlmm.lbPair.activeId,\n          dlmm.lbPair.binStep,\n          position.positionData.lowerBinId,\n          position.positionData.upperBinId,\n          totalXAmount,\n          totalYAmount,\n          activeBinInfo.xAmount,\n          activeBinInfo.yAmount,\n          StrategyType.Spot,\n          dlmm.tokenX.mint,\n          dlmm.tokenY.mint,\n          dlmm.clock,\n        );\n\n        const addLiquidityTx = await dlmm.addLiquidityByStrategy({\n          positionPubKey: nonExtendedPositionKeypair0.publicKey,\n          totalXAmount,\n          totalYAmount,\n          user: keypair.publicKey,\n          strategy: {\n            strategyType: StrategyType.Spot,\n            minBinId: position.positionData.lowerBinId,\n            maxBinId: position.positionData.upperBinId,\n          },\n          slippage: 0,\n        });\n\n        const [beforeReserveXAccount, beforeReserveYAccount] =\n          await connection.getMultipleAccountsInfo([\n            dlmm.tokenX.reserve,\n            dlmm.tokenY.reserve,\n          ]);\n\n        await sendAndConfirmTransaction(connection, addLiquidityTx, [keypair]);\n\n        position = await dlmm.getPosition(\n          nonExtendedPositionKeypair0.publicKey,\n        );\n\n        const [afterReserveXAccount, afterReserveYAccount] =\n          await connection.getMultipleAccountsInfo([\n            dlmm.tokenX.reserve,\n            dlmm.tokenY.reserve,\n          ]);\n\n        const [computedInAmountX, computedInAmountY] =\n          computedInBinAmount.reduce(\n            ([totalXAmount, totalYAmount], { amountX, amountY }) => {\n              return [totalXAmount.add(amountX), totalYAmount.add(amountY)];\n            },\n            [new BN(0), new BN(0)],\n          );\n\n        expect(computedInAmountX.lte(totalXAmount)).toBeTruthy();\n        expect(computedInAmountY.lte(totalYAmount)).toBeTruthy();\n\n        const beforeReserveX = unpackAccount(\n          dlmm.tokenX.reserve,\n          beforeReserveXAccount,\n          beforeReserveXAccount.owner,\n        );\n\n        const beforeReserveY = unpackAccount(\n          dlmm.tokenY.reserve,\n          beforeReserveYAccount,\n          beforeReserveYAccount.owner,\n        );\n\n        const afterReserveX = unpackAccount(\n          dlmm.tokenX.reserve,\n          afterReserveXAccount,\n          afterReserveXAccount.owner,\n        );\n\n        const afterReserveY = unpackAccount(\n          dlmm.tokenY.reserve,\n          afterReserveYAccount,\n          afterReserveYAccount.owner,\n        );\n\n        const reserveXReceivedAmount =\n          afterReserveX.amount - beforeReserveX.amount;\n\n        const reserveYReceivedAmount =\n          afterReserveY.amount - beforeReserveY.amount;\n\n        // There will be some loss due to:\n        // 1. SDK distribute amounts based on strategy (will have loss where total amount in bin <= deposit amount)\n        // 2. Chunk the amounts into smaller bin range\n        // 3. For each chunk, sum the amounts as deposit amount for the chunk\n        // Due to amount feed into step 3 have loss (step 1), the deposit amount passed into the program will be lesser\n        let diffX = computedInAmountX.sub(\n          new BN(reserveXReceivedAmount.toString()),\n        );\n\n        let diffY = computedInAmountY.sub(\n          new BN(reserveYReceivedAmount.toString()),\n        );\n\n        expect(diffX.toNumber()).toBeLessThan(MAX_ALLOWED_LAMPORT_LOSS);\n        expect(diffY.toNumber()).toBeLessThan(MAX_ALLOWED_LAMPORT_LOSS);\n\n        const positionXAmount = new BN(position.positionData.totalXAmount);\n        const positionYAmount = new BN(position.positionData.totalYAmount);\n\n        diffX = computedInAmountX.sub(positionXAmount);\n        diffY = computedInAmountY.sub(positionYAmount);\n\n        expect(diffX.toNumber()).toBeLessThan(MAX_ALLOWED_LAMPORT_LOSS);\n        expect(diffY.toNumber()).toBeLessThan(MAX_ALLOWED_LAMPORT_LOSS);\n\n        expect(positionXAmount.toString()).toBe(\n          reserveXReceivedAmount.toString(),\n        );\n        expect(positionYAmount.toString()).toBe(\n          reserveYReceivedAmount.toString(),\n        );\n      });\n\n      it(\"Initialize position and add liquidity by strategy\", async () => {\n        const totalXAmount = new BN(5).mul(new BN(10 ** btcDecimal));\n        const totalYAmount = new BN(5).mul(new BN(10 ** solDecimal));\n\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        const minBinId = dlmm.lbPair.activeId - 30;\n        const maxBinId = dlmm.lbPair.activeId + 30;\n\n        const activeBinInfo = await dlmm.getActiveBin();\n\n        const computedInBinAmount = toAmountsBothSideByStrategy(\n          dlmm.lbPair.activeId,\n          dlmm.lbPair.binStep,\n          minBinId,\n          maxBinId,\n          totalXAmount,\n          totalYAmount,\n          activeBinInfo.xAmount,\n          activeBinInfo.yAmount,\n          StrategyType.Spot,\n          dlmm.tokenX.mint,\n          dlmm.tokenY.mint,\n          dlmm.clock,\n        );\n\n        const initAndAddLiquidityTx =\n          await dlmm.initializePositionAndAddLiquidityByStrategy({\n            positionPubKey: nonExtendedPositionKeypair1.publicKey,\n            totalXAmount,\n            totalYAmount,\n            strategy: {\n              strategyType: StrategyType.Spot,\n              minBinId,\n              maxBinId,\n            },\n            slippage: 0,\n            user: keypair.publicKey,\n          });\n\n        const [beforeReserveXAccount, beforeReserveYAccount] =\n          await connection.getMultipleAccountsInfo([\n            dlmm.tokenX.reserve,\n            dlmm.tokenY.reserve,\n          ]);\n\n        await sendAndConfirmTransaction(connection, initAndAddLiquidityTx, [\n          keypair,\n          nonExtendedPositionKeypair1,\n        ]);\n\n        const [afterReserveXAccount, afterReserveYAccount] =\n          await connection.getMultipleAccountsInfo([\n            dlmm.tokenX.reserve,\n            dlmm.tokenY.reserve,\n          ]);\n\n        await dlmm.refetchStates();\n\n        const position = await dlmm.getPosition(\n          nonExtendedPositionKeypair1.publicKey,\n        );\n        expect(position.positionData.lowerBinId).toBe(minBinId);\n        expect(position.positionData.upperBinId).toBe(maxBinId);\n\n        const [computedInAmountX, computedInAmountY] =\n          computedInBinAmount.reduce(\n            ([totalXAmount, totalYAmount], { amountX, amountY }) => {\n              return [totalXAmount.add(amountX), totalYAmount.add(amountY)];\n            },\n            [new BN(0), new BN(0)],\n          );\n\n        expect(computedInAmountX.lte(totalXAmount)).toBeTruthy();\n        expect(computedInAmountY.lte(totalYAmount)).toBeTruthy();\n\n        const beforeReserveX = unpackAccount(\n          dlmm.tokenX.reserve,\n          beforeReserveXAccount,\n          beforeReserveXAccount.owner,\n        );\n\n        const beforeReserveY = unpackAccount(\n          dlmm.tokenY.reserve,\n          beforeReserveYAccount,\n          beforeReserveYAccount.owner,\n        );\n\n        const afterReserveX = unpackAccount(\n          dlmm.tokenX.reserve,\n          afterReserveXAccount,\n          afterReserveXAccount.owner,\n        );\n\n        const afterReserveY = unpackAccount(\n          dlmm.tokenY.reserve,\n          afterReserveYAccount,\n          afterReserveYAccount.owner,\n        );\n\n        const reserveXReceivedAmount =\n          afterReserveX.amount - beforeReserveX.amount;\n\n        const reserveYReceivedAmount =\n          afterReserveY.amount - beforeReserveY.amount;\n\n        expect(new BN(reserveXReceivedAmount.toString()).toString()).toBe(\n          computedInAmountX.toString(),\n        );\n\n        expect(new BN(reserveYReceivedAmount.toString()).toString()).toBe(\n          computedInAmountY.toString(),\n        );\n\n        const positionXAmount = new BN(position.positionData.totalXAmount);\n        const positionYAmount = new BN(position.positionData.totalYAmount);\n\n        const xDiff = computedInAmountX.sub(positionXAmount);\n        const yDiff = computedInAmountY.sub(positionYAmount);\n\n        expect(xDiff.lte(new BN(1))).toBeTruthy();\n        expect(yDiff.lte(new BN(1))).toBeTruthy();\n\n        expect(positionXAmount.add(xDiff).toString()).toBe(\n          computedInAmountX.toString(),\n        );\n\n        expect(positionYAmount.add(yDiff).toString()).toBe(\n          computedInAmountY.toString(),\n        );\n      });\n    });\n\n    describe(\"Swap\", () => {\n      it(\"SwapExactIn quote X into Y and execute swap\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const inAmount = new BN(1).mul(new BN(10 ** btcDecimal));\n        const swapForY = true;\n\n        const bidBinArrays = await dlmm.getBinArrayForSwap(swapForY, 3);\n        const quoteResult = dlmm.swapQuote(\n          inAmount,\n          swapForY,\n          new BN(0),\n          bidBinArrays,\n          false,\n        );\n\n        const swapTx = await dlmm.swap({\n          inAmount,\n          inToken: dlmm.tokenX.publicKey,\n          outToken: dlmm.tokenY.publicKey,\n          minOutAmount: quoteResult.minOutAmount,\n          lbPair: pairKey,\n          user: keypair.publicKey,\n          binArraysPubkey: bidBinArrays.map((b) => b.publicKey),\n        });\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        const beforeUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n\n        const beforeUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const consumedXAmount = new BN(\n          (beforeUserX.amount - afterUserX.amount).toString(),\n        );\n        const receivedYAmount = new BN(\n          (afterUserY.amount - beforeUserY.amount).toString(),\n        );\n\n        expect(consumedXAmount.toString()).toBe(\n          quoteResult.consumedInAmount.toString(),\n        );\n        expect(receivedYAmount.toString()).toBe(\n          quoteResult.outAmount.toString(),\n        );\n      });\n\n      it(\"SwapExactOut quote Y into X and execute swap\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const outAmount = new BN(1).mul(new BN(10 ** btcDecimal));\n        const swapForY = false;\n\n        const askBinArrays = await dlmm.getBinArrayForSwap(swapForY, 3);\n        const quoteResult = dlmm.swapQuoteExactOut(\n          outAmount,\n          swapForY,\n          new BN(0),\n          askBinArrays,\n        );\n\n        console.log(\n          \"quote exact out\",\n          quoteResult.inAmount.toString(),\n          quoteResult.outAmount.toString(),\n        );\n\n        const swapTx = await dlmm.swapExactOut({\n          outAmount,\n          inToken: dlmm.tokenY.publicKey,\n          outToken: dlmm.tokenX.publicKey,\n          maxInAmount: quoteResult.maxInAmount,\n          lbPair: pairKey,\n          user: keypair.publicKey,\n          binArraysPubkey: askBinArrays.map((b) => b.publicKey),\n        });\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        const beforeUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n\n        const beforeUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const consumedYAmount = new BN(\n          (beforeUserY.amount - afterUserY.amount).toString(),\n        );\n        const receivedXAmount = new BN(\n          (afterUserX.amount - beforeUserX.amount).toString(),\n        );\n\n        expect(consumedYAmount.toString()).toBe(\n          quoteResult.inAmount.toString(),\n        );\n        expect(receivedXAmount.toString()).toBe(\n          quoteResult.outAmount.toString(),\n        );\n      });\n\n      it(\"SwapExactOut quote X into Y and execute swap\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const outAmount = new BN(1).mul(new BN(10 ** solDecimal));\n        const swapForY = true;\n\n        const bidBinArrays = await dlmm.getBinArrayForSwap(swapForY, 3);\n        const quoteResult = dlmm.swapQuoteExactOut(\n          outAmount,\n          swapForY,\n          new BN(0),\n          bidBinArrays,\n        );\n\n        console.log(\n          \"Quote in and out amount\",\n          quoteResult.inAmount.toString(),\n          quoteResult.outAmount.toString(),\n        );\n\n        const swapTx = await dlmm.swapExactOut({\n          outAmount,\n          inToken: dlmm.tokenX.publicKey,\n          outToken: dlmm.tokenY.publicKey,\n          maxInAmount: quoteResult.maxInAmount,\n          lbPair: pairKey,\n          user: keypair.publicKey,\n          binArraysPubkey: bidBinArrays.map((b) => b.publicKey),\n        });\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        const beforeUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n\n        const beforeUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const consumedXAmount = new BN(\n          (beforeUserX.amount - afterUserX.amount).toString(),\n        );\n        const receivedYAmount = new BN(\n          (afterUserY.amount - beforeUserY.amount).toString(),\n        );\n\n        expect(consumedXAmount.toString()).toBe(\n          quoteResult.inAmount.toString(),\n        );\n        expect(receivedYAmount.toString()).toBe(\n          quoteResult.outAmount.toString(),\n        );\n      });\n\n      it(\"SwapExactIn quote Y into X and execute swap\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const inAmount = new BN(1).mul(new BN(10 ** solDecimal));\n        const swapForY = false;\n\n        const askBinArrays = await dlmm.getBinArrayForSwap(swapForY, 3);\n        const quoteResult = dlmm.swapQuote(\n          inAmount,\n          swapForY,\n          new BN(0),\n          askBinArrays,\n          false,\n        );\n\n        const swapTx = await dlmm.swap({\n          inAmount,\n          inToken: dlmm.tokenY.publicKey,\n          outToken: dlmm.tokenX.publicKey,\n          minOutAmount: quoteResult.minOutAmount,\n          lbPair: pairKey,\n          user: keypair.publicKey,\n          binArraysPubkey: askBinArrays.map((b) => b.publicKey),\n        });\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        await sendAndConfirmTransaction(connection, swapTx, [keypair]);\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([\n            getAssociatedTokenAddressSync(\n              dlmm.tokenX.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenX.owner,\n            ),\n            getAssociatedTokenAddressSync(\n              dlmm.tokenY.publicKey,\n              keypair.publicKey,\n              true,\n              dlmm.tokenY.owner,\n            ),\n          ]);\n\n        const beforeUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n\n        const beforeUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          dlmm.tokenX.publicKey,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          dlmm.tokenY.publicKey,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const consumedYAmount = new BN(\n          (beforeUserY.amount - afterUserY.amount).toString(),\n        );\n        const receivedXAmount = new BN(\n          (afterUserX.amount - beforeUserX.amount).toString(),\n        );\n\n        expect(consumedYAmount.toString()).toBe(\n          quoteResult.consumedInAmount.toString(),\n        );\n        expect(receivedXAmount.toString()).toBe(\n          quoteResult.outAmount.toString(),\n        );\n      });\n    });\n\n    describe(\"Claim fees and rewards\", () => {\n      let userXAta: PublicKey, userYAta: PublicKey, userRewardAta: PublicKey;\n\n      beforeEach(async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        await generateSwapFees();\n\n        userXAta = getAssociatedTokenAddressSync(\n          dlmm.tokenX.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n\n        userYAta = getAssociatedTokenAddressSync(\n          dlmm.tokenY.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        userRewardAta = getAssociatedTokenAddressSync(\n          dlmm.rewards[0].publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.rewards[0].owner,\n        );\n      });\n\n      describe(\"Claim swap fee\", () => {\n        it(\"Claim all swap fees\", async () => {\n          const dlmm = await DLMM.create(connection, pairKey, opt);\n\n          const [beforeUserXAccount, beforeUserYAccount] =\n            await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n          const [beforeP0, beforeP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          const totalClaimableFeeX =\n            beforeP0.positionData.feeXExcludeTransferFee.add(\n              beforeP1.positionData.feeXExcludeTransferFee,\n            );\n\n          const totalClaimableFeeY =\n            beforeP0.positionData.feeYExcludeTransferFee.add(\n              beforeP1.positionData.feeYExcludeTransferFee,\n            );\n\n          const claimFeeTxs = await dlmm.claimAllSwapFee({\n            owner: keypair.publicKey,\n            positions: [beforeP0, beforeP1],\n          });\n\n          expect(claimFeeTxs.length).toBeGreaterThanOrEqual(1);\n\n          await Promise.all(\n            claimFeeTxs.map((tx) =>\n              sendAndConfirmTransaction(connection, tx, [keypair]),\n            ),\n          );\n\n          const [afterUserXAccount, afterUserYAccount] =\n            await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n          assertUserTokenBalanceWithDelta(\n            beforeUserXAccount,\n            afterUserXAccount,\n            totalClaimableFeeX,\n          );\n\n          assertUserTokenBalanceWithDelta(\n            beforeUserYAccount,\n            afterUserYAccount,\n            totalClaimableFeeY,\n          );\n\n          const [afterP0, afterP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          expect(afterP0.positionData.feeX.isZero()).toBeTruthy();\n          expect(afterP0.positionData.feeY.isZero()).toBeTruthy();\n\n          expect(afterP1.positionData.feeX.isZero()).toBeTruthy();\n          expect(afterP1.positionData.feeY.isZero()).toBeTruthy();\n        });\n\n        it(\"Claim swap fee\", async () => {\n          const dlmm = await DLMM.create(connection, pairKey, opt);\n\n          for (const positionKey of [\n            nonExtendedPositionKeypair0.publicKey,\n            nonExtendedPositionKeypair1.publicKey,\n          ]) {\n            const beforePosition = await dlmm.getPosition(positionKey);\n\n            const [beforeUserXAccount, beforeUserYAccount] =\n              await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n            const claimFeeTxs = await dlmm.claimSwapFee({\n              owner: keypair.publicKey,\n              position: beforePosition,\n            });\n\n            await Promise.all(\n              claimFeeTxs.map((tx) =>\n                sendAndConfirmTransaction(connection, tx, [keypair]),\n              ),\n            );\n\n            const [afterUserXAccount, afterUserYAccount] =\n              await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n            assertUserTokenBalanceWithDelta(\n              beforeUserXAccount,\n              afterUserXAccount,\n              beforePosition.positionData.feeXExcludeTransferFee,\n            );\n\n            assertUserTokenBalanceWithDelta(\n              beforeUserYAccount,\n              afterUserYAccount,\n              beforePosition.positionData.feeYExcludeTransferFee,\n            );\n\n            const afterPosition = await dlmm.getPosition(positionKey);\n            expect(afterPosition.positionData.feeX.isZero()).toBeTruthy();\n            expect(afterPosition.positionData.feeY.isZero()).toBeTruthy();\n          }\n        });\n      });\n\n      describe(\"Claim rewards\", () => {\n        beforeEach(async () => {\n          // Generate some fees\n          await new Promise((res) => setTimeout(res, 1000));\n        });\n\n        it(\"Claim reward\", async () => {\n          for (const positionKey of [\n            nonExtendedPositionKeypair0.publicKey,\n            nonExtendedPositionKeypair1.publicKey,\n          ]) {\n            const dlmm = await DLMM.create(connection, pairKey, opt);\n            const position = await dlmm.getPosition(positionKey);\n\n            const beforeUserRewardAccount =\n              await connection.getAccountInfo(userRewardAta);\n\n            const claimTxs = await dlmm.claimLMReward({\n              owner: keypair.publicKey,\n              position,\n            });\n\n            await Promise.all(\n              claimTxs.map((tx) =>\n                sendAndConfirmTransaction(connection, tx, [keypair]),\n              ),\n            );\n\n            const afterUserRewardAccount =\n              await connection.getAccountInfo(userRewardAta);\n\n            const beforeUserReward = unpackAccount(\n              userRewardAta,\n              beforeUserRewardAccount,\n              beforeUserRewardAccount.owner,\n            );\n\n            const afterUserReward = unpackAccount(\n              userRewardAta,\n              afterUserRewardAccount,\n              afterUserRewardAccount.owner,\n            );\n\n            const claimedReward = new BN(\n              (afterUserReward.amount - beforeUserReward.amount).toString(),\n            );\n\n            expect(\n              claimedReward.gte(\n                position.positionData.rewardOneExcludeTransferFee,\n              ),\n            ).toBeTruthy();\n          }\n        });\n\n        it(\"Claim all rewards\", async () => {\n          const dlmm = await DLMM.create(connection, pairKey, opt);\n\n          const beforeUserRewardAccount =\n            await connection.getAccountInfo(userRewardAta);\n\n          const [beforeP0, beforeP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          const totalClaimableReward0 =\n            beforeP0.positionData.rewardOneExcludeTransferFee.add(\n              beforeP1.positionData.rewardOneExcludeTransferFee,\n            );\n\n          const claimTxs = await dlmm.claimAllLMRewards({\n            owner: keypair.publicKey,\n            positions: [beforeP0, beforeP1],\n          });\n\n          expect(claimTxs.length).toBeGreaterThanOrEqual(1);\n\n          await Promise.all(\n            claimTxs.map((tx) =>\n              sendAndConfirmTransaction(connection, tx, [keypair]),\n            ),\n          );\n\n          const afterUserRewardAccount =\n            await connection.getAccountInfo(userRewardAta);\n\n          const beforeUserReward = unpackAccount(\n            userRewardAta,\n            beforeUserRewardAccount,\n            beforeUserRewardAccount.owner,\n          );\n\n          const afterUserReward = unpackAccount(\n            userRewardAta,\n            afterUserRewardAccount,\n            afterUserRewardAccount.owner,\n          );\n\n          const claimedAmount = new BN(\n            (\n              BigInt(afterUserReward.amount) - BigInt(beforeUserReward.amount)\n            ).toString(),\n          );\n\n          expect(claimedAmount.gte(totalClaimableReward0)).toBeTruthy();\n\n          const [afterP0, afterP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          expect(\n            afterP0.positionData.rewardOneExcludeTransferFee.lt(\n              beforeP0.positionData.rewardOneExcludeTransferFee,\n            ),\n          ).toBeTruthy();\n          expect(\n            afterP1.positionData.rewardOneExcludeTransferFee.lt(\n              beforeP1.positionData.rewardOneExcludeTransferFee,\n            ),\n          ).toBeTruthy();\n        });\n      });\n\n      describe(\"Claim fees and rewards together\", () => {\n        beforeEach(async () => {\n          // Generate some fees\n          await new Promise((res) => setTimeout(res, 1000));\n        });\n\n        it(\"Claim fee and reward by position\", async () => {\n          for (const positionKey of [\n            nonExtendedPositionKeypair0.publicKey,\n            nonExtendedPositionKeypair1.publicKey,\n          ]) {\n            const dlmm = await DLMM.create(connection, pairKey, opt);\n            const beforePositionState = await dlmm.getPosition(positionKey);\n\n            const [\n              beforeUserRewardAccount,\n              beforeUserXAccount,\n              beforeUserYAccount,\n            ] = await connection.getMultipleAccountsInfo([\n              userRewardAta,\n              userXAta,\n              userYAta,\n            ]);\n\n            const claimTxs = await dlmm.claimAllRewardsByPosition({\n              position: beforePositionState,\n              owner: keypair.publicKey,\n            });\n\n            expect(claimTxs.length).toBeGreaterThanOrEqual(1);\n\n            await Promise.all(\n              claimTxs.map((tx) => {\n                return sendAndConfirmTransaction(connection, tx, [keypair]);\n              }),\n            );\n\n            const afterPositionState = await dlmm.getPosition(positionKey);\n            expect(afterPositionState.positionData.feeX.isZero()).toBeTruthy();\n            expect(afterPositionState.positionData.feeY.isZero()).toBeTruthy();\n\n            const [\n              afterUserRewardAccount,\n              afterUserXAccount,\n              afterUserYAccount,\n            ] = await connection.getMultipleAccountsInfo([\n              userRewardAta,\n              userXAta,\n              userYAta,\n            ]);\n\n            const beforeUserReward = unpackAccount(\n              userRewardAta,\n              beforeUserRewardAccount,\n              beforeUserRewardAccount.owner,\n            );\n\n            const afterUserReward = unpackAccount(\n              userRewardAta,\n              afterUserRewardAccount,\n              afterUserRewardAccount.owner,\n            );\n\n            const actualClaimedReward = new BN(\n              (afterUserReward.amount - beforeUserReward.amount).toString(),\n            );\n\n            expect(\n              actualClaimedReward.gte(\n                beforePositionState.positionData.rewardOneExcludeTransferFee,\n              ),\n            ).toBeTruthy();\n\n            const beforeUserX = unpackAccount(\n              userXAta,\n              beforeUserXAccount,\n              beforeUserXAccount.owner,\n            );\n\n            const afterUserX = unpackAccount(\n              userXAta,\n              afterUserXAccount,\n              afterUserXAccount.owner,\n            );\n\n            const claimedFeeX = new BN(\n              (afterUserX.amount - beforeUserX.amount).toString(),\n            );\n\n            expect(claimedFeeX.toString()).toBe(\n              beforePositionState.positionData.feeXExcludeTransferFee.toString(),\n            );\n\n            const beforeUserY = unpackAccount(\n              userYAta,\n              beforeUserYAccount,\n              beforeUserYAccount.owner,\n            );\n\n            const afterUserY = unpackAccount(\n              userYAta,\n              afterUserYAccount,\n              afterUserYAccount.owner,\n            );\n\n            const claimedFeeY = new BN(\n              (afterUserY.amount - beforeUserY.amount).toString(),\n            );\n\n            expect(claimedFeeY.toString()).toBe(\n              beforePositionState.positionData.feeYExcludeTransferFee.toString(),\n            );\n          }\n        });\n\n        it(\"Claim all positions fees and rewards\", async () => {\n          const dlmm = await DLMM.create(connection, pairKey, opt);\n\n          const [beforeP0, beforeP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          const [\n            beforeUserRewardAccount,\n            beforeUserXAccount,\n            beforeUserYAccount,\n          ] = await connection.getMultipleAccountsInfo([\n            userRewardAta,\n            userXAta,\n            userYAta,\n          ]);\n\n          const totalClaimableFeeX =\n            beforeP0.positionData.feeXExcludeTransferFee.add(\n              beforeP1.positionData.feeXExcludeTransferFee,\n            );\n\n          const totalClaimableFeeY =\n            beforeP0.positionData.feeYExcludeTransferFee.add(\n              beforeP1.positionData.feeYExcludeTransferFee,\n            );\n\n          const totalClaimableReward =\n            beforeP0.positionData.rewardOneExcludeTransferFee.add(\n              beforeP1.positionData.rewardOneExcludeTransferFee,\n            );\n\n          const claimTxs = await dlmm.claimAllRewards({\n            owner: keypair.publicKey,\n            positions: [beforeP0, beforeP1],\n          });\n\n          expect(claimTxs.length).toBeGreaterThanOrEqual(1);\n\n          await Promise.all(\n            claimTxs.map((tx) => {\n              return sendAndConfirmTransaction(connection, tx, [keypair]);\n            }),\n          );\n\n          const [afterUserRewardAccount, afterUserXAccount, afterUserYAccount] =\n            await connection.getMultipleAccountsInfo([\n              userRewardAta,\n              userXAta,\n              userYAta,\n            ]);\n\n          const [afterP0, afterP1] = await Promise.all([\n            dlmm.getPosition(nonExtendedPositionKeypair0.publicKey),\n            dlmm.getPosition(nonExtendedPositionKeypair1.publicKey),\n          ]);\n\n          expect(afterP0.positionData.feeX.isZero()).toBeTruthy();\n          expect(afterP0.positionData.feeY.isZero()).toBeTruthy();\n\n          expect(afterP1.positionData.feeX.isZero()).toBeTruthy();\n          expect(afterP1.positionData.feeY.isZero()).toBeTruthy();\n\n          const beforeUserReward = unpackAccount(\n            userRewardAta,\n            beforeUserRewardAccount,\n            beforeUserRewardAccount.owner,\n          );\n\n          const afterUserReward = unpackAccount(\n            userRewardAta,\n            afterUserRewardAccount,\n            afterUserRewardAccount.owner,\n          );\n\n          const actualClaimedReward = new BN(\n            (afterUserReward.amount - beforeUserReward.amount).toString(),\n          );\n\n          expect(actualClaimedReward.gte(totalClaimableReward)).toBeTruthy();\n\n          const beforeUserX = unpackAccount(\n            userXAta,\n            beforeUserXAccount,\n            beforeUserXAccount.owner,\n          );\n\n          const afterUserX = unpackAccount(\n            userXAta,\n            afterUserXAccount,\n            afterUserXAccount.owner,\n          );\n\n          const claimedFeeX = new BN(\n            (afterUserX.amount - beforeUserX.amount).toString(),\n          );\n\n          expect(claimedFeeX.toString()).toBe(totalClaimableFeeX.toString());\n\n          const beforeUserY = unpackAccount(\n            userYAta,\n            beforeUserYAccount,\n            beforeUserYAccount.owner,\n          );\n\n          const afterUserY = unpackAccount(\n            userYAta,\n            afterUserYAccount,\n            afterUserYAccount.owner,\n          );\n\n          const claimedFeeY = new BN(\n            (afterUserY.amount - beforeUserY.amount).toString(),\n          );\n\n          expect(claimedFeeY.toString()).toBe(totalClaimableFeeY.toString());\n        });\n      });\n    });\n\n    describe(\"Remove liquidity\", () => {\n      beforeAll(async () => {\n        await generateSwapFees();\n        // Generate some reward\n        await new Promise((res) => setTimeout(res, 1000));\n      });\n\n      it(\"Remove liquidity without claim and close successfully\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        const beforePosition = await dlmm.getPosition(\n          nonExtendedPositionKeypair0.publicKey,\n        );\n\n        const fromBinId = dlmm.lbPair.activeId - 1;\n        const toBinId = dlmm.lbPair.activeId + 1;\n\n        let expectedAmountX = new BN(0);\n        let expectedAmountY = new BN(0);\n\n        const userXAta = getAssociatedTokenAddressSync(\n          dlmm.tokenX.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n\n        const userYAta = getAssociatedTokenAddressSync(\n          dlmm.tokenY.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n        for (const binData of beforePosition.positionData.positionBinData) {\n          if (binData.binId >= fromBinId && binData.binId <= toBinId) {\n            expect(new BN(binData.positionLiquidity).isZero()).toBeFalsy();\n            expectedAmountX = expectedAmountX.add(\n              new BN(binData.positionXAmount),\n            );\n\n            expectedAmountY = expectedAmountY.add(\n              new BN(binData.positionYAmount),\n            );\n          }\n        }\n\n        const expectedAmountXExcludeTranferFee =\n          calculateTransferFeeExcludedAmount(\n            expectedAmountX,\n            dlmm.tokenX.mint,\n            dlmm.clock.epoch.toNumber(),\n          ).amount;\n\n        const expectedAmountYExcludeTranferFee =\n          calculateTransferFeeExcludedAmount(\n            expectedAmountY,\n            dlmm.tokenY.mint,\n            dlmm.clock.epoch.toNumber(),\n          ).amount;\n\n        const removeLiquidityTxs = await dlmm.removeLiquidity({\n          position: nonExtendedPositionKeypair0.publicKey,\n          fromBinId,\n          toBinId,\n          bps: new BN(BASIS_POINT_MAX),\n          user: keypair.publicKey,\n          shouldClaimAndClose: false,\n          skipUnwrapSOL: true,\n        });\n\n        await Promise.all(\n          removeLiquidityTxs.map((tx) =>\n            sendAndConfirmTransaction(connection, tx, [keypair]),\n          ),\n        );\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n        const beforeUserX = unpackAccount(\n          userXAta,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n        const beforeUserY = unpackAccount(\n          userYAta,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          userXAta,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          userYAta,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const amountX = new BN(\n          (afterUserX.amount - beforeUserX.amount).toString(),\n        );\n        const amountY = new BN(\n          (afterUserY.amount - beforeUserY.amount).toString(),\n        );\n\n        expect(amountX.toString()).toBe(\n          expectedAmountXExcludeTranferFee.toString(),\n        );\n        expect(amountY.toString()).toBe(\n          expectedAmountYExcludeTranferFee.toString(),\n        );\n      });\n\n      it(\"Remove liquidity with claim and close successfully\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        const beforePosition = await dlmm.getPosition(\n          nonExtendedPositionKeypair0.publicKey,\n        );\n\n        const fromBinId = beforePosition.positionData.lowerBinId;\n        const toBinId = beforePosition.positionData.upperBinId;\n\n        let expectedAmountX = new BN(0);\n        let expectedAmountY = new BN(0);\n\n        const userXAta = getAssociatedTokenAddressSync(\n          dlmm.tokenX.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n\n        const userYAta = getAssociatedTokenAddressSync(\n          dlmm.tokenY.publicKey,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        const [beforeUserXAccount, beforeUserYAccount] =\n          await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n        for (const binData of beforePosition.positionData.positionBinData) {\n          if (binData.binId >= fromBinId && binData.binId <= toBinId) {\n            expectedAmountX = expectedAmountX\n              .add(new BN(binData.positionXAmount))\n              .add(new BN(binData.positionFeeXAmount));\n\n            expectedAmountY = expectedAmountY\n              .add(new BN(binData.positionYAmount))\n              .add(new BN(binData.positionFeeYAmount));\n          }\n        }\n\n        const expectedAmountXExcludeTranferFee =\n          calculateTransferFeeExcludedAmount(\n            expectedAmountX,\n            dlmm.tokenX.mint,\n            dlmm.clock.epoch.toNumber(),\n          ).amount;\n\n        const expectedAmountYExcludeTranferFee =\n          calculateTransferFeeExcludedAmount(\n            expectedAmountY,\n            dlmm.tokenY.mint,\n            dlmm.clock.epoch.toNumber(),\n          ).amount;\n\n        const removeLiquidityTxs = (await dlmm.removeLiquidity({\n          position: nonExtendedPositionKeypair0.publicKey,\n          fromBinId,\n          toBinId,\n          bps: new BN(BASIS_POINT_MAX),\n          user: keypair.publicKey,\n          shouldClaimAndClose: true,\n          skipUnwrapSOL: true,\n        })) as Transaction[];\n\n        expect(Array.isArray(removeLiquidityTxs)).toBeTruthy();\n        expect(removeLiquidityTxs.length).toBeGreaterThanOrEqual(1);\n\n        for (const tx of removeLiquidityTxs) {\n          await sendAndConfirmTransaction(connection, tx, [keypair]);\n        }\n\n        const [afterUserXAccount, afterUserYAccount] =\n          await connection.getMultipleAccountsInfo([userXAta, userYAta]);\n\n        const beforeUserX = unpackAccount(\n          userXAta,\n          beforeUserXAccount,\n          beforeUserXAccount.owner,\n        );\n        const beforeUserY = unpackAccount(\n          userYAta,\n          beforeUserYAccount,\n          beforeUserYAccount.owner,\n        );\n\n        const afterUserX = unpackAccount(\n          userXAta,\n          afterUserXAccount,\n          afterUserXAccount.owner,\n        );\n\n        const afterUserY = unpackAccount(\n          userYAta,\n          afterUserYAccount,\n          afterUserYAccount.owner,\n        );\n\n        const amountX = new BN(\n          (afterUserX.amount - beforeUserX.amount).toString(),\n        );\n        const amountY = new BN(\n          (afterUserY.amount - beforeUserY.amount).toString(),\n        );\n\n        // LTE due to multiple transfer fee round down precision loss\n        expect(amountX.lte(expectedAmountXExcludeTranferFee)).toBeTruthy();\n        expect(amountY.lte(expectedAmountYExcludeTranferFee)).toBeTruthy();\n\n        const positionAccount = await connection.getAccountInfo(\n          nonExtendedPositionKeypair0.publicKey,\n        );\n\n        expect(positionAccount).toBeNull();\n      });\n    });\n  });\n\n  describe(\"Extend / Shrink position\", () => {\n    describe(\"Extended position\", () => {\n      it(\"Increase from 1 to 1400 max length\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const sides = [ResizeSide.Lower, ResizeSide.Upper];\n\n        for (const side of sides) {\n          const positionKp = Keypair.generate();\n\n          const initPositionTx = await dlmm.createEmptyPosition({\n            positionPubKey: positionKp.publicKey,\n            minBinId: dlmm.lbPair.activeId,\n            maxBinId: dlmm.lbPair.activeId,\n            user: keypair.publicKey,\n          });\n\n          await sendAndConfirmTransaction(connection, initPositionTx, [\n            positionKp,\n            keypair,\n          ]);\n\n          const beforePositionState = await dlmm.getPosition(\n            positionKp.publicKey,\n          );\n\n          const width =\n            beforePositionState.positionData.upperBinId -\n            beforePositionState.positionData.lowerBinId +\n            1;\n\n          const expandPositionTxs = await dlmm.increasePositionLength(\n            positionKp.publicKey,\n            side,\n            POSITION_MAX_LENGTH.sub(new BN(width)),\n            keypair.publicKey,\n          );\n\n          await Promise.all(\n            expandPositionTxs.map((tx) => {\n              return sendAndConfirmTransaction(connection, tx, [keypair]);\n            }),\n          );\n\n          const afterPositionState = await dlmm.getPosition(\n            positionKp.publicKey,\n          );\n\n          const newWidth =\n            afterPositionState.positionData.upperBinId -\n            afterPositionState.positionData.lowerBinId +\n            1;\n\n          expect(newWidth).toBe(POSITION_MAX_LENGTH.toNumber());\n\n          switch (side) {\n            case ResizeSide.Lower: {\n              expect(afterPositionState.positionData.lowerBinId).toBeLessThan(\n                beforePositionState.positionData.lowerBinId,\n              );\n              break;\n            }\n            case ResizeSide.Upper: {\n              expect(\n                afterPositionState.positionData.upperBinId,\n              ).toBeGreaterThan(beforePositionState.positionData.upperBinId);\n              break;\n            }\n          }\n        }\n      });\n\n      it(\"Decrease from 1400 max length to 1\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n        const sides = [ResizeSide.Lower, ResizeSide.Upper];\n\n        for (const side of sides) {\n          const positionKp = Keypair.generate();\n\n          const initPositionTx = await dlmm.createEmptyPosition({\n            positionPubKey: positionKp.publicKey,\n            minBinId: dlmm.lbPair.activeId,\n            maxBinId: dlmm.lbPair.activeId,\n            user: keypair.publicKey,\n          });\n\n          await sendAndConfirmTransaction(connection, initPositionTx, [\n            positionKp,\n            keypair,\n          ]);\n\n          const beforePositionState = await dlmm.getPosition(\n            positionKp.publicKey,\n          );\n\n          const width =\n            beforePositionState.positionData.upperBinId -\n            beforePositionState.positionData.lowerBinId +\n            1;\n\n          const expandPositionTxs = await dlmm.increasePositionLength(\n            positionKp.publicKey,\n            side,\n            POSITION_MAX_LENGTH.sub(new BN(width)),\n            keypair.publicKey,\n          );\n\n          await Promise.all(\n            expandPositionTxs.map((tx) => {\n              return sendAndConfirmTransaction(connection, tx, [keypair]);\n            }),\n          );\n\n          let afterPositionState = await dlmm.getPosition(positionKp.publicKey);\n\n          let newWidth =\n            afterPositionState.positionData.upperBinId -\n            afterPositionState.positionData.lowerBinId +\n            1;\n\n          expect(newWidth).toBe(POSITION_MAX_LENGTH.toNumber());\n\n          const shrinkPositionTxs = await dlmm.decreasePositionLength(\n            positionKp.publicKey,\n            side,\n            POSITION_MAX_LENGTH,\n            true,\n          );\n\n          await Promise.all(\n            shrinkPositionTxs.map((tx) => {\n              return sendAndConfirmTransaction(connection, tx, [keypair]);\n            }),\n          );\n\n          afterPositionState = await dlmm.getPosition(positionKp.publicKey);\n          newWidth =\n            afterPositionState.positionData.upperBinId -\n            afterPositionState.positionData.lowerBinId +\n            1;\n\n          expect(newWidth).toBe(1);\n        }\n      });\n    });\n\n    describe(\"Initialize multiple extended position and add liquidity to strategy\", () => {\n      it(\"Initialize multiple extended position and add liquidity to strategy\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        console.log(\"🚀 ~ dlmm:\", dlmm.pubkey.toBase58());\n\n        const totalXAmount = new BN(1_000_000_000);\n        const totalYAmount = new BN(1_000_000_000);\n        const minBinId = dlmm.lbPair.activeId - 2000;\n        const maxBinId = dlmm.lbPair.activeId + 2000;\n\n        const userTokenX = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenXMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n        const userTokenY = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenYMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        const [beforeTokenX, beforeTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        const { instructionsByPositions } =\n          await dlmm.initializeMultiplePositionAndAddLiquidityByStrategy(\n            async (count) => {\n              const positionKeypairs = [];\n              for (let i = 0; i < count; i++) {\n                const positionKeypair = Keypair.generate();\n                positionKeypairs.push(positionKeypair);\n              }\n              return positionKeypairs;\n            },\n            totalXAmount,\n            totalYAmount,\n            {\n              minBinId,\n              maxBinId,\n              strategyType: StrategyType.Curve,\n            },\n            keypair.publicKey,\n            keypair.publicKey,\n            0,\n          );\n\n        const promises = [];\n\n        // Have to execute sequentially due to position auto resize\n        for (const {\n          positionKeypair,\n          initializePositionIx,\n          addLiquidityIxs,\n        } of instructionsByPositions) {\n          const latestBlockhashInfo = await connection.getLatestBlockhash();\n\n          const tx = new Transaction({\n            ...latestBlockhashInfo,\n          }).add(initializePositionIx);\n\n          tx.sign(keypair, positionKeypair);\n\n          const promise = connection\n            .sendRawTransaction(tx.serialize())\n            .then(async (sig) => {\n              await connection.confirmTransaction({\n                ...latestBlockhashInfo,\n                signature: sig,\n              });\n\n              console.log(\"Init position sig\", sig);\n            })\n            .then(async (_) => {\n              for (const addLiquidityIx of addLiquidityIxs) {\n                const latestBlockhashInfo =\n                  await connection.getLatestBlockhash();\n\n                const tx = new Transaction({\n                  ...latestBlockhashInfo,\n                }).add(...addLiquidityIx);\n\n                tx.sign(keypair);\n                const sig = await connection.sendRawTransaction(tx.serialize());\n                await connection.confirmTransaction({\n                  ...latestBlockhashInfo,\n                  signature: sig,\n                });\n                console.log(\"Add liq sig\", sig);\n              }\n            });\n\n          promises.push(promise);\n        }\n\n        await Promise.all(promises);\n        await logLbPairLiquidities(pairKey, dlmm.lbPair.binStep, dlmm.program);\n\n        const [afterTokenX, afterTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        const consumedTokenX = beforeTokenX.sub(afterTokenX);\n        const consumedTokenY = beforeTokenY.sub(afterTokenY);\n\n        // Due to transfer fee\n        expect(consumedTokenX.gte(totalXAmount)).toBeTruthy();\n        expect(consumedTokenY.lte(totalYAmount)).toBeTruthy();\n      });\n\n      it(\"Initialize multiple extended position and add liquidity to strategy 2\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        console.log(\"🚀 ~ dlmm:\", dlmm.pubkey.toBase58());\n\n        const [initALTIx, altAddress] =\n          AddressLookupTableProgram.createLookupTable({\n            authority: keypair.publicKey,\n            payer: keypair.publicKey,\n            recentSlot: await connection.getSlot(\"finalized\"),\n          });\n\n        const extendInstruction = AddressLookupTableProgram.extendLookupTable({\n          payer: keypair.publicKey,\n          authority: keypair.publicKey,\n          lookupTable: altAddress,\n          addresses: [\n            TOKEN_PROGRAM_ID,\n            TOKEN_2022_PROGRAM_ID,\n            SYSTEM_PROGRAM_ID,\n            deriveEventAuthority(dlmm.program.programId)[0],\n            MEMO_PROGRAM_ID,\n            NATIVE_MINT,\n          ],\n        });\n\n        const initALTTransaction = new Transaction({\n          ...(await connection.getLatestBlockhash()),\n          feePayer: keypair.publicKey,\n        }).add(initALTIx, extendInstruction);\n\n        await sendAndConfirmTransaction(connection, initALTTransaction, [\n          keypair,\n        ]);\n\n        const totalXAmount = new BN(1_000_000_000);\n        const totalYAmount = new BN(1_000_000_000);\n        const minBinId = dlmm.lbPair.activeId - 2000;\n        const maxBinId = dlmm.lbPair.activeId + 2000;\n\n        const userTokenX = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenXMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n        const userTokenY = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenYMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        const [beforeTokenX, beforeTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        const { instructionsByPositions } =\n          await dlmm.initializeMultiplePositionAndAddLiquidityByStrategy2(\n            async (count) => {\n              const positionKeypairs = [];\n              for (let i = 0; i < count; i++) {\n                const positionKeypair = Keypair.generate();\n                positionKeypairs.push(positionKeypair);\n              }\n              return positionKeypairs;\n            },\n            totalXAmount,\n            totalYAmount,\n            {\n              minBinId,\n              maxBinId,\n              strategyType: StrategyType.Curve,\n            },\n            keypair.publicKey,\n            keypair.publicKey,\n            0,\n            altAddress,\n          );\n\n        const altAccount = await connection.getAddressLookupTable(altAddress);\n        const latestBlockhashInfo = await connection.getLatestBlockhash();\n\n        await Promise.all(\n          instructionsByPositions.flatMap(\n            ({ positionKeypair, transactionInstructions }) => {\n              return transactionInstructions.flatMap((ixs) => {\n                const messageV0 = new TransactionMessage({\n                  payerKey: keypair.publicKey,\n                  recentBlockhash: latestBlockhashInfo.blockhash,\n                  instructions: ixs,\n                }).compileToV0Message([altAccount.value]);\n\n                const transaction = new VersionedTransaction(messageV0);\n                transaction.sign([keypair, positionKeypair]);\n\n                return connection.sendTransaction(transaction).then((sig) => {\n                  console.log(\"Add liquidity\", sig);\n                  return connection.confirmTransaction(\n                    {\n                      signature: sig,\n                      lastValidBlockHeight:\n                        latestBlockhashInfo.lastValidBlockHeight,\n                      blockhash: latestBlockhashInfo.blockhash,\n                    },\n                    \"confirmed\",\n                  );\n                });\n              });\n            },\n          ),\n        );\n\n        await logLbPairLiquidities(pairKey, dlmm.lbPair.binStep, dlmm.program);\n\n        const positions = await Promise.all(\n          instructionsByPositions.map(({ positionKeypair }) =>\n            dlmm.getPosition(positionKeypair.publicKey),\n          ),\n        );\n\n        for (const position of positions) {\n          const width =\n            position.positionData.upperBinId -\n            position.positionData.lowerBinId +\n            1;\n          console.log(\"🚀 ~ Position width:\", width);\n        }\n\n        let positionMinBinId = Number.MAX_SAFE_INTEGER;\n        let positionMaxBinId = Number.MIN_SAFE_INTEGER;\n\n        for (const position of positions) {\n          if (position.positionData.lowerBinId < positionMinBinId) {\n            positionMinBinId = position.positionData.lowerBinId;\n          }\n          if (position.positionData.upperBinId > positionMaxBinId) {\n            positionMaxBinId = position.positionData.upperBinId;\n          }\n        }\n\n        expect(positionMinBinId).toBe(minBinId);\n        expect(positionMaxBinId).toBe(maxBinId);\n\n        const [afterTokenX, afterTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        console.log(\"here\", beforeTokenY.toString(), afterTokenY.toString());\n\n        const consumedTokenX = beforeTokenX.sub(afterTokenX);\n        const consumedTokenY = beforeTokenY.sub(afterTokenY);\n\n        // Due to transfer fee\n        expect(consumedTokenX.gte(totalXAmount)).toBeTruthy();\n        expect(consumedTokenY.lte(totalYAmount)).toBeTruthy();\n      });\n    });\n\n    describe(\"Add liquidity chunk\", () => {\n      it(\"Add liquidity chunk\", async () => {\n        const dlmm = await DLMM.create(connection, pairKey, opt);\n\n        console.log(\"🚀 ~ dlmm:\", dlmm.pubkey.toBase58());\n\n        const totalXAmount = new BN(1_000_000_000);\n        const totalYAmount = new BN(1_000_000_000);\n\n        const minBinId = dlmm.lbPair.activeId - 400;\n        const maxBinId = dlmm.lbPair.activeId + 400;\n\n        const positionKp = Keypair.generate();\n\n        const initPositionIx = await dlmm.createEmptyPosition({\n          positionPubKey: positionKp.publicKey,\n          minBinId,\n          maxBinId: minBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1,\n          user: keypair.publicKey,\n        });\n\n        await sendAndConfirmTransaction(connection, initPositionIx, [\n          keypair,\n          positionKp,\n        ]);\n\n        const userTokenX = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenXMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenX.owner,\n        );\n        const userTokenY = getAssociatedTokenAddressSync(\n          dlmm.lbPair.tokenYMint,\n          keypair.publicKey,\n          true,\n          dlmm.tokenY.owner,\n        );\n\n        const [beforeTokenX, beforeTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        const addLiquidityTxs = await dlmm.addLiquidityByStrategyChunkable({\n          positionPubKey: positionKp.publicKey,\n          totalXAmount,\n          totalYAmount,\n          strategy: {\n            minBinId,\n            maxBinId,\n            strategyType: StrategyType.Curve,\n          },\n          user: keypair.publicKey,\n          slippage: 1,\n        });\n\n        for (const addLiquidityTx of addLiquidityTxs) {\n          const latestBlockhashInfo = await connection.getLatestBlockhash();\n\n          const tx = new Transaction({\n            ...latestBlockhashInfo,\n          }).add(...addLiquidityTx.instructions);\n\n          tx.sign(keypair);\n\n          const sig = await connection.sendRawTransaction(tx.serialize());\n          await connection.confirmTransaction({\n            ...latestBlockhashInfo,\n            signature: sig,\n          });\n        }\n\n        await logLbPairLiquidities(pairKey, dlmm.lbPair.binStep, dlmm.program);\n\n        const [afterTokenX, afterTokenY] = await Promise.all([\n          connection\n            .getTokenAccountBalance(userTokenX)\n            .then((res) => new BN(res.value.amount)),\n          connection\n            .getTokenAccountBalance(userTokenY)\n            .then((res) => new BN(res.value.amount)),\n        ]);\n\n        const consumedTokenX = beforeTokenX.sub(afterTokenX);\n        const consumedTokenY = beforeTokenY.sub(afterTokenY);\n\n        // Due to transfer fee\n        expect(consumedTokenX.gte(totalXAmount)).toBeTruthy();\n        expect(consumedTokenY.lte(totalYAmount)).toBeTruthy();\n      });\n    });\n  });\n\n  describe(\"Oracle\", () => {\n    it(\"increaseOracleLength\", async () => {\n      const dlmm = await DLMM.create(connection, pairKey, opt);\n      const oracleBefore = await dlmm.getOracle();\n      const lengthBefore = oracleBefore.metadata.length;\n\n      const lengthToAdd = new BN(5);\n      const tx = await dlmm.increaseOracleLength(\n        lengthToAdd,\n        keypair.publicKey,\n      );\n      await sendAndConfirmTransaction(connection, tx, [keypair]);\n\n      const oracleAfter = await dlmm.getOracle();\n      expect(oracleAfter.metadata.length.toNumber()).toBe(\n        lengthBefore.toNumber() + lengthToAdd.toNumber(),\n      );\n    });\n  });\n\n  describe(\"Position fetcher\", () => {\n    const pairWithPositionKey: {\n      pair: PublicKey;\n      position: PublicKey;\n      user: PublicKey;\n    }[] = [];\n\n    beforeAll(async () => {\n      const pairs = await DLMM.getLbPairs(connection, opt);\n\n      for (const pair of pairs) {\n        const userKeypair = Keypair.generate();\n\n        const airdropSig = await connection.requestAirdrop(\n          userKeypair.publicKey,\n          1 * LAMPORTS_PER_SOL,\n        );\n\n        await connection.confirmTransaction(airdropSig, \"confirmed\");\n\n        const positionKeypair = Keypair.generate();\n        const dlmm = await DLMM.create(connection, pair.publicKey, opt);\n\n        const minBinId = -30;\n        const maxBinId = 30;\n\n        const createPositionAndBinArraysTx = await dlmm.createEmptyPosition({\n          positionPubKey: positionKeypair.publicKey,\n          minBinId,\n          maxBinId,\n          user: userKeypair.publicKey,\n        });\n\n        await sendAndConfirmTransaction(\n          connection,\n          createPositionAndBinArraysTx,\n          [userKeypair, positionKeypair],\n        );\n\n        pairWithPositionKey.push({\n          pair: pair.publicKey,\n          position: positionKeypair.publicKey,\n          user: userKeypair.publicKey,\n        });\n      }\n    });\n\n    it(\"Load position by user and pair successfully\", async () => {\n      for (const { pair, position, user } of pairWithPositionKey) {\n        const dlmm = await DLMM.create(connection, pair, opt);\n        const { userPositions } = await dlmm.getPositionsByUserAndLbPair(user);\n\n        expect(userPositions.length).toBe(1);\n        expect(\n          userPositions.find((x) => x.publicKey.equals(position)),\n        ).toBeDefined();\n        expect(\n          userPositions.filter((x) => x.positionData.owner.equals(user)).length,\n        ).toBe(userPositions.length);\n      }\n    });\n\n    it(\"Load all positions by user successfully\", async () => {\n      const pairKeyedPosition = await DLMM.getAllLbPairPositionsByUser(\n        connection,\n        keypair.publicKey,\n        opt,\n      );\n\n      const positionContainers = Array.from(pairKeyedPosition.values());\n      const positions = positionContainers.flatMap(\n        (x) => x.lbPairPositionsData,\n      );\n\n      for (const position of positions) {\n        expect(\n          position.positionData.owner.equals(keypair.publicKey),\n        ).toBeTruthy();\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/single_bin.test.ts",
    "content": "import { BN, web3 } from \"@coral-xyz/anchor\";\nimport {\n  ASSOCIATED_TOKEN_PROGRAM_ID,\n  TOKEN_PROGRAM_ID,\n  createMint,\n  getAssociatedTokenAddressSync,\n  getOrCreateAssociatedTokenAccount,\n  mintTo,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  PublicKey,\n  Transaction,\n  sendAndConfirmTransaction,\n} from \"@solana/web3.js\";\nimport fs from \"fs\";\nimport { FunctionType, LBCLMM_PROGRAM_IDS } from \"../dlmm/constants\";\nimport { deriveCustomizablePermissionlessLbPair } from \"../dlmm/helpers\";\nimport { DLMM } from \"../dlmm/index\";\nimport { ActivationType } from \"../dlmm/types\";\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\nconst owner = Keypair.fromSecretKey(new Uint8Array(JSON.parse(keypairBuffer)));\nconst programId = new PublicKey(LBCLMM_PROGRAM_IDS[\"localhost\"]);\n\ndescribe(\"Single Bin Seed Liquidity Test\", () => {\n  describe(\"TokenX decimals < TokenY decimals\", () => {\n    const baseKeypair = Keypair.generate();\n    const positionOwnerKeypair = Keypair.generate();\n    const feeOwnerKeypair = Keypair.generate();\n\n    const wenDecimal = 5;\n    const usdcDecimal = 6;\n    const feeBps = new BN(500);\n    const initialPrice = 0.000001;\n    const binStep = 100;\n    const wenSeedAmount = new BN(200_000 * 10 ** wenDecimal);\n\n    let WEN: web3.PublicKey;\n    let USDC: web3.PublicKey;\n    let userWEN: web3.PublicKey;\n    let userUSDC: web3.PublicKey;\n    let pairKey: web3.PublicKey;\n    let pair: DLMM;\n    let positionOwnerTokenX: web3.PublicKey;\n\n    const initialPricePerLamport = DLMM.getPricePerLamport(\n      wenDecimal,\n      usdcDecimal,\n      initialPrice\n    );\n    const binId = DLMM.getBinIdFromPrice(\n      initialPricePerLamport,\n      binStep,\n      false\n    );\n\n    beforeAll(async () => {\n      WEN = await createMint(\n        connection,\n        owner,\n        owner.publicKey,\n        null,\n        wenDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      USDC = await createMint(\n        connection,\n        owner,\n        owner.publicKey,\n        null,\n        usdcDecimal,\n        Keypair.generate(),\n        null,\n        TOKEN_PROGRAM_ID\n      );\n\n      const userWenInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        owner,\n        WEN,\n        owner.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userWEN = userWenInfo.address;\n\n      const userUsdcInfo = await getOrCreateAssociatedTokenAccount(\n        connection,\n        owner,\n        USDC,\n        owner.publicKey,\n        false,\n        \"confirmed\",\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID,\n        ASSOCIATED_TOKEN_PROGRAM_ID\n      );\n      userUSDC = userUsdcInfo.address;\n\n      await mintTo(\n        connection,\n        owner,\n        WEN,\n        userWEN,\n        owner.publicKey,\n        wenSeedAmount.toNumber() + 1,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      await mintTo(\n        connection,\n        owner,\n        USDC,\n        userUSDC,\n        owner.publicKey,\n        1_000_000_000 * 10 ** usdcDecimal,\n        [],\n        {\n          commitment: \"confirmed\",\n        },\n        TOKEN_PROGRAM_ID\n      );\n\n      const slot = await connection.getSlot();\n      const activationPoint = new BN(slot).add(new BN(100));\n\n      let rawTx = await DLMM.createCustomizablePermissionlessLbPair(\n        connection,\n        new BN(binStep),\n        WEN,\n        USDC,\n        new BN(binId.toString()),\n        feeBps,\n        ActivationType.Slot,\n        false, // No alpha vault. Set to true the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: https://github.com/MeteoraAg/alpha-vault-sdk initialize{Prorata|Fcfs}Vault method to create the alpha vault.\n        owner.publicKey,\n        activationPoint,\n        false,\n        {\n          cluster: \"localhost\",\n        }\n      );\n\n      let txHash = await sendAndConfirmTransaction(connection, rawTx, [\n        owner,\n      ]).catch((e) => {\n        console.error(e);\n        throw e;\n      });\n      console.log(\"Create permissioned LB pair\", txHash);\n\n      [pairKey] = deriveCustomizablePermissionlessLbPair(WEN, USDC, programId);\n\n      pair = await DLMM.create(connection, pairKey, {\n        cluster: \"localhost\",\n      });\n\n      positionOwnerTokenX = getAssociatedTokenAddressSync(\n        WEN,\n        positionOwnerKeypair.publicKey,\n        true\n      );\n    });\n\n    it(\"seed liquidity single bin\", async () => {\n      const { instructions } = await pair.seedLiquiditySingleBin(\n        owner.publicKey,\n        baseKeypair.publicKey,\n        wenSeedAmount,\n        initialPrice,\n        true,\n        positionOwnerKeypair.publicKey,\n        feeOwnerKeypair.publicKey,\n        owner.publicKey,\n        new BN(0),\n        true\n      );\n\n      const { blockhash, lastValidBlockHeight } =\n        await connection.getLatestBlockhash(\"confirmed\");\n      const tx = new Transaction({\n        feePayer: owner.publicKey,\n        blockhash,\n        lastValidBlockHeight,\n      }).add(...instructions);\n\n      const beforeTokenXBalance = await connection\n        .getTokenAccountBalance(userWEN)\n        .then((i) => new BN(i.value.amount));\n\n      await sendAndConfirmTransaction(connection, tx, [\n        owner,\n        baseKeypair,\n      ]).catch((e) => {\n        console.error(e);\n      });\n\n      const afterTokenXBalance = await connection\n        .getTokenAccountBalance(userWEN)\n        .then((i) => new BN(i.value.amount));\n\n      const actualDepositedAmount = beforeTokenXBalance.sub(afterTokenXBalance);\n      expect(actualDepositedAmount.toString()).toEqual(\n        // 1 prove token was sent to positionOwnerTokenX\n        wenSeedAmount.addn(1).toString()\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "ts-client/src/test/token_2022.test.ts",
    "content": "import { Wallet } from \"@coral-xyz/anchor\";\nimport {\n  createInitializeMintInstruction,\n  createInitializeTransferFeeConfigInstruction,\n  createInitializeTransferHookInstruction,\n  ExtensionType,\n  getExtraAccountMetaAddress,\n  getMintLen,\n  TOKEN_2022_PROGRAM_ID,\n  unpackMint,\n} from \"@solana/spl-token\";\nimport {\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL, \n  PublicKey,\n  sendAndConfirmTransaction,\n  SystemProgram,\n  Transaction,\n  TransactionInstruction,\n} from \"@solana/web3.js\";\nimport { BN } from \"bn.js\";\nimport fs from \"fs\";\nimport {\n  calculateTransferFeeExcludedAmount,\n  calculateTransferFeeIncludedAmount,\n  getExtraAccountMetasForTransferHook,\n  getMultipleMintsExtraAccountMetasForTransferHook,\n} from \"../dlmm/helpers/token_2022\";\nimport {\n  createExtraAccountMetaListAndCounter,\n  deriveCounter,\n} from \"./external/helper\";\nimport {\n  createTransferHookCounterProgram,\n  TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n} from \"./external/program\";\n\nconst connection = new Connection(\"http://127.0.0.1:8899\", \"confirmed\");\n\nconst keypairBuffer = fs.readFileSync(\n  \"../keys/localnet/admin-bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1.json\",\n  \"utf-8\"\n);\nconst keypair = Keypair.fromSecretKey(\n  new Uint8Array(JSON.parse(keypairBuffer))\n);\n\nconst BTCKeypair = Keypair.generate();\nconst USDCKeypair = Keypair.generate();\n\nconst BTCWithTransferHook: PublicKey = BTCKeypair.publicKey;\nconst USDCWithTransferFeeAndHook: PublicKey = USDCKeypair.publicKey;\n\nconst transferFeeBps = 500; // 5%\nconst maxFee = BigInt(100_000);\n\nasync function createMintWithExtensions(\n  owner: Keypair,\n  mintKeypair: Keypair,\n  extensionWithIx: {\n    createIx: TransactionInstruction;\n    extensionType: ExtensionType;\n  }[],\n  decimals: number\n) {\n  const extensions = extensionWithIx.map((e) => e.extensionType);\n  const mintLen = getMintLen(extensions);\n  const minLamports =\n    await connection.getMinimumBalanceForRentExemption(mintLen);\n\n  const transaction = new Transaction().add(\n    SystemProgram.createAccount({\n      fromPubkey: keypair.publicKey,\n      newAccountPubkey: mintKeypair.publicKey,\n      space: mintLen,\n      lamports: minLamports,\n      programId: TOKEN_2022_PROGRAM_ID,\n    })\n  );\n\n  for (const { createIx } of extensionWithIx) {\n    transaction.add(createIx);\n  }\n\n  transaction.add(\n    createInitializeMintInstruction(\n      mintKeypair.publicKey,\n      decimals,\n      owner.publicKey,\n      null,\n      TOKEN_2022_PROGRAM_ID\n    )\n  );\n\n  await sendAndConfirmTransaction(\n    connection,\n    transaction,\n    [keypair, mintKeypair],\n    {\n      commitment: \"confirmed\",\n    }\n  );\n}\n\ndescribe(\"Token 2022 helper test\", () => {\n  beforeAll(async () => {\n    const signature = await connection.requestAirdrop(\n      keypair.publicKey,\n      10 * LAMPORTS_PER_SOL\n    );\n    await connection.confirmTransaction(signature, \"confirmed\");\n\n    const transferHookCounterProgram = createTransferHookCounterProgram(\n      new Wallet(keypair),\n      TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n      connection\n    );\n\n    await createMintWithExtensions(\n      keypair,\n      USDCKeypair,\n      [\n        {\n          createIx: createInitializeTransferHookInstruction(\n            USDCKeypair.publicKey,\n            keypair.publicKey,\n            TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n            TOKEN_2022_PROGRAM_ID\n          ),\n          extensionType: ExtensionType.TransferHook,\n        },\n        {\n          createIx: createInitializeTransferFeeConfigInstruction(\n            USDCKeypair.publicKey,\n            keypair.publicKey,\n            null,\n            transferFeeBps,\n            maxFee,\n            TOKEN_2022_PROGRAM_ID\n          ),\n          extensionType: ExtensionType.TransferFeeConfig,\n        },\n      ],\n      6\n    ).then(() => {\n      return createExtraAccountMetaListAndCounter(\n        transferHookCounterProgram,\n        USDCWithTransferFeeAndHook\n      );\n    });\n\n    await createMintWithExtensions(\n      keypair,\n      BTCKeypair,\n      [\n        {\n          createIx: createInitializeTransferHookInstruction(\n            BTCKeypair.publicKey,\n            keypair.publicKey,\n            TRANSFER_HOOK_COUNTER_PROGRAM_ID,\n            TOKEN_2022_PROGRAM_ID\n          ),\n          extensionType: ExtensionType.TransferHook,\n        },\n      ],\n      6\n    ).then(() => {\n      return createExtraAccountMetaListAndCounter(\n        transferHookCounterProgram,\n        BTCWithTransferHook\n      );\n    });\n  });\n\n  it(\"getExtraAccountMetasForTransferHook return correct accounts\", async () => {\n    const mintAccount = await connection.getAccountInfo(\n      USDCWithTransferFeeAndHook\n    );\n\n    const extraAccountMetas = await getExtraAccountMetasForTransferHook(\n      connection,\n      USDCWithTransferFeeAndHook,\n      mintAccount\n    );\n\n    const counterPda = deriveCounter(\n      USDCWithTransferFeeAndHook,\n      TRANSFER_HOOK_COUNTER_PROGRAM_ID\n    );\n\n    expect(extraAccountMetas.length).toBe(3);\n\n    const account0 = extraAccountMetas[0].pubkey.toBase58();\n    expect(account0).toBe(counterPda.toBase58());\n\n    const account1 = extraAccountMetas[1].pubkey.toBase58();\n    expect(account1).toBe(TRANSFER_HOOK_COUNTER_PROGRAM_ID.toBase58());\n\n    const account2 = extraAccountMetas[2].pubkey.toBase58();\n    expect(account2).toBe(\n      getExtraAccountMetaAddress(\n        USDCWithTransferFeeAndHook,\n        TRANSFER_HOOK_COUNTER_PROGRAM_ID\n      ).toBase58()\n    );\n  });\n\n  it(\"getMultipleMintsExtraAccountMetasForTransferHook return correct accounts\", async () => {\n    const [usdcMintAccount, btcMintAccount] =\n      await connection.getMultipleAccountsInfo([\n        USDCWithTransferFeeAndHook,\n        BTCWithTransferHook,\n      ]);\n\n    const multipleMintsExtraAccountMetas =\n      await getMultipleMintsExtraAccountMetasForTransferHook(connection, [\n        {\n          mintAddress: USDCWithTransferFeeAndHook,\n          mintAccountInfo: usdcMintAccount,\n        },\n        {\n          mintAddress: BTCWithTransferHook,\n          mintAccountInfo: btcMintAccount,\n        },\n      ]);\n\n    for (const [mintAddress, accounts] of multipleMintsExtraAccountMetas) {\n      expect(accounts.length).toBe(3);\n      const mintKey = new PublicKey(mintAddress);\n\n      const counterPda = deriveCounter(\n        mintKey,\n        TRANSFER_HOOK_COUNTER_PROGRAM_ID\n      );\n\n      const account0 = accounts[0].pubkey.toBase58();\n      expect(account0).toBe(counterPda.toBase58());\n\n      const account1 = accounts[1].pubkey.toBase58();\n      expect(account1).toBe(TRANSFER_HOOK_COUNTER_PROGRAM_ID.toBase58());\n\n      const account2 = accounts[2].pubkey.toBase58();\n      expect(account2).toBe(\n        getExtraAccountMetaAddress(\n          mintKey,\n          TRANSFER_HOOK_COUNTER_PROGRAM_ID\n        ).toBase58()\n      );\n    }\n  });\n\n  it(\"calculateTransferFeeIncludedAmount return more value than original value\", async () => {\n    const usdcMintAccount = await connection.getAccountInfo(\n      USDCWithTransferFeeAndHook\n    );\n\n    const mint = unpackMint(\n      USDCWithTransferFeeAndHook,\n      usdcMintAccount,\n      usdcMintAccount.owner\n    );\n\n    const transferFeeExcludedAmount = new BN(100_000);\n\n    const transferFeeIncludedAmount = calculateTransferFeeIncludedAmount(\n      transferFeeExcludedAmount,\n      mint,\n      0\n    ).amount;\n\n    expect(\n      transferFeeIncludedAmount.gt(transferFeeExcludedAmount)\n    ).toBeTruthy();\n  });\n\n  it(\"calculateTransferFeeExcludedAmount return less value than original value\", async () => {\n    const usdcMintAccount = await connection.getAccountInfo(\n      USDCWithTransferFeeAndHook\n    );\n\n    const mint = unpackMint(\n      USDCWithTransferFeeAndHook,\n      usdcMintAccount,\n      usdcMintAccount.owner\n    );\n\n    const transferFeeIncludedAmount = new BN(100_000);\n\n    const transferFeeExcludedAmount = calculateTransferFeeExcludedAmount(\n      transferFeeIncludedAmount,\n      mint,\n      0\n    ).amount;\n\n    expect(\n      transferFeeIncludedAmount.gt(transferFeeExcludedAmount)\n    ).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "ts-client/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"types\": [\"jest\"],\n    \"typeRoots\": [\"./node_modules/@types\"],\n    \"module\": \"commonjs\",\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"resolveJsonModule\": true,\n    \"noImplicitAny\": false,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"strictNullChecks\": false,\n  }\n}\n"
  },
  {
    "path": "ts-client/tsup.config.ts",
    "content": "import type { Options } from \"tsup\";\n\nconst config: Options = {\n  entry: [\"src/index.ts\"],\n  format: [\"esm\", \"cjs\"],\n  splitting: true,\n  sourcemap: true,\n  minify: false,\n  clean: true,\n  skipNodeModulesBundle: true,\n  dts: true,\n  external: [\"node_modules\"],\n  // post-process CJS build to fix default export for require() users\n  onSuccess: async () => {\n    const fs = await import(\"fs\");\n    const path = await import(\"path\");\n    const cjsPath = path.join(process.cwd(), \"dist\", \"index.js\");\n    let content = fs.readFileSync(cjsPath, \"utf8\");\n\n    content +=\n      \"\\n\\n// CJS interop: Make default export primary for require() compatibility\\n\";\n    content += \"if (exports.default) {\\n\";\n    content += \"  module.exports = exports.default;\\n\";\n    content += \"  for (const key in exports) {\\n\";\n    content += '    if (key !== \"default\") {\\n';\n    content += \"      module.exports[key] = exports[key];\\n\";\n    content += \"    }\\n\";\n    content += \"  }\\n\";\n    content += \"}\\n\";\n\n    fs.writeFileSync(cjsPath, content);\n  },\n};\n\nexport default config;\n"
  }
]