Full Code of Uniswap/v4-core for AI

main d153b048868a cached
193 files
5.5 MB
1.4M tokens
556 symbols
1 requests
Download .txt
Showing preview only (5,774K chars total). Download the full file or copy to clipboard to get everything.
Repository: Uniswap/v4-core
Branch: main
Commit: d153b048868a
Files: 193
Total size: 5.5 MB

Directory structure:
gitextract_ps96d9yk/

├── .gitattributes
├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.yml
│   │   └── FEATURE_IMPROVEMENT.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── deploy.yaml
│       ├── lint.yml
│       ├── mythx.yml
│       ├── tests-merge.yml
│       └── tests-pr.yml
├── .gitignore
├── .gitmodules
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .solhint.json
├── CONTRIBUTING.md
├── README.md
├── SECURITY.md
├── docs/
│   └── whitepaper/
│       └── latex/
│           ├── main-zh.tex
│           ├── main.bib
│           └── main.tex
├── echidna.config.yml
├── foundry.toml
├── justfile
├── licenses/
│   ├── BUSL_LICENSE
│   └── MIT_LICENSE
├── package.json
├── remappings.txt
├── snapshots/
│   ├── ClearTest.json
│   ├── CustomAccountingTest.json
│   ├── ERC6909ClaimsTest.json
│   ├── ExtsloadTest.json
│   ├── ModifyLiquidityTest.json
│   ├── PoolManagerInitializeTest.json
│   ├── PoolManagerTest.json
│   ├── ProtocolFeesTest.json
│   ├── SkipCallsTest.json
│   ├── SqrtPriceMathTest.json
│   ├── StateLibraryTest.json
│   ├── SwapMathTest.json
│   ├── SyncTest.json
│   ├── TestBitMath.json
│   ├── TestDelegateCall.json
│   ├── TestDynamicFees.json
│   ├── TestDynamicReturnFees.json
│   ├── TickBitmapTest.json
│   ├── TickMathTestTest.json
│   └── TickTest.json
├── src/
│   ├── ERC6909.sol
│   ├── ERC6909Claims.sol
│   ├── Extsload.sol
│   ├── Exttload.sol
│   ├── NoDelegateCall.sol
│   ├── PoolManager.sol
│   ├── ProtocolFees.sol
│   ├── interfaces/
│   │   ├── IExtsload.sol
│   │   ├── IExttload.sol
│   │   ├── IHooks.sol
│   │   ├── IPoolManager.sol
│   │   ├── IProtocolFees.sol
│   │   ├── callback/
│   │   │   └── IUnlockCallback.sol
│   │   └── external/
│   │       ├── IERC20Minimal.sol
│   │       └── IERC6909Claims.sol
│   ├── libraries/
│   │   ├── BitMath.sol
│   │   ├── CurrencyDelta.sol
│   │   ├── CurrencyReserves.sol
│   │   ├── CustomRevert.sol
│   │   ├── FixedPoint128.sol
│   │   ├── FixedPoint96.sol
│   │   ├── FullMath.sol
│   │   ├── Hooks.sol
│   │   ├── LPFeeLibrary.sol
│   │   ├── LiquidityMath.sol
│   │   ├── Lock.sol
│   │   ├── NonzeroDeltaCount.sol
│   │   ├── ParseBytes.sol
│   │   ├── Pool.sol
│   │   ├── Position.sol
│   │   ├── ProtocolFeeLibrary.sol
│   │   ├── SafeCast.sol
│   │   ├── SqrtPriceMath.sol
│   │   ├── StateLibrary.sol
│   │   ├── SwapMath.sol
│   │   ├── TickBitmap.sol
│   │   ├── TickMath.sol
│   │   ├── TransientStateLibrary.sol
│   │   └── UnsafeMath.sol
│   ├── test/
│   │   ├── ActionsRouter.sol
│   │   ├── BaseTestHooks.sol
│   │   ├── CurrencyTest.sol
│   │   ├── CustomCurveHook.sol
│   │   ├── DeltaReturningHook.sol
│   │   ├── DynamicFeesTestHook.sol
│   │   ├── DynamicReturnFeeTestHook.sol
│   │   ├── EmptyRevertContract.sol
│   │   ├── EmptyTestHooks.sol
│   │   ├── FeeTakingHook.sol
│   │   ├── Fuzzers.sol
│   │   ├── HooksTest.sol
│   │   ├── LPFeeTakingHook.sol
│   │   ├── LiquidityMathTest.sol
│   │   ├── MockContract.sol
│   │   ├── MockERC6909Claims.sol
│   │   ├── MockHooks.sol
│   │   ├── NativeERC20.sol
│   │   ├── NoDelegateCallTest.sol
│   │   ├── PoolClaimsTest.sol
│   │   ├── PoolDonateTest.sol
│   │   ├── PoolEmptyUnlockTest.sol
│   │   ├── PoolModifyLiquidityTest.sol
│   │   ├── PoolModifyLiquidityTestNoChecks.sol
│   │   ├── PoolNestedActionsTest.sol
│   │   ├── PoolSwapTest.sol
│   │   ├── PoolTakeTest.sol
│   │   ├── PoolTestBase.sol
│   │   ├── ProtocolFeesImplementation.sol
│   │   ├── ProxyPoolManager.sol
│   │   ├── SkipCallsTestHook.sol
│   │   ├── SqrtPriceMathEchidnaTest.sol
│   │   ├── SwapRouterNoChecks.sol
│   │   ├── TestERC20.sol
│   │   ├── TestInvalidERC20.sol
│   │   ├── TickMathEchidnaTest.sol
│   │   ├── TickMathTest.sol
│   │   └── TickOverflowSafetyEchidnaTest.sol
│   └── types/
│       ├── BalanceDelta.sol
│       ├── BeforeSwapDelta.sol
│       ├── Currency.sol
│       ├── PoolId.sol
│       ├── PoolKey.sol
│       ├── PoolOperation.sol
│       └── Slot0.sol
└── test/
    ├── CurrencyReserves.t.sol
    ├── CustomAccounting.t.sol
    ├── DynamicFees.t.sol
    ├── DynamicReturnFees.t.sol
    ├── ERC6909Claims.t.sol
    ├── Extsload.t.sol
    ├── ModifyLiquidity.t.sol
    ├── NoDelegateCall.t.sol
    ├── PoolManager.clear.t.sol
    ├── PoolManager.gas.spec.ts
    ├── PoolManager.swap.t.sol
    ├── PoolManager.t.sol
    ├── PoolManagerInitialize.t.sol
    ├── ProtocolFeesImplementation.t.sol
    ├── SkipCallsTestHook.t.sol
    ├── Sync.t.sol
    ├── Tick.t.sol
    ├── bin/
    │   └── v3Factory.bytecode
    ├── js-scripts/
    │   ├── build.js
    │   ├── dist/
    │   │   ├── getModifyLiquidityResult.js
    │   │   ├── getSqrtPriceAtTick.js
    │   │   └── getTickAtSqrtPrice.js
    │   ├── package.json
    │   ├── src/
    │   │   ├── getModifyLiquidityResult.ts
    │   │   ├── getSqrtPriceAtTick.ts
    │   │   ├── getTickAtSqrtPrice.ts
    │   │   └── utils/
    │   │       └── shared.ts
    │   └── tsconfig.json
    ├── libraries/
    │   ├── BitMath.t.sol
    │   ├── FullMath.t.sol
    │   ├── Hooks.t.sol
    │   ├── LPFeeLibrary.t.sol
    │   ├── LiquidityMath.t.sol
    │   ├── Lock.t.sol
    │   ├── NonzeroDeltaCount.t.sol
    │   ├── Pool.t.sol
    │   ├── PoolId.t.sol
    │   ├── Position.t.sol
    │   ├── ProtocolFeeLibrary.t.sol
    │   ├── SafeCast.t.sol
    │   ├── SqrtPriceMath.t.sol
    │   ├── StateLibrary.t.sol
    │   ├── SwapMath.t.sol
    │   ├── TickBitmap.t.sol
    │   ├── TickMath.t.sol
    │   └── UnsafeMath.t.sol
    ├── types/
    │   ├── BalanceDelta.t.sol
    │   ├── Currency.t.sol
    │   └── Slot0.t.sol
    └── utils/
        ├── AmountHelpers.sol
        ├── Constants.sol
        ├── CurrencySettler.sol
        ├── Deployers.sol
        ├── JavascriptFfi.sol
        ├── LiquidityAmounts.sol
        ├── Logger.sol
        ├── NestedActions.t.sol
        ├── SortTokens.sol
        ├── SwapHelper.t.sol
        └── V3Helper.sol

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
*.sol linguist-language=Solidity

================================================
FILE: .github/CODEOWNERS
================================================
* @uniswap/protocols


================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.yml
================================================
name: Bug report
description: File a bug report to help us improve the code
title: "[Bug]: "
labels: ["bug"]

body:
  - type: markdown
    attributes:
      value: |
        Please check that the bug is not already being tracked.
  - type: textarea
    attributes:
      label: Describe the bug
      description: Provide a clear and concise description of what the bug is and which contracts it affects.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Expected Behavior
      description: Provide a clear and concise description of the desired fix.
    validations:
      required: true
  - type: textarea
    attributes:
      label: To Reproduce
      description: If you have written tests to showcase the bug, what can we run to reproduce the issue?
      placeholder: "git checkout <branchname> / forge test --isolate --mt <testName>"
  - type: textarea
    attributes:
      label: Additional context
      description: If there is any additional context needed like a dependency or integrating contract that is affected please describe it below.


================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE_IMPROVEMENT.yml
================================================
name: Feature Improvement
description: Suggest an improvement to v4-core.
labels: ["triage"]

body:
  - type: markdown
    attributes:
      value: |
        Please ensure that the feature has not already been requested.
  - type: dropdown
    attributes:
      label: Component
      description: Which area of code does your idea improve?
      multiple: true
      options:
        - Hooks
        - Singleton
        - Lock and Call
        - Delta accounting
        - 1155 Balances
        - Pool Actions (swap, modifyLiquidity, donate, take, settle, mint)
        - Gas Optimization
        - General design optimization (improving efficiency, cleanliness, or developer experience)
        - Documentation
  - type: textarea
    attributes:
      label: Describe the suggested feature and problem it solves.
      description: Provide a clear and concise description of what feature you would like to see, and what problems it solves.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Describe the desired implementation.
      description: If possible, provide a suggested architecture change or implementation.
  - type: textarea
    attributes:
      label: Describe alternatives.
      description: If possible, describe the alternatives you've considered, or describe the current functionality and how it may be sub-optimal.
  - type: textarea
    attributes:
      label: Additional context.
      description: Please list any additional dependencies or integrating contacts that are affected.


================================================
FILE: .github/pull_request_template.md
================================================
## Related Issue

Which issue does this pull request resolve?

## Description of changes


================================================
FILE: .github/workflows/deploy.yaml
================================================
name: Release
on:
  # manual trigger
  workflow_dispatch:

jobs:
  deploy:
    name: release
    runs-on:
      group: npm-deploy
    environment:
      name: release
    permissions:
      id-token: write
      contents: write
    steps:
      - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4

      - name: Checkout
        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0

      - name: Setup Node
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
        with:
          node-version: "20.x"
          registry-url: "https://registry.npmjs.org"
          scope: "@uniswap"

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@50d5a8956f2e319df19e6b57539d7e2acb9f8c1e # v1.5.0
        with:
          version: v1.3.6

      - name: Install dependencies
        run: |
          git submodule update --init --recursive

      - name: Compile
        run: forge build

      - name: Install npm
        run: npm install -g npm@latest

      - name: Release
        run: |
          npm publish --access public


================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  run-linters:
    name: Run linters
    runs-on: ubuntu-latest

    steps:
      - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4

      - name: Check out Git repository
        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@50d5a8956f2e319df19e6b57539d7e2acb9f8c1e # v1.5.0
        with:
          version: v1.3.6

      - name: Lint
        run: forge fmt --check

      - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
        name: Configure npm caching
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/prettier.yml') }}
          restore-keys: |
            ${{ runner.os }}-npm-

      - name: Check code formatting
        run: |-
          npx prettier --check .


================================================
FILE: .github/workflows/mythx.yml
================================================
name: Mythx

on:
  workflow_dispatch:

jobs:
  mythx:
    name: Submit to Mythx
    runs-on: ubuntu-latest

    steps:
      - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4

      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

      - name: Set up node
        uses: actions/setup-node@f1f314fca9dfce2769ece7d933488f076716723e # v1.4.6
        with:
          node-version: 16

      - name: Set up Python 3.8
        uses: actions/setup-python@e9aba2c848f5ebd159c070c61ea2c4e2b122355e # v2.3.4
        with:
          python-version: 3.8

      - name: Install node dependencies
        run: yarn install --frozen-lockfile

      - name: Install pip3
        run: |
          python -m pip install --upgrade pip

      - name: Install mythx CLI
        run: |
          pip3 install mythx-cli

      - name: Install solc-select
        run: |
          pip3 install solc-select

      - name: Install solc 0.8.20
        run: |
          solc-select install 0.8.20
          solc-select use 0.8.20

      - name: Submit code to Mythx
        run: |
          mythx --api-key ${{ secrets.MYTHX_API_KEY }} \
            --yes \
            analyze \
            --mode deep \
            --async \
            --create-group \
            --group-name "@uniswap/core-next@${{ github.sha }}" \
            --solc-version 0.8.20 \
            --check-properties \
            --remap-import "@openzeppelin/contracts/=$(pwd)/node_modules/@openzeppelin/contracts/" \
            contracts/test/TickBitmapEchidnaTest.sol --include TickBitmapEchidnaTest \
            contracts/test/TickMathEchidnaTest.sol --include TickMathEchidnaTest \
            contracts/test/SqrtPriceMathEchidnaTest.sol --include SqrtPriceMathEchidnaTest \
            contracts/test/SwapMathEchidnaTest.sol --include SwapMathEchidnaTest \
            contracts/test/TickEchidnaTest.sol --include TickEchidnaTest \
            contracts/test/TickOverflowSafetyEchidnaTest.sol --include TickOverflowSafetyEchidnaTest \
            contracts/test/OracleEchidnaTest.sol --include OracleEchidnaTest \
            contracts/test/BitMathEchidnaTest.sol --include BitMathEchidnaTest \
            contracts/test/UnsafeMathEchidnaTest.sol --include UnsafeMathEchidnaTest \
            contracts/test/FullMathEchidnaTest.sol --include FullMathEchidnaTest


================================================
FILE: .github/workflows/tests-merge.yml
================================================
name: Tests

on:
  push:
    branches:
      - main

jobs:
  forge-tests:
    name: Forge Tests
    runs-on: ubuntu-latest

    steps:
      - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4

      - uses: actions/checkout@v5 # v5.0.0
        with:
          submodules: recursive

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@50d5a8956f2e319df19e6b57539d7e2acb9f8c1e # v1.5.0
        with:
          version: v1.3.6

      - name: Build
        run: forge build
        env:
          FOUNDRY_PROFILE: ci

      - name: Run tests
        run: forge test --isolate -vvv
        env:
          FOUNDRY_PROFILE: ci
          FORGE_SNAPSHOT_CHECK: true


================================================
FILE: .github/workflows/tests-pr.yml
================================================
name: Tests

on:
  pull_request:
    branches:
      - main
      - dev
      - audit/*

jobs:
  forge-tests:
    name: Forge Tests
    runs-on: ubuntu-latest

    steps:
      - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4

      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
        with:
          submodules: recursive

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@50d5a8956f2e319df19e6b57539d7e2acb9f8c1e # v1.5.0
        with:
          version: v1.3.6

      - name: Show Forge version
        run: |
          forge --version

      - name: Build
        run: forge build
        env:
          FOUNDRY_PROFILE: pr

      - name: Run tests
        run: forge test --isolate -vvv
        env:
          FOUNDRY_PROFILE: pr
          FORGE_SNAPSHOT_CHECK: true


================================================
FILE: .gitignore
================================================
# if you add a file here, add it to `.npmignore` too
artifacts/
cache/
crytic-export/
node_modules/
typechain/
foundry-out/
.vscode/
out/


================================================
FILE: .gitmodules
================================================
[submodule "lib/forge-std"]
	path = lib/forge-std
	url = https://github.com/foundry-rs/forge-std
[submodule "lib/solmate"]
	path = lib/solmate
	url = https://github.com/transmissions11/solmate
[submodule "lib/openzeppelin-contracts"]
	path = lib/openzeppelin-contracts
	url = https://github.com/openzeppelin/openzeppelin-contracts


================================================
FILE: .npmignore
================================================
artifacts/
cache/
crytic-export/
node_modules/
typechain/
foundry-out/
.vscode/


================================================
FILE: .prettierignore
================================================
.prettierrc
foundry.toml
out
lib/
cache/
*.sol
dist/
snapshots/


================================================
FILE: .prettierrc
================================================
{
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "singleQuote": false,
  "bracketSpacing": true,
  "trailingComma": "all",
  "embeddedLanguageFormatting": "off",
  "overrides": [
    {
      "files": "*.sol",
      "options": {
        "printWidth": 120,
        "tabWidth": 4,
        "useTabs": false,
        "singleQuote": false,
        "bracketSpacing": false
      }
    },
    {
      "files": "*.json",
      "options": {
        "tabWidth": 2
      }
    }
  ]
}


================================================
FILE: .solhint.json
================================================
{
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
}


================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Guidelines

Thanks for your interest in contributing to v4 of the Uniswap Protocol! The contracts in this repo are in early stages - we are releasing the draft code now so that v4 can be built in public, with open feedback and meaningful community contribution. We expect this will be a months-long process, and we appreciate any kind of contribution, no matter how small.

If you need to get in contact with the repository maintainers, please reach out in our [Discord](https://discord.com/invite/FCfyBSbCU5).

## Types of Contributing

There are many ways to contribute, but here are a few if you want a place to start:

1. **Opening an issue.** Before opening an issue, please check that there is not an issue already open. If there is, feel free to comment more details, explanations, or examples within the open issue rather than duplicating it. Suggesting changes to the open development process are within the bounds of opening issues. We are always open to feedback and receptive to suggestions!
2. **Resolving an issue.** You can resolve an issue either by showing that it is not an issue or by fixing the issue with code changes, additional tests, etc. Any pull request fixing an issue should reference that issue.
3. **Reviewing open PRs.** You can provide comments, standards guidance, naming suggestions, gas optimizations, or ideas for alternative designs on any open pull request.

## Opening an Issue

When opening an [issue](https://github.com/Uniswap/v4-core/issues/new/choose), choose a template to start from: Bug Report or Feature Improvement. For bug reports, you should be able to reproduce the bug through tests or proof of concept implementations. For feature improvements, please title it with a concise problem statement and check that a similar request is not already open or already in progress. Not all issues may be deemed worth resolving, so please follow through with responding to any questions or comments that others may have regarding the issue.

Feel free to tag the issue as a “good first issue” for any clean-up related issues, or small scoped changes to help encourage pull requests from first time contributors!

## Opening a Pull Request

All pull requests should be opened against the `main` branch. In the pull request, please reference the issue you are fixing.

Pull requests can be reviewed by community members, but to be merged they will need approval from the repository maintainers. Please understand it will take time to receive a response, although the maintainers will aim to respond and comment as soon as possible.

**For larger, more substantial changes to the code, it is best to open an issue and start a discussion with the maintainers to align on the change before spending time on the development.**

Finally, before opening a pull request please do the following:

- Check that the code style follows the [standards](#standards).
- Run the tests and snapshots. Commands are outlined in the [tests](#tests) section.
- Document any new functions, structs, or interfaces following the natspec standard.
- Add tests! For smaller contributions, they should be tested with unit tests, and fuzz tests where possible. For bigger contributions, they should be tested with integration tests and invariant tests where possible.
- Make sure all commits are [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)

## Standards

All contributions must follow the below standards. Maintainers will close out PRs that do not adhere to these standards.

1. All contracts should be formatted with the default forge fmt config. Run `forge fmt`.
2. These contracts follow the [solidity style guide](https://docs.soliditylang.org/en/v0.8.17/style-guide.html) with one minor exception of using the \_prependUnderscore style naming for internal contract functions, internal top-level parameters, and function parameters with naming collisions.
3. All external facing contracts should inherit from interfaces, which specify and document its functions with natspec.
4. Picking up stale issues by other authors is fine! Please just communicate with them ahead of time and it is best practice to include co-authors in any commits.
5. Squash commits where possible to make reviews clean and efficient. PRs that are merged to main will be squashed into 1 commit.

## Setup

`forge build` to get contract artifacts and dependencies for forge

`forge test --isolate` to run forge tests and update snapshots

## Code of Conduct

Above all else, please be respectful of the people behind the code. Any kind of aggressive or disrespectful comments, issues, and language will be removed.

Issues and PRs that are obviously spam and unhelpful to the development process or unrelated to the core code will also be closed.


================================================
FILE: README.md
================================================
# Uniswap v4 Core

[![Lint](https://github.com/Uniswap/v4-core/actions/workflows/lint.yml/badge.svg)](https://github.com/Uniswap/v4-core/actions/workflows/lint.yml)
[![Tests](https://github.com/Uniswap/v4-core/actions/workflows/tests-merge.yml/badge.svg)](https://github.com/Uniswap/v4-core/actions/workflows/tests-merge.yml)

Uniswap v4 is a new automated market maker protocol that provides extensible and customizable pools. `v4-core` hosts the core pool logic for creating pools and executing pool actions like swapping and providing liquidity.

The contracts in this repo are in early stages - we are releasing the draft code now so that v4 can be built in public, with open feedback and meaningful community contribution. We expect this will be a months-long process, and we appreciate any kind of contribution, no matter how small.

## Contributing

If you’re interested in contributing please see our [contribution guidelines](./CONTRIBUTING.md)!

## Whitepaper

A more detailed description of Uniswap v4 Core can be found in the draft of the [Uniswap v4 Core Whitepaper](./docs/whitepaper/whitepaper-v4.pdf).

## Architecture

`v4-core` uses a singleton-style architecture, where all pool state is managed in the `PoolManager.sol` contract. Pool actions can be taken after an initial call to `unlock`. Integrators implement the `unlockCallback` and proceed with any of the following actions on the pools:

- `swap`
- `modifyLiquidity`
- `donate`
- `take`
- `settle`
- `mint`
- `burn`

Note that pool initialization can happen outside the context of unlocking the PoolManager.

Only the net balances owed to the user (positive) or to the pool (negative) are tracked throughout the duration of an unlock. This is the `delta` field held in the unlock state. Any number of actions can be run on the pools, as long as the deltas accumulated during the unlock reach 0 by the unlock’s release. This unlock and call style architecture gives callers maximum flexibility in integrating with the core code.

Additionally, a pool may be initialized with a hook contract, that can implement any of the following callbacks in the lifecycle of pool actions:

- {before,after}Initialize
- {before,after}AddLiquidity
- {before,after}RemoveLiquidity
- {before,after}Swap
- {before,after}Donate

The callback logic, may be updated by the hooks dependent on their implementation. However _which_ callbacks are executed on a pool cannot change after pool initialization.

## Repository Structure

All contracts are held within the `v4-core/src` folder.

Note that helper contracts used by tests are held in the `v4-core/src/test` subfolder within the `src` folder. Any new test helper contracts should be added here, but all foundry tests are in the `v4-core/test` folder.

```markdown
src/
----interfaces/
    | IPoolManager.sol
    | ...
----libraries/
    | Position.sol
    | Pool.sol
    | ...
----test
----PoolManager.sol
...
test/
----libraries/
    | Position.t.sol
    | Pool.t.sol
```

## Local deployment and Usage

To utilize the contracts and deploy to a local testnet, you can install the code in your repo with forge:

```markdown
forge install https://github.com/Uniswap/v4-core
```

To integrate with the contracts, the interfaces are available to use:

```solidity

import {IPoolManager} from 'v4-core/contracts/interfaces/IPoolManager.sol';
import {IUnlockCallback} from 'v4-core/contracts/interfaces/callback/IUnlockCallback.sol';

contract MyContract is IUnlockCallback {
    IPoolManager poolManager;

    function doSomethingWithPools() {
        // this function will call `unlockCallback` below
        poolManager.unlock(...);
    }

    function unlockCallback(bytes calldata data) external returns (bytes memory) {
        // disallow arbitrary caller
        if (msg.sender != address(poolManager) revert Unauthorized();
        // perform pool actions
        poolManager.swap(...)
    }
}

error Unauthorized();
```

## License

Uniswap V4 Core is licensed under the Business Source License 1.1 (`BUSL-1.1`), see [BUSL_LICENSE](https://github.com/Uniswap/v4-core/blob/main/licenses/BUSL_LICENSE), and the MIT License (`MIT`), see [MIT_LICENSE](https://github.com/Uniswap/v4-core/blob/main/licenses/MIT_LICENSE). Each file in Uniswap V4 Core states the applicable license type in the header.


================================================
FILE: SECURITY.md
================================================
# Uniswap Labs Security

## Vulnerability Disclosure and Bug Bounty

Bug bounty details can be found in https://uniswap.org/bug-bounty

## Careers

See our available job openings in https://boards.greenhouse.io/uniswaplabs

## Security Team Contact Details

Please contact us through the bug bounty https://uniswap.org/bug-bounty or directly via [security@uniswap.org](mailto:security@uniswap.org)


================================================
FILE: docs/whitepaper/latex/main-zh.tex
================================================
\documentclass[sigconf,nonacm,prologue,table]{acmart}
\usepackage{ctex}

\usepackage{listings}

%% labels
%% sections:    "sec"
%% definitions: "def"
%% equations:   "eq"
%% figures:     "fig"
%% tables:      "tab"

%% packages
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{subcaption}
\usepackage{commath}
\usepackage[utf8]{inputenc}
\usetikzlibrary{positioning, arrows.meta, shapes, calc}
%% \usepackage{tikz}

\pagenumbering{arabic}

%% hide ACM reference
\settopmatter{printacmref=false}

%% hide copyright
\renewcommand\footnotetextcopyrightpermission[1]{}

%% \pagestyle{plain}
\settopmatter{printfolios=true}

\numberwithin{equation}{section}

\theoremstyle{definition}
\newtheorem{definition}{Definition}

\theoremstyle{remark}
\newtheorem*{remark}{Remark}

\captionsetup[subfigure]{
    labelfont=bf,
    textfont=normalfont,
}
\renewcommand{\thesubfigure}{\Roman{subfigure}}

\definecolor{rowA}{gray}{0.9}
\definecolor{rowB}{gray}{0.8}

\newcommand{\rplus}{\mathbb{R}_{\geq 0}}
\newcommand{\rpos}{\mathbb{R}_{>0}}

\begin{document}
\title{Uniswap v4 核心 [草稿]}
\subtitle{June 2023}
\date{June 2023}

\author{Hayden Adams}
\affiliation{}
\email{hayden@uniswap.org}

\author{Moody Salem}
\affiliation{}
\email{moody.salem@gmail.com}

\author{Noah Zinsmeister}
\affiliation{}
\email{noah@uniswap.org}

\author{Sara Reynolds}
\affiliation{}
\email{sara@uniswap.org}

\author{Austin Adams}
\affiliation{}
\email{austin@uniswap.org}

\author{Will Pote}
\affiliation{}
\email{pote@uniswap.org}

\author{Mark Toda}
\affiliation{}
\email{mark@uniswap.org}

\author{Alice Henshaw}
\affiliation{}
\email{alice@uniswap.org}

\author{Emily Williams}
\affiliation{}
\email{emily@uniswap.org}

\author{Dan Robinson}
\affiliation{}
\email{dan@paradigm.xyz}

\titlenote{Uniswap v4 核心白皮书的中文翻译由 WTF Academy 贡献。}

\begin{teaserfigure}
\caption*{
    \hspace{\textwidth}
    }
\end{teaserfigure}

\renewcommand{\shortauthors}{Adams et al.}

\begin{abstract}

\textsc{Uniswap v4}是一种实现在以太坊虚拟机上的非托管自动做市商。通过任意代码Hooks,\textsc{Uniswap v4}提供了可自定义性,允许开发人员在\textsc{Uniswap v3}中引入的集中流动性模型中增加新功能。在\textsc{Uniswap v4}中,任何人都可以创建一个带有指定Hooks的新池,该Hooks可以在预定的池操作之前或之后运行。Hooks可用于实现之前内置于协议中的功能,如预言机,以及以前需要在协议层面独立实现的新功能。\textsc{Uniswap v4}还通过单例模式(singleton)、闪电记账(flash accounting)和对原生ETH的支持,提高了gas效率和开发者体验。
\end{abstract}

\maketitle

\section{介绍} \label{sec:introduction}
\textsc{Uniswap v4}是一种实现在以太坊虚拟机(EVM)上的自动做市商(AMM),用于实现价值的高效交换。与\textsc{Uniswap Protocol}的先前版本一样,\textsc{Uniswap v4}是非托管、不可升级和无需许可的。 \textsc{Uniswap v4}的重点是通过可定制性和gas效率升级的体系结构变化,在\textsc{Uniswap v1}和\textsc{v2}中构建的AMM模型和\textsc{Uniswap v3}中引入的集中流动性模型的基础上进行改进。

\textsc{Uniswap v1} \cite{Adams18}和\textsc{v2} \cite{Adams20}是\textsc{Uniswap Protocol}的前两个版本,分别实现了ERC-20 <> ETH和ERC-20 <> ERC-20的交易,两者都使用了常量乘积做市商(CPMM)模型。 \textsc{Uniswap v3} \cite{Adams21}通过使用在有限价格范围内提供流动性的仓位,提供了更高资本效率的流动性,并引入了多个费用层级。

尽管集中流动性和费用层级增加了流动性提供者的灵活性,并允许实施新的策略,但\textsc{Uniswap v3}不足以支持随着AMM和市场的发展而出现的新功能。

一些功能,例如最初在\textsc{Uniswap v2}中引入的价格预言机,允许集成者利用去中心化的链上定价数据,但这以增加交易者的gas成本为代价,并且对集成者而言不具有可定制性。其他增强功能的想法,包括通过时间加权平均价格做市商(TWAMM) \cite{White2021} 实现的时间加权平均价格订单(TWAP)、波动率预言机、限价订单或动态费用,需要重新实现核心协议,无法由第三方开发者添加到\textsc{Uniswap v3}中。

此外,在以前的\textsc{Uniswap}版本中,部署新的池需要部署新的合约,其成本随着合约字节码的大小而增加。另外,涉及到与多个\textsc{Uniswap}池的交易涉及到多个合约之间的转账和冗余状态更新。自\textsc{Uniswap v2}以来,\textsc{Uniswap}要求ETH被包装成ERC-20,而不是支持原生ETH。这些都带来了gas成本。

在\textsc{Uniswap v4}中,我们通过一些值得注意的功能改进了这一点:
\begin{itemize}
    \item \emph{Hooks}:\textsc{Uniswap v4}允许任何人使用自定义功能部署新的集中流动性池。对于每个池,创建者可以定义一个“Hooks合约”,该合约在调用的生命周期的关键点执行逻辑。这些Hooks也可以管理池的交换费用以及向流动性提供者收取的提款费用。
    \item \emph{单例模式}:\textsc{Uniswap v4}摒弃了先前版本中使用的工厂模型,而是实现了一个包含所有池的单个合约。单例模式降低了池的创建成本和多跳交易(multi-hop trade)的成本。
    \item \emph{闪电记账}:单例使用“闪电记账”机制,要求在锁定结束时池或调用者没有代币欠款。在调用过程中,代币可以用于单例内外的任意数量的操作。通过EIP-1153 \cite{Akhunov2018}中提议的瞬态存储操作码,这种功能将变得高效。闪电记账进一步降低了跨多个池的交易的gas成本,并支持与\textsc{Uniswap v4}的更复杂集成。
    \item \emph{原生ETH}:\textsc{Uniswap v4}恢复了对原生ETH的支持,并支持在\textsc{v4}池中使用原生代币进行配对。ETH交换者和流动性提供者从转账成本更低和去除额外包装成本中受益。
\end{itemize}
%% \ref{sec:liquidity-oracle})。

以下章节详细解释了这些变化,与成就它们的架构变化。

\section{Hooks} 
\label{sec:Hooks}

\emph{Hooks}是在池的执行过程中在指定点执行一些开发者定义的逻辑的外部部署合约。这些Hooks允许集成者创建具有灵活和可定制执行的集中流动性池。

Hooks可以修改池的参数,或添加新特性和功能。可以使用Hooks实现的示例功能包括:
\begin{itemize}
\item 在一段时间通过TWAMM执行大型订单
\item 按指定价格成交的链上限价订单
\item 随波动率变化的动态费用
\item 流动性提供者的内部化MEV分配机制
\item 实现中位数、截断或其他自定义预言机
\end{itemize}

我们预计在未来为特定的Hooks设计撰写独立的白皮书,因为许多Hooks的复杂性与协议本身一样。

\begin{figure*}[ht!]
    \centering
    \scalebox{.65}{
    \begin{tikzpicture}[
            every node/.style = {inner sep = 2ex},
            flow/.style = {thick, arrows = {-To[scale=2]}},
            decision/.style = {
                draw,
                rectangle split,
                rectangle split horizontal,
                rectangle split parts = 2,
                rectangle split draw splits = false,
                align = left,
                rounded corners = 3ex
            },
            block/.style = {
                draw,
                rectangle split,
                rectangle split horizontal,
                rectangle split parts = 2,
                rectangle split draw splits = false,
                align = left
            },
            universal/.style = {draw, diamond, inner sep = .5ex},
        ]

        \node (start) [universal] at (0,0) {开始 swap};

        \node [decision, below=3em of start] (S0) {
            S0.
            \nodepart{two}
            检查 beforeSwap flag
        };

        \node (H1) [block, right=4em of S0] {
            H1.
            \nodepart{two}
            运行 beforeSwap Hook
        };

        \node [block, below=3em of S0] (S1) {
            S1.
            \nodepart{two}
            执行 swap
        };

        \node (S2) [decision, below=3em of S1] {
            S2.
            \nodepart{two}
            检查 afterSwap flag
        };

        \node (H2) [block, right=4em of S2] {
            H2.
            \nodepart{two}
            运行 afterSwap Hook
        };

        \node (stop) [universal, below=3em of S2] {
            结束 swap
        };

        \draw [flow] (start) -- (S0);
        \draw [flow] (S0) -- node[midway, above] {True} (H1);
        \draw [flow] (S0) -- node[midway, right] {False} (S1);
        \draw [flow] (H1) .. controls + (0,-2) .. node[near end, above] {Return} (S1);
        \draw [flow] (S1) -- (S2);
        \draw [flow] (S2) -- node[midway, above] {True} (H2);
        \draw [flow] (S2) -- node[midway, right] {False} (stop);
        \draw [flow] (H2) .. controls + (0,-2.5) .. node[near end, above] {Return} (stop);
    \end{tikzpicture}
    }
    \caption{Swap Hook 流程图}
    \label{fig:swapflow}
\end{figure*}

\subsection{操作Hooks} 
\label{actionhooks}

当有人在\textsc{Uniswap v4}上创建一个池时,他们可以指定一个Hooks合约。该Hooks合约实现了在池的执行过程中池将调用的自定义逻辑。 \textsc{Uniswap v4}目前支持八个此类Hooks回调:

\begin{itemize}
\item beforeInitialize/afterInitialize
\item beforeAddLiquidity/afterAddLiquidity
\item beforeRemoveLiquidity/afterRemoveLiquidity
\item beforeSwap/afterSwap
\item beforeDonate/afterDonate
\end{itemize}

Hooks合约的地址决定了哪些Hooks回调会被执行。这一方法高效且表达力强,并确保即使是可升级的挂钩也遵守某些不变量。创建有效Hooks时有最低准则需要遵守。在图 \ref{fig:swapflow} 中,我们描述了beforeSwap和afterSwapHooks在交换执行流程部分的工作原理。

\subsection{Hooks管理费用} 
\label{hookfees}

\textsc{Uniswap v4}允许对交换和提取流动性收取费用。

交换费用可以是静态的,也可以由Hooks合约动态管理。Hooks合约还可以选择将一定比例的交换费用分配给自己。提款费用不能在池中进行本地设置。要设置提款费用,池创建者必须设置一个Hooks合约来管理该费用,并且,收取的提款费用会支付给Hooks合约。支付给Hooks合约的费用可以由Hooks合约的代码任意分配,包括支付给流动性提供者、交换者、Hooks创建者或任何其他方。

Hooks的功能受创建池时选择的不可变标志(flag)的限制。池创建者可以选择的费用设置有:
\begin{itemize}
    \item 池收取静态费用(以及该费用是多少)还是动态费用
    \item Hooks是否具有收取交换费用的权限
    \item Hooks是否具有收取提款费用的权限
\end{itemize}

治理可以从交换费用或提款费用中收取一定费用,如下面的治理部分所讨论的。 

\section{单例和闪电记账} 
\label{flashaccounting}

\textsc{Uniswap Protocol}的先前版本使用工厂/池模式,其中工厂为新的代币对创建单独的合约。 \textsc{Uniswap v4}使用单例设计模式,所有池都由单个合约管理,使得池的部署成本降低约99\%。

单例设计与\textsc{v4}中的另一个体系结构变化\emph{闪电记账}相辅相成。在\textsc{Uniswap Protocol}的先前版本中,每个操作(例如交换或向池中添加流动性)都以代币转移结束。在\textsc{v4}中,每个操作都会更新一个称为\verb|delta|的内部净余额,仅在锁定结束时进行外部转账。新的\newline \verb|take()|和\verb|settle()|函数分别用于从池中借资金和存入资金到池中。通过要求池或调用者没有代币欠款,确保了池的偿付能力。

闪电记账简化了复杂的池操作,例如原子交换和原子添加。与单例模式结合使用时,它还简化了多跳交易。

在当前的执行环境中,闪电记账架构是昂贵的,因为它要在每次余额变化时进行存储更新。尽管合约保证了内部会计数据实际上从未序列化到存储中,但当超过存储退款上限,用户仍然需要支付费用 \cite{Buterin2021}。但是,由于余额必须在事务结束时为0,因此可以使用瞬态存储实现对这些余额的记账,正如EIP-1153 \cite{Akhunov2018}中所描绘的。

单例和闪电记账使得在多个\textsc{v4}池之间更高效地进行路由成为可能,降低了流动性碎片化的成本。引入Hooks将大大增加池的数量,这个特性会非常有用。

\section{原生ETH} 
\label{nativeeth}

\textsc{Uniswap v4}将原生ETH带回交易对中。虽然\textsc{Uniswap v1}严格将ETH与ERC-20代币配对,但由于实施复杂性和在WETH和ETH配对之间的流动性碎片化的担忧,\textsc{Uniswap v2}中删除了原生ETH配对。单例和闪电记账减轻了这些问题,因此\textsc{Uniswap v4}允许同时支持WETH和ETH配对。

原生ETH转账的gas成本约为ERC-20转账的一半(ETH为21k gas,ERC-20约为40k gas)。目前,\textsc{Uniswap v2}和\textsc{v3}要求绝大多数用户在在Uniswap Protocol上交易之前(之后)将他们的ETH包装(解包装)为WETH,这需要额外的gas。

\section{其他值得注意的功能} 
\label{other}

\subsection{ERC1155记账} 
\textsc{Uniswap v4}将支持通过单例实现的ERC-1155代币的铸造/销毁,用于额外的代币记账。用户现在可以将代币保留在单例合约中,避免ERC-20转入或转出合约的。这一点对于频繁交换者或流动性提供者非常有价值,因为它们会在多个区块或交易中连续使用相同的代币。

\subsection{治理更新} 
\textsc{Uniswap v4}具有两种单独的治理费用机制,交换费用和提款费用,有着不同的机制。首先,与\textsc{Uniswap v3}类似,治理可以选择在特定池上获取特定百分比的交换费用。对于\textsc{v4},如果Hooks最初选择为池打开提款费用,治理还可以获取特定百分比的提款费用。与\textsc{Uniswap v3}不同,治理不控制可允许的费用层级或价格刻度间距。

\subsection{Gas减少}
正如上面所讨论的,\textsc{Uniswap v4}通过闪电记账、单例模式和对原生ETH的支持引入了有意义的gas优化。此外,引入了Hooks使得协议内嵌的价格预言机(在\textsc{Uniswap v2}和\textsc{Uniswap v3}中包含)变得不再必要,这也意味着一些池可以完全放弃预言机,并在每个区块中的第一次池交换中节省约15k gas。

\subsection{donate()}
\verb|donate()|允许用户、集成者和Hooks直接支付给特定范围内的流动性提供者,支付的方式可以是池中的任意一种或两种代币。此功能依赖于费用记账系统以实现高效支付,而费用支付系统仅支持池中的代币。可能的用例包括在TWAMM订单上给范围内的流动性提供者打赏或新类型的费用系统。

\section{总结}
总之,\textsc{Uniswap v4}是一个非托管、不可升级且无需许可的AMM协议。它基于\textsc{Uniswap v3}中引入的集中流动性模型,通过Hooks实现了可定制的池。与Hooks相辅相成的还有其他体系结构变化,如单例合约,它将所有的池状态保存在一个合约中,以及闪电记账,它有效地确保池的偿付能力。其他改进包括对原生ETH的支持,ERC-1155余额记账,新的费用机制以及向范围内流动性提供者捐赠的能力。

\bibliographystyle{ACM-Reference-Format}
\bibliography{main}

\section*{免责声明}

本文仅供一般信息目的。它不构成投资建议或购买或销售任何投资的推荐或招揽,也不应用于评估做出任何投资决策的价值。不应依赖本文提供会计、法律或税务建议或投资建议。本文反映了作者当前的观点,并不代表Uniswap Labs、Paradigm或其关联公司的观点,也不一定反映Uniswap Labs、Paradigm、其关联公司或与之相关的个人的观点。所反映的观点可能会随时更改,而无需进行更新。

\end{document}


================================================
FILE: docs/whitepaper/latex/main.bib
================================================
@online{Adams18,
  author =       "Hayden Adams",
  year =         "2018",
  month =        nov,
  title =        "Uniswap v1 Core",
  url =          "https://hackmd.io/@HaydenAdams/HJ9jLsfTz",
  lastaccessed = "Jun 12, 2023",
}

@online{Adams20,
  author =       "Hayden Adams and Noah Zinsmeister and Dan Robinson",
  year =         "2020",
  month =        mar,
  title =        "Uniswap v2 Core",
  url =          "https://uniswap.org/whitepaper.pdf",
  lastaccessed = "Jun 12, 2023",
}

@online{Adams21,
  author =       "Hayden Adams and Noah Zinsmeister and Moody Salem and River Keefer and Dan Robinson",
  year =         "2021",
  month =        mar,
  title =        "Uniswap v3 Core",
  url =          "https://uniswap.org/whitepaper-v3.pdf",
  lastaccessed = "Jun 12, 2023",
}

@online{White2021,
  author =       "Dave White and Dan Robinson and Hayden Adams",
  year =         "2021",
  month =        jul,
  title =        "TWAMM",
  url =          "https://www.paradigm.xyz/2021/07/twamm",
  lastaccessed = "Jun 12, 2023",
}

@online{Akhunov2018,
  author =       "Alexey Akhunov and Moody Salem",
  year =         "2018",
  month =        jun,
  title =        "EIP-1153: Transient storage opcodes",
  url =          "https://eips.ethereum.org/EIPS/eip-1153",
  lastaccessed = "Jun 12, 2023",
}

@online{Buterin2021,
  author =       "Vitalik Buterin and Martin Swende",
  year =         "2021",
  month =        apr,
  title =        "EIP-3529: Reduction in refunds",
  url =          "https://eips.ethereum.org/EIPS/eip-3529",
  lastaccessed = "Jun 12, 2023",
}

@article{adams2024amm,
  title={am-AMM: An Auction-Managed Automated Market Maker},
  author={Adams, Austin and Moallemi, Ciamac and Reynolds, Sara and Robinson, Dan},
  journal={arXiv preprint arXiv:2403.03367},
  year={2024}
}

@online{riley2023,
  author =       "JT Riley and Dillon and Sara and Vectorized and Neodaoist",
  year =         "2023",
  month =        apr,
  title =        "ERC-6909: Minimal Multi-Token Interface",
  url =          "https://eips.ethereum.org/EIPS/eip-6909",
  lastaccessed = "Aug 26, 2024",
}


================================================
FILE: docs/whitepaper/latex/main.tex
================================================
\documentclass[sigconf,nonacm,prologue,table]{acmart}
\usepackage{listings}

%% labels
%% sections:    "sec"
%% definitions: "def"
%% equations:   "eq"
%% figures:     "fig"
%% tables:      "tab"

%% packages
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{subcaption}
\usepackage{commath}
\usepackage[utf8]{inputenc}
\usetikzlibrary{positioning, arrows.meta, shapes, calc}
%% \usepackage{tikz}

\pagenumbering{arabic}

%% hide ACM reference
\settopmatter{printacmref=false}

%% hide copyright
\renewcommand\footnotetextcopyrightpermission[1]{}

%% \pagestyle{plain}
\settopmatter{printfolios=true}

\numberwithin{equation}{section}

\theoremstyle{definition}
\newtheorem{definition}{Definition}

\theoremstyle{remark}
\newtheorem*{remark}{Remark}

\captionsetup[subfigure]{
    labelfont=bf,
    textfont=normalfont,
}
\renewcommand{\thesubfigure}{\Roman{subfigure}}

\definecolor{rowA}{gray}{0.9}
\definecolor{rowB}{gray}{0.8}

\newcommand{\rplus}{\mathbb{R}_{\geq 0}}
\newcommand{\rpos}{\mathbb{R}_{>0}}

\begin{document}
\title{Uniswap v4 Core}
\subtitle{August 2024}
\date{August 2024}

\author{Hayden Adams}
\affiliation{}
\email{hayden@uniswap.org}

\author{Moody Salem}
\affiliation{}
\email{moody.salem@gmail.com}

\author{Noah Zinsmeister}
\affiliation{}
\email{noah@uniswap.org}

\author{Sara Reynolds}
\affiliation{}
\email{sara@uniswap.org}

\author{Austin Adams}
\affiliation{}
\email{me@aada.ms}

\author{Will Pote}
\affiliation{}
\email{willpote@gmail.com}

\author{Mark Toda}
\affiliation{}
\email{mark@uniswap.org}

\author{Alice Henshaw}
\affiliation{}
\email{alice@uniswap.org}

\author{Emily Williams}
\affiliation{}
\email{emily@uniswap.org}

\author{Dan Robinson}
\affiliation{}
\email{dan@paradigm.xyz}

\begin{teaserfigure}
\caption*{
    \hspace{\textwidth}
    }
\end{teaserfigure}

\renewcommand{\shortauthors}{Adams et al.}

\begin{abstract}

\textsc{Uniswap v4} is a non-custodial automated market maker implemented for the Ethereum Virtual Machine. \textsc{Uniswap v4} offers customizability via arbitrary code hooks, allowing developers to augment the concentrated liquidity model introduced in \textsc{Uniswap v3} with new functionality. In \textsc{Uniswap v4}, anyone can create a new pool with a specified hook, which can run before or after pre-determined pool actions. Hooks can be used to implement features that were previously built into the protocol, like oracles, as well as new features that previously would have required independent implementations of the protocol. \textsc{Uniswap v4} also offers improved gas efficiency and developer experience through a singleton implementation, flash accounting, and support for native ETH.
\end{abstract}

\maketitle

\section{Introduction} \label{sec:introduction}
\textsc{Uniswap v4} is an automated market maker (AMM) facilitating efficient exchange of value on the Ethereum Virtual Machine (EVM). As with previous versions of the \textsc{Uniswap Protocol}, it is non-custodial, non-upgradable, and permissionless. The focus of \textsc{Uniswap v4} is on additional customization for developers and architectural changes for gas efficiency improvements, building on the AMM model built by \textsc{Uniswap v1} and \textsc{v2} and the concentrated liquidity model introduced in \textsc{Uniswap v3}.

\textsc{Uniswap v1} \cite{Adams18} and \textsc{v2} \cite{Adams20} were the first two iterations of the \textsc{Uniswap Protocol}, facilitating ERC-20 <> ETH and ERC-20 <> ERC-20 swaps, respectively, both using a constant product market maker (CPMM) model. \textsc{Uniswap v3} \cite{Adams21} introduced concentrated liquidity, enabling more capital efficient liquidity through positions that provide liquidity within a limited price range, and multiple fee tiers.

While concentrated liquidity and fee tiers increased flexibility for liquidity providers and allowed for new liquidity provision strategies, \textsc{Uniswap v3} lacks flexibility to support new functionalities invented as AMMs and DeFi have evolved.

Some features, like the price oracle originally introduced in \textsc{Uniswap v2} and included in \textsc{Uniswap v3}, allow integrators to utilize decentralized onchain pricing data, at the expense of increased gas costs for swappers and without customizability for integrators. Other possible enhancements, such as time-weighted average price orders (TWAP) through a time-weighted average market maker (TWAMM) \cite{White2021}, volatility oracles, limit orders, or dynamic fees, require reimplementations of the core protocol, and can not be added to \textsc{Uniswap v3} by third-party developers.

Additionally, in previous versions of \textsc{Uniswap}, deployment of new pools involves deploying a new contract—where cost scales with the size of the bytecode—and trades with multiple \textsc{Uniswap} pools involve transfers and redundant state updates across multiple contracts. Additionally since \textsc{Uniswap v2}, \textsc{Uniswap} has required ETH to be wrapped into an ERC-20, rather than supporting native ETH. These design choices came with increased gas costs for end users.

In \textsc{Uniswap v4}, we improve on these inefficiencies through a few notable features:
\begin{itemize}
    \item \emph{Hooks}: \textsc{Uniswap v4} allows anyone to deploy new concentrated liquidity pools with custom functionality. For each pool, the creator can define a “hook contract” that implements logic executed at specific points in a call’s lifecycle. These hooks can also manage the swap fee of the pool dynamically, implement custom curves, and adjust fees charged to liquidity providers and swappers though \emph{Custom Accounting}.
    \item \emph{Singleton}: \textsc{Uniswap v4} moves away from the factory model used in previous versions, instead implementing a single contract that holds all pools. The singleton model reduces the cost of pool creation and multi-hop trades.
    \item \emph{Flash accounting}:  The singleton uses “flash accounting,” which allows a caller to lock the pool and access any of its tokens, as long as no tokens are owed to or from the caller by the end of the lock. This functionality is made efficient by the transient storage opcodes described in EIP-1153 \cite{Akhunov2018}. Flash accounting further reduces the gas cost of trades that cross multiple pools and supports more complex integrations with \textsc{Uniswap v4}.
    \item \emph{Native ETH}: \textsc{Uniswap v4} brings back support for native ETH, with support for pairs with native tokens inside \textsc{v4} pools. ETH swappers and liquidity providers benefit from gas cost reductions from cheaper transfers and removal of additional wrapping costs.
   \item \emph{Custom Accounting}: The singleton supports both augmenting and bypassing the native concentrated liquidity pools through hook-returned deltas, utilizing the singleton as an immutable settlement layer for connected pools. This feature can support use-cases like hook withdrawal fees, wrapping assets, or constant product market maker curves like \textsc{Uniswap v2}.
\end{itemize}

The following sections provide in-depth explanations of these changes and the architectural changes that help make them possible.

\section{Hooks} 
\label{sec:Hooks}

\emph{Hooks} are externally deployed contracts that execute some developer-defined logic at a specified point in a pool’s execution. These hooks allow integrators to create a concentrated liquidity pool with flexible and customizable execution. Optionally, hooks can also return custom deltas that allow the hook to change the behavior of the swap — described in detail in the \emph{Custom Accounting} section (\ref{customaccounting}).

Hooks can modify pool parameters, or add new features and functionality. Example functionalities that could be implemented with hooks include: 
\begin{itemize}
\item Executing large orders over time through TWAMM \cite{White2021}
\item Onchain limit orders that fill at tick prices
\item Volatility-shifting dynamic fees
\item Mechanisms to internalize MEV for liquidity providers \cite{adams2024amm}
\item Median, truncated, or other custom oracle implementations
\item Constant Product Market Makers (Uniswap v2 functionality)
\end{itemize}

\begin{figure*}[ht!]
    \centering
    \scalebox{.7225}{
    \begin{tikzpicture}[
            every node/.style = {inner sep = 2ex},
            flow/.style = {thick, arrows = {-To[scale=2]}},
            decision/.style = {
                draw,
                rectangle split,
                rectangle split horizontal,
                rectangle split parts = 2,
                rectangle split draw splits = false,
                align = left,
                rounded corners = 3ex
            },
            block/.style = {
                draw,
                rectangle split,
                rectangle split horizontal,
                rectangle split parts = 2,
                rectangle split draw splits = false,
                align = left
            },
            universal/.style = {draw, diamond, inner sep = .5ex},
        ]

        \node (start) [universal] at (0,0) {Start swap};

        \node [decision, below=3em of start] (S0) {
            S0.
            \nodepart{two}
            Check beforeSwap flag
        };

        \node (H1) [block, right=4em of S0] {
            H1.
            \nodepart{two}
            Run beforeSwap Hook
        };

        \node [block, below=3em of S0] (S1) {
            S1.
            \nodepart{two}
            Execute swap
        };

        \node (S2) [decision, below=3em of S1] {
            S2.
            \nodepart{two}
            Check afterSwap flag
        };

        \node (H2) [block, right=4em of S2] {
            H2.
            \nodepart{two}
            Run afterSwap Hook
        };

        \node (stop) [universal, below=3em of S2] {
            End swap
        };

        \draw [flow] (start) -- (S0);
        \draw [flow] (S0) -- node[midway, above] {True} (H1);
        \draw [flow] (S0) -- node[midway, right] {False} (S1);
        \draw [flow] (H1) .. controls + (0,-2) .. node[near end, above] {Return} (S1);
        \draw [flow] (S1) -- (S2);
        \draw [flow] (S2) -- node[midway, above] {True} (H2);
        \draw [flow] (S2) -- node[midway, right] {False} (stop);
        \draw [flow] (H2) .. controls + (0,-2.5) .. node[near end, above] {Return} (stop);
    \end{tikzpicture}
    }
    \caption{Swap Hook Flow}
    \label{fig:swapflow}
\end{figure*}

\subsection{Action Hooks} 
\label{actionhooks}

When someone creates a pool on \textsc{Uniswap v4}, they can specify a hook contract. This hook contract implements custom logic that the pool will call out to during its execution. 
\textsc{Uniswap v4} currently supports ten such hook callbacks:

\begin{itemize}
\item beforeInitialize/afterInitialize
\item beforeAddLiquidity/afterAddLiquidity\footnote{Having separate permissions for `beforeAddLiquidity` and `beforeRemoveLiquidity` reflects the difference in security assumptions between those two actions. Hooks that can affect minting but not burning of liquidity are safer for liquidity providers, since they are guaranteed to be able to withdraw their liquidity.}
\item beforeRemoveLiquidity/afterRemoveLiquidity
\item beforeSwap/afterSwap
\item beforeDonate/afterDonate
\end{itemize}

The address of the hook contract determines which of these hook callbacks are executed. This creates a gas efficient and expressive methodology for determining the desired callbacks to execute, and ensures that even upgradeable hooks obey certain invariants. There are minimal requirements for creating a working hook. In Figure \ref{fig:swapflow}, we describe how the beforeSwap and afterSwap hooks work as part of swap execution flow.


\subsection{Hook-managed fees} \label{hookfees}

\textsc{Uniswap v4} allows fees to be taken on swapping by the hook. 

Swap fees can be either static, or dynamically managed by a hook contract. The hook contract can also choose to allocate a percentage of the swap fees to itself. Fees that accrue to hook contracts can be allocated arbitrarily by the hook’s code, including to liquidity providers, swappers, hook creators, or any other party. 

The capabilities of the hook are limited by immutable flags chosen when the pool is created. For example, a pool creator can choose whether a pool has a static fee (and what that fee is) or dynamic fees.

Governance also can take a capped percentage of swap fees, as discussed below in the Governance section (\ref{gov}). 

\section{Singleton and Flash Accounting} \label{flashaccounting}

Previous versions of the \textsc{Uniswap Protocol} use the factory/pool pattern, where the factory creates separate contracts for new token pairs. \textsc{Uniswap v4} uses a \emph{singleton} design pattern where all pools are managed by a single contract, making pool deployment ~99\% cheaper. 

The singleton design complements another architectural change in \textsc{v4}: \emph{flash accounting}. In previous versions of the \textsc{Uniswap Protocol}, most operations (such as swapping or adding liquidity to a pool) ended by transferring tokens. In \textsc{v4}, each operation updates an internal net balance, known as a \verb|delta|, only making external transfers at the end of the lock. The new \verb|take()| and  \verb|settle()| functions can be used to borrow or deposit funds to the pool, respectively. By requiring that no tokens are owed to the pool manager or to the caller by the end of the call, the pool's solvency is enforced. 

Flash accounting simplifies complex pool operations, such as atomic swapping and adding. When combined with the singleton model, it also simplifies multi-hop trades or compound operations like swapping before adding liquidity.

Before the Cancun hard fork, the flash accounting architecture was expensive because it required storage updates at every balance change. Even though the contract guaranteed that internal accounting data is never actually serialized to storage, users would still pay those same costs once the storage refund cap was exceeded \cite{Buterin2021}. But, because balances must be 0 by the end of the transaction, accounting for these balances can be implemented with transient storage, as specified by EIP-1153 \cite{Akhunov2018}.

Together, singleton and flash accounting enable more efficient routing across multiple \textsc{v4} pools, reducing the cost of liquidity fragmentation. This is especially useful given the introduction of hooks, which will greatly increase the number of pools. 

\section{Native ETH} 
\label{nativeeth}

\textsc{Uniswap v4} is bringing back native ETH in trading pairs. While \textsc{Uniswap v1} was strictly ETH paired against ERC-20 tokens, native ETH pairs were removed in \textsc{Uniswap v2} due to implementation complexity and concerns of liquidity fragmentation across WETH and ETH pairs. Singleton and flash accounting mitigate these problems, so \textsc{Uniswap v4} allows for both WETH and ETH pairs.

Native ETH transfers are about half the gas cost of ERC-20 transfers (21k gas for ETH and around 40k gas for ERC-20s). Currently \textsc{Uniswap v2} and \textsc{v3} require the vast majority of users to wrap (unwrap) their ETH to (from) WETH before (after) trading on the Uniswap Protocol, requiring extra gas. According to transaction data, the majority of users start or end their transactions in ETH, adding this additional unneeded complexity.

\section{Custom Accounting} 
\label{customaccounting}

Newly introduced in \textsc{Uniswap v4} is custom accounting - which allows hook developers to alter end user actions utilizing hook-returned deltas, token amounts that are debited/credited to the user and credited/debited to the hook, respectively. This allows hook developers to potentially add withdrawal fees on LP positions, customized LP fee models, or match against some flow, all while ultimately utilizing the internal concentrated liquidity native to \textsc{Uniswap v4}. 

Importantly, hook developers can also forgo the concentrated liquidity model entirely, creating custom curves from the \textsc{v4} swap parameters. This creates interface composability for integrators - allowing the hook to map the swap parameters to their internal logic.

In \textsc{Uniswap v3}, users were required to utilize the concentrated liquidity AMM introduced in the same version. Since their introduction, concentrated liquidity AMMs have become widely used as the base liquidity provision strategy in the decentralized finance markets. While concentrated liquidity is able to support most arbitrary liquidity provision strategies, it may require increased gas overhead to implement specific strategies.

One possible example is a \textsc{Uniswap v2} on \textsc{Uniswap v4} hook, which bypasses the internal concentrated liquidity model entirely - utilizing a constant product market maker fully inside of the hook. Using custom accounting is cheaper than creating a similar strategy in the concentrated liquidity math.

The benefit of custom accounting for developers - compared to rolling a custom AMM - is the \textsc{singleton}, \textsc{flash accounting}, and \textsc{ERC-6909}. These features support cheaper multi-hop swaps, security benefits, and easier integration for flow. Developers should also benefit from a well-audited code-base for the basis of their AMM.

Custom accounting will also support experimentation in liquidity provision strategies, which historically requires the creation of an entirely new AMM. Creating a custom AMM requires significant technical resources and investment, which may not be economically viable for many. 

\section{Other Notable Features} 
\label{other}

\subsection{ERC-6909 Accounting} 
\textsc{Uniswap v4} supports the minting/burning of singleton-implemented ERC-6909 tokens for additional token accounting, described in the ERC-6909 specification \cite{riley2023}. Users can now keep tokens within the singleton and avoid ERC-20 transfers to and from the contract. This will be especially valuable for users and hooks who continually use the same tokens over multiple blocks or transactions, like frequent swappers, liquidity providers, or custom accounting hooks.


\subsection{Governance updates} \label{gov}
Similar to \textsc{Uniswap v3}, \textsc{Uniswap v4} allows governance the ability to take up to a capped percentage of the swap fee on a particular pool, which are additive to LP fees. Unlike in \textsc{Uniswap v3}, governance does not control the permissible fee tiers or tick spacings.

\subsection{Gas reductions}
As discussed above, \textsc{Uniswap v4} introduces meaningful gas optimizations through flash accounting, the singleton model, and support for native ETH. Additionally, the introduction of hooks makes the protocol-enshrined price oracle that was included in \textsc{Uniswap v2} and \textsc{Uniswap v3} unnecessary, which also means base pools forgo the oracle altogether and save around 15k gas on the first swap on a pool in each block. 

\subsection{donate()}
\verb|donate()| allows users, integrators, and hooks to directly pay in-range liquidity providers in either or both of the tokens of the pool. This functionality relies on the fee accounting system to facilitate efficient payments. The fee payment system can only support either of the tokens in the token pair for the pool. Potential use-cases could be tipping in-range liquidity providers on TWAMM orders or new types of fee systems.

\section{Summary}
In summary, \textsc{Uniswap v4} is a non-custodial, non-upgradeable, and permissionless AMM protocol. It builds upon the concentrated liquidity model introduced in \textsc{Uniswap v3} with customizable pools through hooks. Complementary to hooks are other architectural changes like the singleton contract which holds all pool state in one contract, and flash accounting which enforces pool solvency across each pool efficiently. Additionally, hook developers can elect to bypass the concentrated liquidity entirely, utilizing the \textsc{v4} singleton as an arbitrary delta resolver. Some other improvements are native ETH support, ERC-6909 balance accounting, new fee mechanisms, and the ability to donate to in-range liquidity providers.

\bibliographystyle{ACM-Reference-Format}
\bibliography{main}

\section*{Disclaimer}

This paper is for general information purposes only. It does not constitute investment advice or a recommendation or solicitation to buy or sell any investment and should not be used in the evaluation of the merits of making any investment decision. It should not be relied upon for accounting, legal or tax advice or investment recommendations.  This paper reflects current opinions of the authors and is not made on behalf of Uniswap Labs, Paradigm, or their affiliates and does not necessarily reflect the opinions of Uniswap Labs, Paradigm, their affiliates or individuals associated with them. The opinions reflected herein are subject to change without being updated. 

\end{document}
\endinput

================================================
FILE: echidna.config.yml
================================================
#format can be "text" or "json" for different output (human or machine readable)
format: "text"
#checkAsserts checks assertions
checkAsserts: true
#coverage controls coverage guided testing
coverage: false
# #psender is the sender for property transactions; by default intentionally
# #the same as contract deployer
# psender: "0x00a329c0648769a73afac7f9381e08fb43dbea70"
# #prefix is the prefix for Boolean functions that are properties to be checked
# prefix: "echidna_"
# #propMaxGas defines gas cost at which a property fails
# propMaxGas: 8000030
# #testMaxGas is a gas limit; does not cause failure, but terminates sequence
# testMaxGas: 8000030
# #maxGasprice is the maximum gas price
# maxGasprice: 100000000000
# #testLimit is the number of test sequences to run
# testLimit: 50000
# #stopOnFail makes echidna terminate as soon as any property fails and has been shrunk
# stopOnFail: false
# #estimateGas makes echidna perform analysis of maximum gas costs for functions (experimental)
# estimateGas: false
# #seqLen defines how many transactions are in a test sequence
# seqLen: 100
# #shrinkLimit determines how much effort is spent shrinking failing sequences
# shrinkLimit: 5000
# #contractAddr is the address of the contract itself
# contractAddr: "0x00a329c0648769a73afac7f9381e08fb43dbea72"
# #deployer is address of the contract deployer (who often is privileged owner, etc.)
# deployer: "0x00a329c0648769a73afac7f9381e08fb43dbea70"
# #sender is set of addresses transactions may originate from
# sender: ["0x10000", "0x20000", "0x00a329c0648769a73afac7f9381e08fb43dbea70"]
# #balanceAddr is default balance for addresses
# balanceAddr: 0xffffffff
# #balanceContract overrides balanceAddr for the contract address
# balanceContract: 0
# #solcArgs allows special args to solc
# solcArgs: ""
# #solcLibs is solc libraries
# solcLibs: []
# #cryticArgs allows special args to crytic
# cryticArgs: []
# #quiet produces (much) less verbose output
# quiet: false
# #initialize the blockchain with some data
# initialize: null
# #whether or not to use the multi-abi mode of testing
# multi-abi: false
# #benchmarkMode enables benchmark mode
# benchmarkMode: false
# #timeout controls test timeout settings
# timeout: null
# #seed not defined by default, is the random seed
# #seed: 0
# #dictFreq controls how often to use echidna's internal dictionary vs random
# #values
# dictFreq: 0.40
# maxTimeDelay: 604800
# #maximum time between generated txs; default is one week
# maxBlockDelay: 60480
# #maximum number of blocks elapsed between generated txs; default is expected increment in one week
# # timeout:
# #campaign timeout (in seconds)
# # list of methods to filter
# filterFunctions: []
# # by default, blacklist methods in filterFunctions
# filterBlacklist: true
# #directory to save the corpus; by default is disabled
# corpusDir: null
# # constants for corpus mutations (for experimentation only)
# mutConsts: [100, 1, 1]
# # maximum value to send to payable functions
# maxValue: 100000000000000000000 # 100 eth


================================================
FILE: foundry.toml
================================================
[profile.default]
optimizer_runs = 44444444
via_ir = true
ffi = true
fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}, { access = "read", path = "./out"}, {access = "read", path = "./test/bin"}]
solc = "0.8.26"
evm_version = "cancun"
gas_limit = "300000000"
bytecode_hash = "none"
allow_internal_expect_revert = true

[profile.default.fuzz]
runs = 1000
seed = "0x4444"

[profile.pr.fuzz]
runs = 10000

[profile.ci.fuzz]
runs = 100000

[profile.debug]
via_ir = false
optimizer_runs = 200
fuzz.runs = 100

# See more config options https://github.com/foundry-rs/foundry/tree/master/config


================================================
FILE: justfile
================================================

test *args: (test-forge args)
build *args: (build-forge args)
prep *args: fix (test-forge args)


test-forge *args: build-forge
    forge test --isolate {{args}}


build-forge *args: install-forge
    forge build {{args}}

install-forge:
    forge install

fix:
    forge fmt



================================================
FILE: licenses/BUSL_LICENSE
================================================
Business Source License 1.1

License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.

-----------------------------------------------------------------------------

Parameters

Licensor:             Universal Navigation Inc.

Licensed Work:        Uniswap V4 Core
                      The Licensed Work is (c) 2023 Universal Navigation Inc.

Additional Use Grant: Any uses listed and defined at
                      v4-core-license-grants.uniswap.eth

Change Date:          The earlier of 2027-06-15 or a date specified at
                      v4-core-license-date.uniswap.eth

Change License:       MIT License

-----------------------------------------------------------------------------

Terms

The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use.

Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate.

If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work.

All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor.

You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work.

Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work.

This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License).

TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.

MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.

-----------------------------------------------------------------------------

Covenants of Licensor

In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor:

1. To specify as the Change License the GPL Version 2.0 or any later version,    or a license that is compatible with GPL Version 2.0 or a later version,    where "compatible" means that software provided under the Change License can    be included in a program with software provided under GPL Version 2.0 or a    later version. Licensor may specify additional Change Licenses without    limitation.

2. To either: (a) specify an additional grant of rights to use that does not    impose any additional restriction on the right granted in this License, as    the Additional Use Grant; or (b) insert the text "None".

3. To specify a Change Date.

4. Not to modify this License in any other way.

-----------------------------------------------------------------------------

Notice

The Business Source License (this document, or the "License") is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License.


================================================
FILE: licenses/MIT_LICENSE
================================================
Copyright 2023 Universal Navigation Inc. 

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: package.json
================================================
{
  "name": "@uniswap/v4-core",
  "version": "1.0.2",
  "description": "🦄 Core smart contracts of Uniswap v4",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/Uniswap/v4-core.git"
  },
  "license": "BUSL-1.1",
  "keywords": [
    "uniswap",
    "core",
    "v4"
  ],
  "bugs": {
    "url": "https://uniswap.org/bug-bounty"
  },
  "homepage": "https://github.com/Uniswap/v4-core#readme",
  "publishConfig": {
    "access": "public",
    "provenance": true
  }
}


================================================
FILE: remappings.txt
================================================
@ensdomains/=node_modules/@ensdomains/
@openzeppelin/=lib/openzeppelin-contracts/
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
hardhat/=node_modules/hardhat/
solmate/=lib/solmate/


================================================
FILE: snapshots/ClearTest.json
================================================
{
  "clear": "1717"
}

================================================
FILE: snapshots/CustomAccountingTest.json
================================================
{
  "addLiquidity CA fee": "170695",
  "removeLiquidity CA fee": "141199",
  "swap CA custom curve + swap noop": "124402",
  "swap CA fee on unspecified": "154572"
}

================================================
FILE: snapshots/ERC6909ClaimsTest.json
================================================
{
  "ERC6909Claims approve": "46323",
  "ERC6909Claims burn": "29389",
  "ERC6909Claims mint": "46603",
  "ERC6909Claims transfer": "51756",
  "ERC6909Claims transferFrom as operator": "54437",
  "ERC6909Claims transferFrom with approval": "59939",
  "ERC6909Claims transferFrom with infinite approval": "56770"
}

================================================
FILE: snapshots/ExtsloadTest.json
================================================
{
  "sparse external sload": "22164"
}

================================================
FILE: snapshots/ModifyLiquidityTest.json
================================================
{
  "add liquidity to already existing position with salt": "144401",
  "create new liquidity to a position with salt": "292593"
}

================================================
FILE: snapshots/PoolManagerInitializeTest.json
================================================
{
  "initialize": "51532"
}

================================================
FILE: snapshots/PoolManagerTest.json
================================================
{
  "addLiquidity with empty hook": "274012",
  "addLiquidity with native token": "135001",
  "donate gas with 1 token": "106214",
  "donate gas with 2 tokens": "145510",
  "erc20 collect protocol fees": "57728",
  "native collect protocol fees": "59371",
  "poolManager bytecode size": "24009",
  "poolManager initcode hash (without constructor params, as uint256)": "19281018184167079101887460999643277467915809731640262058315305465805214934776",
  "removeLiquidity with empty hook": "130613",
  "removeLiquidity with native token": "112523",
  "simple addLiquidity": "161276",
  "simple addLiquidity second addition same range": "98731",
  "simple removeLiquidity": "85099",
  "simple removeLiquidity some liquidity remains": "92986",
  "simple swap": "123144",
  "simple swap with native": "108434",
  "swap against liquidity": "116527",
  "swap against liquidity with native token": "105569",
  "swap burn 6909 for input": "129285",
  "swap burn native 6909 for input": "118672",
  "swap mint native output as 6909": "139620",
  "swap mint output as 6909": "154985",
  "swap with hooks": "132165"
}

================================================
FILE: snapshots/ProtocolFeesTest.json
================================================
{
  "set protocol fee": "31730"
}

================================================
FILE: snapshots/SkipCallsTest.json
================================================
{
  "swap skips hook call if hook is caller": "206030"
}

================================================
FILE: snapshots/SqrtPriceMathTest.json
================================================
{
  "getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse": "243",
  "getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue": "360",
  "getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse": "229",
  "getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue": "264",
  "getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas": "316",
  "getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas": "539",
  "getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas": "544",
  "getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas": "214"
}

================================================
FILE: snapshots/StateLibraryTest.json
================================================
{
  "extsload getFeeGrowthGlobals": "4774",
  "extsload getFeeGrowthInside": "2375",
  "extsload getLiquidity": "2375",
  "extsload getPositionInfo": "6949",
  "extsload getPositionLiquidity": "2375",
  "extsload getSlot0": "2375",
  "extsload getTickBitmap": "2375",
  "extsload getTickFeeGrowthOutside": "4774",
  "extsload getTickInfo": "6949",
  "extsload getTickLiquidity": "2375"
}

================================================
FILE: snapshots/SwapMathTest.json
================================================
{
  "SwapMath_oneForZero_exactInCapped": "1188",
  "SwapMath_oneForZero_exactInPartial": "1274",
  "SwapMath_oneForZero_exactOutCapped": "1001",
  "SwapMath_oneForZero_exactOutPartial": "1565",
  "SwapMath_zeroForOne_exactInCapped": "1126",
  "SwapMath_zeroForOne_exactInPartial": "1439",
  "SwapMath_zeroForOne_exactOutCapped": "919",
  "SwapMath_zeroForOne_exactOutPartial": "1133"
}

================================================
FILE: snapshots/SyncTest.json
================================================
{
  "getReserves": "5973"
}

================================================
FILE: snapshots/TestBitMath.json
================================================
{
  "BitMathLeastSignificantBitMaxUint128": "648",
  "BitMathLeastSignificantBitMaxUint256": "648",
  "BitMathLeastSignificantBitSmallNumber": "25",
  "BitMathMostSignificantBitMaxUint128": "648",
  "BitMathMostSignificantBitMaxUint256": "648",
  "BitMathMostSignificantBitSmallNumber": "14"
}

================================================
FILE: snapshots/TestDelegateCall.json
================================================
{
  "NoDelegateCall": "51"
}

================================================
FILE: snapshots/TestDynamicFees.json
================================================
{
  "swap with dynamic fee": "139153",
  "update dynamic fee in before swap": "147743"
}

================================================
FILE: snapshots/TestDynamicReturnFees.json
================================================
{
  "swap with return dynamic fee": "145475"
}

================================================
FILE: snapshots/TickBitmapTest.json
================================================
{
  "flipTick_flippingATickThatResultsInDeletingAWord": "5109",
  "flipTick_flippingFirstTickInWordToInitialized": "22209",
  "flipTick_flippingSecondTickInWordToInitialized": "5178",
  "nextInitializedTickWithinOneWord_lteFalse_forEntireWord": "2263",
  "nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary": "2252",
  "nextInitializedTickWithinOneWord_lteFalse_onBoundary": "2281",
  "nextInitializedTickWithinOneWord_lteTrue_forEntireWord": "2258",
  "nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary": "2242",
  "nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas": "2287"
}

================================================
FILE: snapshots/TickMathTestTest.json
================================================
{
  "TickMathGetSqrtPriceAtTick": "72349",
  "TickMathGetTickAtSqrtPrice": "195022"
}

================================================
FILE: snapshots/TickTest.json
================================================
{
  "tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing": "25",
  "tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing": "25",
  "tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing": "25"
}

================================================
FILE: src/ERC6909.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC6909Claims} from "./interfaces/external/IERC6909Claims.sol";

/// @notice Minimalist and gas efficient standard ERC6909 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC6909.sol)
/// @dev Copied from the commit at 4b47a19038b798b4a33d9749d25e570443520647
/// @dev This contract has been modified from the implementation at the above link.
abstract contract ERC6909 is IERC6909Claims {
    /*//////////////////////////////////////////////////////////////
                             ERC6909 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address owner => mapping(address operator => bool isOperator)) public isOperator;

    mapping(address owner => mapping(uint256 id => uint256 balance)) public balanceOf;

    mapping(address owner => mapping(address spender => mapping(uint256 id => uint256 amount))) public allowance;

    /*//////////////////////////////////////////////////////////////
                              ERC6909 LOGIC
    //////////////////////////////////////////////////////////////*/

    function transfer(address receiver, uint256 id, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender][id] -= amount;

        balanceOf[receiver][id] += amount;

        emit Transfer(msg.sender, msg.sender, receiver, id, amount);

        return true;
    }

    function transferFrom(address sender, address receiver, uint256 id, uint256 amount) public virtual returns (bool) {
        if (msg.sender != sender && !isOperator[sender][msg.sender]) {
            uint256 allowed = allowance[sender][msg.sender][id];
            if (allowed != type(uint256).max) allowance[sender][msg.sender][id] = allowed - amount;
        }

        balanceOf[sender][id] -= amount;

        balanceOf[receiver][id] += amount;

        emit Transfer(msg.sender, sender, receiver, id, amount);

        return true;
    }

    function approve(address spender, uint256 id, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender][id] = amount;

        emit Approval(msg.sender, spender, id, amount);

        return true;
    }

    function setOperator(address operator, bool approved) public virtual returns (bool) {
        isOperator[msg.sender][operator] = approved;

        emit OperatorSet(msg.sender, operator, approved);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165
            || interfaceId == 0x0f632fb3; // ERC165 Interface ID for ERC6909
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address receiver, uint256 id, uint256 amount) internal virtual {
        balanceOf[receiver][id] += amount;

        emit Transfer(msg.sender, address(0), receiver, id, amount);
    }

    function _burn(address sender, uint256 id, uint256 amount) internal virtual {
        balanceOf[sender][id] -= amount;

        emit Transfer(msg.sender, sender, address(0), id, amount);
    }
}


================================================
FILE: src/ERC6909Claims.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ERC6909} from "./ERC6909.sol";

/// @notice ERC6909Claims inherits ERC6909 and implements an internal burnFrom function
abstract contract ERC6909Claims is ERC6909 {
    /// @notice Burn `amount` tokens of token type `id` from `from`.
    /// @dev if sender is not `from` they must be an operator or have sufficient allowance.
    /// @param from The address to burn tokens from.
    /// @param id The currency to burn.
    /// @param amount The amount to burn.
    function _burnFrom(address from, uint256 id, uint256 amount) internal {
        address sender = msg.sender;
        if (from != sender && !isOperator[from][sender]) {
            uint256 senderAllowance = allowance[from][sender][id];
            if (senderAllowance != type(uint256).max) {
                allowance[from][sender][id] = senderAllowance - amount;
            }
        }
        _burn(from, id, amount);
    }
}


================================================
FILE: src/Extsload.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IExtsload} from "./interfaces/IExtsload.sol";

/// @notice Enables public storage access for efficient state retrieval by external contracts.
/// https://eips.ethereum.org/EIPS/eip-2330#rationale
abstract contract Extsload is IExtsload {
    /// @inheritdoc IExtsload
    function extsload(bytes32 slot) external view returns (bytes32) {
        assembly ("memory-safe") {
            mstore(0, sload(slot))
            return(0, 0x20)
        }
    }

    /// @inheritdoc IExtsload
    function extsload(bytes32 startSlot, uint256 nSlots) external view returns (bytes32[] memory) {
        assembly ("memory-safe") {
            let memptr := mload(0x40)
            let start := memptr
            // A left bit-shift of 5 is equivalent to multiplying by 32 but costs less gas.
            let length := shl(5, nSlots)
            // The abi offset of dynamic array in the returndata is 32.
            mstore(memptr, 0x20)
            // Store the length of the array returned
            mstore(add(memptr, 0x20), nSlots)
            // update memptr to the first location to hold a result
            memptr := add(memptr, 0x40)
            let end := add(memptr, length)
            for {} 1 {} {
                mstore(memptr, sload(startSlot))
                memptr := add(memptr, 0x20)
                startSlot := add(startSlot, 1)
                if iszero(lt(memptr, end)) { break }
            }
            return(start, sub(end, start))
        }
    }

    /// @inheritdoc IExtsload
    function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory) {
        assembly ("memory-safe") {
            let memptr := mload(0x40)
            let start := memptr
            // for abi encoding the response - the array will be found at 0x20
            mstore(memptr, 0x20)
            // next we store the length of the return array
            mstore(add(memptr, 0x20), slots.length)
            // update memptr to the first location to hold an array entry
            memptr := add(memptr, 0x40)
            // A left bit-shift of 5 is equivalent to multiplying by 32 but costs less gas.
            let end := add(memptr, shl(5, slots.length))
            let calldataptr := slots.offset
            for {} 1 {} {
                mstore(memptr, sload(calldataload(calldataptr)))
                memptr := add(memptr, 0x20)
                calldataptr := add(calldataptr, 0x20)
                if iszero(lt(memptr, end)) { break }
            }
            return(start, sub(end, start))
        }
    }
}


================================================
FILE: src/Exttload.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IExttload} from "./interfaces/IExttload.sol";

/// @notice Enables public transient storage access for efficient state retrieval by external contracts.
/// https://eips.ethereum.org/EIPS/eip-2330#rationale
abstract contract Exttload is IExttload {
    /// @inheritdoc IExttload
    function exttload(bytes32 slot) external view returns (bytes32) {
        assembly ("memory-safe") {
            mstore(0, tload(slot))
            return(0, 0x20)
        }
    }

    /// @inheritdoc IExttload
    function exttload(bytes32[] calldata slots) external view returns (bytes32[] memory) {
        assembly ("memory-safe") {
            let memptr := mload(0x40)
            let start := memptr
            // for abi encoding the response - the array will be found at 0x20
            mstore(memptr, 0x20)
            // next we store the length of the return array
            mstore(add(memptr, 0x20), slots.length)
            // update memptr to the first location to hold an array entry
            memptr := add(memptr, 0x40)
            // A left bit-shift of 5 is equivalent to multiplying by 32 but costs less gas.
            let end := add(memptr, shl(5, slots.length))
            let calldataptr := slots.offset
            for {} 1 {} {
                mstore(memptr, tload(calldataload(calldataptr)))
                memptr := add(memptr, 0x20)
                calldataptr := add(calldataptr, 0x20)
                if iszero(lt(memptr, end)) { break }
            }
            return(start, sub(end, start))
        }
    }
}


================================================
FILE: src/NoDelegateCall.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {CustomRevert} from "./libraries/CustomRevert.sol";

/// @title Prevents delegatecall to a contract
/// @notice Base contract that provides a modifier for preventing delegatecall to methods in a child contract
abstract contract NoDelegateCall {
    using CustomRevert for bytes4;

    error DelegateCallNotAllowed();

    /// @dev The original address of this contract
    address private immutable original;

    constructor() {
        // Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode.
        // In other words, this variable won't change when it's checked at runtime.
        original = address(this);
    }

    /// @dev Private method is used instead of inlining into modifier because modifiers are copied into each method,
    ///     and the use of immutable means the address bytes are copied in every place the modifier is used.
    function checkNotDelegateCall() private view {
        if (address(this) != original) DelegateCallNotAllowed.selector.revertWith();
    }

    /// @notice Prevents delegatecall into the modified method
    modifier noDelegateCall() {
        checkNotDelegateCall();
        _;
    }
}


================================================
FILE: src/PoolManager.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

import {Hooks} from "./libraries/Hooks.sol";
import {Pool} from "./libraries/Pool.sol";
import {SafeCast} from "./libraries/SafeCast.sol";
import {Position} from "./libraries/Position.sol";
import {LPFeeLibrary} from "./libraries/LPFeeLibrary.sol";
import {Currency, CurrencyLibrary} from "./types/Currency.sol";
import {PoolKey} from "./types/PoolKey.sol";
import {TickMath} from "./libraries/TickMath.sol";
import {NoDelegateCall} from "./NoDelegateCall.sol";
import {IHooks} from "./interfaces/IHooks.sol";
import {IPoolManager} from "./interfaces/IPoolManager.sol";
import {IUnlockCallback} from "./interfaces/callback/IUnlockCallback.sol";
import {ProtocolFees} from "./ProtocolFees.sol";
import {ERC6909Claims} from "./ERC6909Claims.sol";
import {PoolId} from "./types/PoolId.sol";
import {ModifyLiquidityParams, SwapParams} from "./types/PoolOperation.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "./types/BalanceDelta.sol";
import {BeforeSwapDelta} from "./types/BeforeSwapDelta.sol";
import {Lock} from "./libraries/Lock.sol";
import {CurrencyDelta} from "./libraries/CurrencyDelta.sol";
import {NonzeroDeltaCount} from "./libraries/NonzeroDeltaCount.sol";
import {CurrencyReserves} from "./libraries/CurrencyReserves.sol";
import {Extsload} from "./Extsload.sol";
import {Exttload} from "./Exttload.sol";
import {CustomRevert} from "./libraries/CustomRevert.sol";

//  4
//   44
//     444
//       444                   4444
//        4444            4444     4444
//          4444          4444444    4444                           4
//            4444        44444444     4444                         4
//             44444       4444444       4444444444444444       444444
//           4   44444     44444444       444444444444444444444    4444
//            4    44444    4444444         4444444444444444444444  44444
//             4     444444  4444444         44444444444444444444444 44  4
//              44     44444   444444          444444444444444444444 4     4
//               44      44444   44444           4444444444444444444 4 44
//                44       4444     44             444444444444444     444
//                444     4444                        4444444
//               4444444444444                     44                      4
//              44444444444                        444444     444444444    44
//             444444           4444               4444     4444444444      44
//             4444           44    44              4      44444444444
//            44444          444444444                   444444444444    4444
//            44444          44444444                  4444  44444444    444444
//            44444                                  4444   444444444    44444444
//           44444                                 4444     44444444    4444444444
//          44444                                4444      444444444   444444444444
//         44444                               4444        44444444    444444444444
//       4444444                             4444          44444444         4444444
//      4444444                            44444          44444444          4444444
//     44444444                           44444444444444444444444444444        4444
//   4444444444                           44444444444444444444444444444         444
//  444444444444                         444444444444444444444444444444   444   444
//  44444444444444                                      444444444         44444
// 44444  44444444444         444                       44444444         444444
// 44444  4444444444      4444444444      444444        44444444    444444444444
//  444444444444444      4444  444444    4444444       44444444     444444444444
//  444444444444444     444    444444     444444       44444444      44444444444
//   4444444444444     4444   444444        4444                      4444444444
//    444444444444      4     44444         4444                       444444444
//     44444444444           444444         444                        44444444
//      44444444            444444         4444                         4444444
//                          44444          444                          44444
//                          44444         444      4                    4444
//                          44444        444      44                   444
//                          44444       444      4444
//                           444444  44444        444
//                             444444444           444
//                                                  44444   444
//                                                      444

/// @title PoolManager
/// @notice Holds the state for all pools
contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claims, Extsload, Exttload {
    using SafeCast for *;
    using Pool for *;
    using Hooks for IHooks;
    using CurrencyDelta for Currency;
    using LPFeeLibrary for uint24;
    using CurrencyReserves for Currency;
    using CustomRevert for bytes4;

    int24 private constant MAX_TICK_SPACING = TickMath.MAX_TICK_SPACING;

    int24 private constant MIN_TICK_SPACING = TickMath.MIN_TICK_SPACING;

    mapping(PoolId id => Pool.State) internal _pools;

    /// @notice This will revert if the contract is locked
    modifier onlyWhenUnlocked() {
        if (!Lock.isUnlocked()) ManagerLocked.selector.revertWith();
        _;
    }

    constructor(address initialOwner) ProtocolFees(initialOwner) {}

    /// @inheritdoc IPoolManager
    function unlock(bytes calldata data) external override returns (bytes memory result) {
        if (Lock.isUnlocked()) AlreadyUnlocked.selector.revertWith();

        Lock.unlock();

        // the caller does everything in this callback, including paying what they owe via calls to settle
        result = IUnlockCallback(msg.sender).unlockCallback(data);

        if (NonzeroDeltaCount.read() != 0) CurrencyNotSettled.selector.revertWith();
        Lock.lock();
    }

    /// @inheritdoc IPoolManager
    function initialize(PoolKey memory key, uint160 sqrtPriceX96) external noDelegateCall returns (int24 tick) {
        // see TickBitmap.sol for overflow conditions that can arise from tick spacing being too large
        if (key.tickSpacing > MAX_TICK_SPACING) TickSpacingTooLarge.selector.revertWith(key.tickSpacing);
        if (key.tickSpacing < MIN_TICK_SPACING) TickSpacingTooSmall.selector.revertWith(key.tickSpacing);
        if (key.currency0 >= key.currency1) {
            CurrenciesOutOfOrderOrEqual.selector.revertWith(
                Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)
            );
        }
        if (!key.hooks.isValidHookAddress(key.fee)) Hooks.HookAddressNotValid.selector.revertWith(address(key.hooks));

        uint24 lpFee = key.fee.getInitialLPFee();

        key.hooks.beforeInitialize(key, sqrtPriceX96);

        PoolId id = key.toId();

        tick = _pools[id].initialize(sqrtPriceX96, lpFee);

        // event is emitted before the afterInitialize call to ensure events are always emitted in order
        // emit all details of a pool key. poolkeys are not saved in storage and must always be provided by the caller
        // the key's fee may be a static fee or a sentinel to denote a dynamic fee.
        emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks, sqrtPriceX96, tick);

        key.hooks.afterInitialize(key, sqrtPriceX96, tick);
    }

    /// @inheritdoc IPoolManager
    function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData)
        external
        onlyWhenUnlocked
        noDelegateCall
        returns (BalanceDelta callerDelta, BalanceDelta feesAccrued)
    {
        PoolId id = key.toId();
        {
            Pool.State storage pool = _getPool(id);
            pool.checkPoolInitialized();

            key.hooks.beforeModifyLiquidity(key, params, hookData);

            BalanceDelta principalDelta;
            (principalDelta, feesAccrued) = pool.modifyLiquidity(
                Pool.ModifyLiquidityParams({
                    owner: msg.sender,
                    tickLower: params.tickLower,
                    tickUpper: params.tickUpper,
                    liquidityDelta: params.liquidityDelta.toInt128(),
                    tickSpacing: key.tickSpacing,
                    salt: params.salt
                })
            );

            // fee delta and principal delta are both accrued to the caller
            callerDelta = principalDelta + feesAccrued;
        }

        // event is emitted before the afterModifyLiquidity call to ensure events are always emitted in order
        emit ModifyLiquidity(id, msg.sender, params.tickLower, params.tickUpper, params.liquidityDelta, params.salt);

        BalanceDelta hookDelta;
        (callerDelta, hookDelta) = key.hooks.afterModifyLiquidity(key, params, callerDelta, feesAccrued, hookData);

        // if the hook doesn't have the flag to be able to return deltas, hookDelta will always be 0
        if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) _accountPoolBalanceDelta(key, hookDelta, address(key.hooks));

        _accountPoolBalanceDelta(key, callerDelta, msg.sender);
    }

    /// @inheritdoc IPoolManager
    function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData)
        external
        onlyWhenUnlocked
        noDelegateCall
        returns (BalanceDelta swapDelta)
    {
        if (params.amountSpecified == 0) SwapAmountCannotBeZero.selector.revertWith();
        PoolId id = key.toId();
        Pool.State storage pool = _getPool(id);
        pool.checkPoolInitialized();

        BeforeSwapDelta beforeSwapDelta;
        {
            int256 amountToSwap;
            uint24 lpFeeOverride;
            (amountToSwap, beforeSwapDelta, lpFeeOverride) = key.hooks.beforeSwap(key, params, hookData);

            // execute swap, account protocol fees, and emit swap event
            // _swap is needed to avoid stack too deep error
            swapDelta = _swap(
                pool,
                id,
                Pool.SwapParams({
                    tickSpacing: key.tickSpacing,
                    zeroForOne: params.zeroForOne,
                    amountSpecified: amountToSwap,
                    sqrtPriceLimitX96: params.sqrtPriceLimitX96,
                    lpFeeOverride: lpFeeOverride
                }),
                params.zeroForOne ? key.currency0 : key.currency1 // input token
            );
        }

        BalanceDelta hookDelta;
        (swapDelta, hookDelta) = key.hooks.afterSwap(key, params, swapDelta, hookData, beforeSwapDelta);

        // if the hook doesn't have the flag to be able to return deltas, hookDelta will always be 0
        if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) _accountPoolBalanceDelta(key, hookDelta, address(key.hooks));

        _accountPoolBalanceDelta(key, swapDelta, msg.sender);
    }

    /// @notice Internal swap function to execute a swap, take protocol fees on input token, and emit the swap event
    function _swap(Pool.State storage pool, PoolId id, Pool.SwapParams memory params, Currency inputCurrency)
        internal
        returns (BalanceDelta)
    {
        (BalanceDelta delta, uint256 amountToProtocol, uint24 swapFee, Pool.SwapResult memory result) =
            pool.swap(params);

        // the fee is on the input currency
        if (amountToProtocol > 0) _updateProtocolFees(inputCurrency, amountToProtocol);

        // event is emitted before the afterSwap call to ensure events are always emitted in order
        emit Swap(
            id,
            msg.sender,
            delta.amount0(),
            delta.amount1(),
            result.sqrtPriceX96,
            result.liquidity,
            result.tick,
            swapFee
        );

        return delta;
    }

    /// @inheritdoc IPoolManager
    function donate(PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData)
        external
        onlyWhenUnlocked
        noDelegateCall
        returns (BalanceDelta delta)
    {
        PoolId poolId = key.toId();
        Pool.State storage pool = _getPool(poolId);
        pool.checkPoolInitialized();

        key.hooks.beforeDonate(key, amount0, amount1, hookData);

        delta = pool.donate(amount0, amount1);

        _accountPoolBalanceDelta(key, delta, msg.sender);

        // event is emitted before the afterDonate call to ensure events are always emitted in order
        emit Donate(poolId, msg.sender, amount0, amount1);

        key.hooks.afterDonate(key, amount0, amount1, hookData);
    }

    /// @inheritdoc IPoolManager
    function sync(Currency currency) external {
        // address(0) is used for the native currency
        if (currency.isAddressZero()) {
            // The reserves balance is not used for native settling, so we only need to reset the currency.
            CurrencyReserves.resetCurrency();
        } else {
            uint256 balance = currency.balanceOfSelf();
            CurrencyReserves.syncCurrencyAndReserves(currency, balance);
        }
    }

    /// @inheritdoc IPoolManager
    function take(Currency currency, address to, uint256 amount) external onlyWhenUnlocked {
        unchecked {
            // negation must be safe as amount is not negative
            _accountDelta(currency, -(amount.toInt128()), msg.sender);
            currency.transfer(to, amount);
        }
    }

    /// @inheritdoc IPoolManager
    function settle() external payable onlyWhenUnlocked returns (uint256) {
        return _settle(msg.sender);
    }

    /// @inheritdoc IPoolManager
    function settleFor(address recipient) external payable onlyWhenUnlocked returns (uint256) {
        return _settle(recipient);
    }

    /// @inheritdoc IPoolManager
    function clear(Currency currency, uint256 amount) external onlyWhenUnlocked {
        int256 current = currency.getDelta(msg.sender);
        // Because input is `uint256`, only positive amounts can be cleared.
        int128 amountDelta = amount.toInt128();
        if (amountDelta != current) MustClearExactPositiveDelta.selector.revertWith();
        // negation must be safe as amountDelta is positive
        unchecked {
            _accountDelta(currency, -(amountDelta), msg.sender);
        }
    }

    /// @inheritdoc IPoolManager
    function mint(address to, uint256 id, uint256 amount) external onlyWhenUnlocked {
        unchecked {
            Currency currency = CurrencyLibrary.fromId(id);
            // negation must be safe as amount is not negative
            _accountDelta(currency, -(amount.toInt128()), msg.sender);
            _mint(to, currency.toId(), amount);
        }
    }

    /// @inheritdoc IPoolManager
    function burn(address from, uint256 id, uint256 amount) external onlyWhenUnlocked {
        Currency currency = CurrencyLibrary.fromId(id);
        _accountDelta(currency, amount.toInt128(), msg.sender);
        _burnFrom(from, currency.toId(), amount);
    }

    /// @inheritdoc IPoolManager
    function updateDynamicLPFee(PoolKey memory key, uint24 newDynamicLPFee) external {
        if (!key.fee.isDynamicFee() || msg.sender != address(key.hooks)) {
            UnauthorizedDynamicLPFeeUpdate.selector.revertWith();
        }
        newDynamicLPFee.validate();
        PoolId id = key.toId();
        _pools[id].setLPFee(newDynamicLPFee);
    }

    // if settling native, integrators should still call `sync` first to avoid DoS attack vectors
    function _settle(address recipient) internal returns (uint256 paid) {
        Currency currency = CurrencyReserves.getSyncedCurrency();

        // if not previously synced, or the syncedCurrency slot has been reset, expects native currency to be settled
        if (currency.isAddressZero()) {
            paid = msg.value;
        } else {
            if (msg.value > 0) NonzeroNativeValue.selector.revertWith();
            // Reserves are guaranteed to be set because currency and reserves are always set together
            uint256 reservesBefore = CurrencyReserves.getSyncedReserves();
            uint256 reservesNow = currency.balanceOfSelf();
            paid = reservesNow - reservesBefore;
            CurrencyReserves.resetCurrency();
        }

        _accountDelta(currency, paid.toInt128(), recipient);
    }

    /// @notice Adds a balance delta in a currency for a target address
    function _accountDelta(Currency currency, int128 delta, address target) internal {
        if (delta == 0) return;

        (int256 previous, int256 next) = currency.applyDelta(target, delta);

        if (next == 0) {
            NonzeroDeltaCount.decrement();
        } else if (previous == 0) {
            NonzeroDeltaCount.increment();
        }
    }

    /// @notice Accounts the deltas of 2 currencies to a target address
    function _accountPoolBalanceDelta(PoolKey memory key, BalanceDelta delta, address target) internal {
        _accountDelta(key.currency0, delta.amount0(), target);
        _accountDelta(key.currency1, delta.amount1(), target);
    }

    /// @notice Implementation of the _getPool function defined in ProtocolFees
    function _getPool(PoolId id) internal view override returns (Pool.State storage) {
        return _pools[id];
    }

    /// @notice Implementation of the _isUnlocked function defined in ProtocolFees
    function _isUnlocked() internal view override returns (bool) {
        return Lock.isUnlocked();
    }
}


================================================
FILE: src/ProtocolFees.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Currency} from "./types/Currency.sol";
import {CurrencyReserves} from "./libraries/CurrencyReserves.sol";
import {IProtocolFees} from "./interfaces/IProtocolFees.sol";
import {PoolKey} from "./types/PoolKey.sol";
import {ProtocolFeeLibrary} from "./libraries/ProtocolFeeLibrary.sol";
import {Owned} from "solmate/src/auth/Owned.sol";
import {PoolId} from "./types/PoolId.sol";
import {Pool} from "./libraries/Pool.sol";
import {CustomRevert} from "./libraries/CustomRevert.sol";

/// @notice Contract handling the setting and accrual of protocol fees
abstract contract ProtocolFees is IProtocolFees, Owned {
    using ProtocolFeeLibrary for uint24;
    using Pool for Pool.State;
    using CustomRevert for bytes4;

    /// @inheritdoc IProtocolFees
    mapping(Currency currency => uint256 amount) public protocolFeesAccrued;

    /// @inheritdoc IProtocolFees
    address public protocolFeeController;

    constructor(address initialOwner) Owned(initialOwner) {}

    /// @inheritdoc IProtocolFees
    function setProtocolFeeController(address controller) external onlyOwner {
        protocolFeeController = controller;
        emit ProtocolFeeControllerUpdated(controller);
    }

    /// @inheritdoc IProtocolFees
    function setProtocolFee(PoolKey memory key, uint24 newProtocolFee) external {
        if (msg.sender != protocolFeeController) InvalidCaller.selector.revertWith();
        if (!newProtocolFee.isValidProtocolFee()) ProtocolFeeTooLarge.selector.revertWith(newProtocolFee);
        PoolId id = key.toId();
        _getPool(id).setProtocolFee(newProtocolFee);
        emit ProtocolFeeUpdated(id, newProtocolFee);
    }

    /// @inheritdoc IProtocolFees
    function collectProtocolFees(address recipient, Currency currency, uint256 amount)
        external
        returns (uint256 amountCollected)
    {
        if (msg.sender != protocolFeeController) InvalidCaller.selector.revertWith();
        if (!currency.isAddressZero() && CurrencyReserves.getSyncedCurrency() == currency) {
            // prevent transfer between the sync and settle balanceOfs (native settle uses msg.value)
            ProtocolFeeCurrencySynced.selector.revertWith();
        }

        amountCollected = (amount == 0) ? protocolFeesAccrued[currency] : amount;
        protocolFeesAccrued[currency] -= amountCollected;
        currency.transfer(recipient, amountCollected);
    }

    /// @dev abstract internal function to allow the ProtocolFees contract to access the lock
    function _isUnlocked() internal virtual returns (bool);

    /// @dev abstract internal function to allow the ProtocolFees contract to access pool state
    /// @dev this is overridden in PoolManager.sol to give access to the _pools mapping
    function _getPool(PoolId id) internal virtual returns (Pool.State storage);

    function _updateProtocolFees(Currency currency, uint256 amount) internal {
        unchecked {
            protocolFeesAccrued[currency] += amount;
        }
    }
}


================================================
FILE: src/interfaces/IExtsload.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Interface for functions to access any storage slot in a contract
interface IExtsload {
    /// @notice Called by external contracts to access granular pool state
    /// @param slot Key of slot to sload
    /// @return value The value of the slot as bytes32
    function extsload(bytes32 slot) external view returns (bytes32 value);

    /// @notice Called by external contracts to access granular pool state
    /// @param startSlot Key of slot to start sloading from
    /// @param nSlots Number of slots to load into return value
    /// @return values List of loaded values.
    function extsload(bytes32 startSlot, uint256 nSlots) external view returns (bytes32[] memory values);

    /// @notice Called by external contracts to access sparse pool state
    /// @param slots List of slots to SLOAD from.
    /// @return values List of loaded values.
    function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory values);
}


================================================
FILE: src/interfaces/IExttload.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @notice Interface for functions to access any transient storage slot in a contract
interface IExttload {
    /// @notice Called by external contracts to access transient storage of the contract
    /// @param slot Key of slot to tload
    /// @return value The value of the slot as bytes32
    function exttload(bytes32 slot) external view returns (bytes32 value);

    /// @notice Called by external contracts to access sparse transient pool state
    /// @param slots List of slots to tload
    /// @return values List of loaded values
    function exttload(bytes32[] calldata slots) external view returns (bytes32[] memory values);
}


================================================
FILE: src/interfaces/IHooks.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {PoolKey} from "../types/PoolKey.sol";
import {BalanceDelta} from "../types/BalanceDelta.sol";
import {ModifyLiquidityParams, SwapParams} from "../types/PoolOperation.sol";
import {BeforeSwapDelta} from "../types/BeforeSwapDelta.sol";

/// @notice V4 decides whether to invoke specific hooks by inspecting the least significant bits
/// of the address that the hooks contract is deployed to.
/// For example, a hooks contract deployed to address: 0x0000000000000000000000000000000000002400
/// has the lowest bits '10 0100 0000 0000' which would cause the 'before initialize' and 'after add liquidity' hooks to be used.
/// See the Hooks library for the full spec.
/// @dev Should only be callable by the v4 PoolManager.
interface IHooks {
    /// @notice The hook called before the state of a pool is initialized
    /// @param sender The initial msg.sender for the initialize call
    /// @param key The key for the pool being initialized
    /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
    /// @return bytes4 The function selector for the hook
    function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96) external returns (bytes4);

    /// @notice The hook called after the state of a pool is initialized
    /// @param sender The initial msg.sender for the initialize call
    /// @param key The key for the pool being initialized
    /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
    /// @param tick The current tick after the state of a pool is initialized
    /// @return bytes4 The function selector for the hook
    function afterInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, int24 tick)
        external
        returns (bytes4);

    /// @notice The hook called before liquidity is added
    /// @param sender The initial msg.sender for the add liquidity call
    /// @param key The key for the pool
    /// @param params The parameters for adding liquidity
    /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be passed on to the hook
    /// @return bytes4 The function selector for the hook
    function beforeAddLiquidity(
        address sender,
        PoolKey calldata key,
        ModifyLiquidityParams calldata params,
        bytes calldata hookData
    ) external returns (bytes4);

    /// @notice The hook called after liquidity is added
    /// @param sender The initial msg.sender for the add liquidity call
    /// @param key The key for the pool
    /// @param params The parameters for adding liquidity
    /// @param delta The caller's balance delta after adding liquidity; the sum of principal delta, fees accrued, and hook delta
    /// @param feesAccrued The fees accrued since the last time fees were collected from this position
    /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be passed on to the hook
    /// @return bytes4 The function selector for the hook
    /// @return BalanceDelta The hook's delta in token0 and token1. Positive: the hook is owed/took currency, negative: the hook owes/sent currency
    function afterAddLiquidity(
        address sender,
        PoolKey calldata key,
        ModifyLiquidityParams calldata params,
        BalanceDelta delta,
        BalanceDelta feesAccrued,
        bytes calldata hookData
    ) external returns (bytes4, BalanceDelta);

    /// @notice The hook called before liquidity is removed
    /// @param sender The initial msg.sender for the remove liquidity call
    /// @param key The key for the pool
    /// @param params The parameters for removing liquidity
    /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    function beforeRemoveLiquidity(
        address sender,
        PoolKey calldata key,
        ModifyLiquidityParams calldata params,
        bytes calldata hookData
    ) external returns (bytes4);

    /// @notice The hook called after liquidity is removed
    /// @param sender The initial msg.sender for the remove liquidity call
    /// @param key The key for the pool
    /// @param params The parameters for removing liquidity
    /// @param delta The caller's balance delta after removing liquidity; the sum of principal delta, fees accrued, and hook delta
    /// @param feesAccrued The fees accrued since the last time fees were collected from this position
    /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    /// @return BalanceDelta The hook's delta in token0 and token1. Positive: the hook is owed/took currency, negative: the hook owes/sent currency
    function afterRemoveLiquidity(
        address sender,
        PoolKey calldata key,
        ModifyLiquidityParams calldata params,
        BalanceDelta delta,
        BalanceDelta feesAccrued,
        bytes calldata hookData
    ) external returns (bytes4, BalanceDelta);

    /// @notice The hook called before a swap
    /// @param sender The initial msg.sender for the swap call
    /// @param key The key for the pool
    /// @param params The parameters for the swap
    /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    /// @return BeforeSwapDelta The hook's delta in specified and unspecified currencies. Positive: the hook is owed/took currency, negative: the hook owes/sent currency
    /// @return uint24 Optionally override the lp fee, only used if three conditions are met: 1. the Pool has a dynamic fee, 2. the value's 2nd highest bit is set (23rd bit, 0x400000), and 3. the value is less than or equal to the maximum fee (1 million)
    function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata hookData)
        external
        returns (bytes4, BeforeSwapDelta, uint24);

    /// @notice The hook called after a swap
    /// @param sender The initial msg.sender for the swap call
    /// @param key The key for the pool
    /// @param params The parameters for the swap
    /// @param delta The amount owed to the caller (positive) or owed to the pool (negative)
    /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    /// @return int128 The hook's delta in unspecified currency. Positive: the hook is owed/took currency, negative: the hook owes/sent currency
    function afterSwap(
        address sender,
        PoolKey calldata key,
        SwapParams calldata params,
        BalanceDelta delta,
        bytes calldata hookData
    ) external returns (bytes4, int128);

    /// @notice The hook called before donate
    /// @param sender The initial msg.sender for the donate call
    /// @param key The key for the pool
    /// @param amount0 The amount of token0 being donated
    /// @param amount1 The amount of token1 being donated
    /// @param hookData Arbitrary data handed into the PoolManager by the donor to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    function beforeDonate(
        address sender,
        PoolKey calldata key,
        uint256 amount0,
        uint256 amount1,
        bytes calldata hookData
    ) external returns (bytes4);

    /// @notice The hook called after donate
    /// @param sender The initial msg.sender for the donate call
    /// @param key The key for the pool
    /// @param amount0 The amount of token0 being donated
    /// @param amount1 The amount of token1 being donated
    /// @param hookData Arbitrary data handed into the PoolManager by the donor to be be passed on to the hook
    /// @return bytes4 The function selector for the hook
    function afterDonate(
        address sender,
        PoolKey calldata key,
        uint256 amount0,
        uint256 amount1,
        bytes calldata hookData
    ) external returns (bytes4);
}


================================================
FILE: src/interfaces/IPoolManager.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Currency} from "../types/Currency.sol";
import {PoolKey} from "../types/PoolKey.sol";
import {IHooks} from "./IHooks.sol";
import {IERC6909Claims} from "./external/IERC6909Claims.sol";
import {IProtocolFees} from "./IProtocolFees.sol";
import {BalanceDelta} from "../types/BalanceDelta.sol";
import {PoolId} from "../types/PoolId.sol";
import {IExtsload} from "./IExtsload.sol";
import {IExttload} from "./IExttload.sol";
import {ModifyLiquidityParams, SwapParams} from "../types/PoolOperation.sol";

/// @notice Interface for the PoolManager
interface IPoolManager is IProtocolFees, IERC6909Claims, IExtsload, IExttload {
    /// @notice Thrown when a currency is not netted out after the contract is unlocked
    error CurrencyNotSettled();

    /// @notice Thrown when trying to interact with a non-initialized pool
    error PoolNotInitialized();

    /// @notice Thrown when unlock is called, but the contract is already unlocked
    error AlreadyUnlocked();

    /// @notice Thrown when a function is called that requires the contract to be unlocked, but it is not
    error ManagerLocked();

    /// @notice Pools are limited to type(int16).max tickSpacing in #initialize, to prevent overflow
    error TickSpacingTooLarge(int24 tickSpacing);

    /// @notice Pools must have a positive non-zero tickSpacing passed to #initialize
    error TickSpacingTooSmall(int24 tickSpacing);

    /// @notice PoolKey must have currencies where address(currency0) < address(currency1)
    error CurrenciesOutOfOrderOrEqual(address currency0, address currency1);

    /// @notice Thrown when a call to updateDynamicLPFee is made by an address that is not the hook,
    /// or on a pool that does not have a dynamic swap fee.
    error UnauthorizedDynamicLPFeeUpdate();

    /// @notice Thrown when trying to swap amount of 0
    error SwapAmountCannotBeZero();

    ///@notice Thrown when native currency is passed to a non native settlement
    error NonzeroNativeValue();

    /// @notice Thrown when `clear` is called with an amount that is not exactly equal to the open currency delta.
    error MustClearExactPositiveDelta();

    /// @notice Emitted when a new pool is initialized
    /// @param id The abi encoded hash of the pool key struct for the new pool
    /// @param currency0 The first currency of the pool by address sort order
    /// @param currency1 The second currency of the pool by address sort order
    /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
    /// @param tickSpacing The minimum number of ticks between initialized ticks
    /// @param hooks The hooks contract address for the pool, or address(0) if none
    /// @param sqrtPriceX96 The price of the pool on initialization
    /// @param tick The initial tick of the pool corresponding to the initialized price
    event Initialize(
        PoolId indexed id,
        Currency indexed currency0,
        Currency indexed currency1,
        uint24 fee,
        int24 tickSpacing,
        IHooks hooks,
        uint160 sqrtPriceX96,
        int24 tick
    );

    /// @notice Emitted when a liquidity position is modified
    /// @param id The abi encoded hash of the pool key struct for the pool that was modified
    /// @param sender The address that modified the pool
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param liquidityDelta The amount of liquidity that was added or removed
    /// @param salt The extra data to make positions unique
    event ModifyLiquidity(
        PoolId indexed id, address indexed sender, int24 tickLower, int24 tickUpper, int256 liquidityDelta, bytes32 salt
    );

    /// @notice Emitted for swaps between currency0 and currency1
    /// @param id The abi encoded hash of the pool key struct for the pool that was modified
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param amount0 The delta of the currency0 balance of the pool
    /// @param amount1 The delta of the currency1 balance of the pool
    /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96
    /// @param liquidity The liquidity of the pool after the swap
    /// @param tick The log base 1.0001 of the price of the pool after the swap
    /// @param fee The swap fee in hundredths of a bip
    event Swap(
        PoolId indexed id,
        address indexed sender,
        int128 amount0,
        int128 amount1,
        uint160 sqrtPriceX96,
        uint128 liquidity,
        int24 tick,
        uint24 fee
    );

    /// @notice Emitted for donations
    /// @param id The abi encoded hash of the pool key struct for the pool that was donated to
    /// @param sender The address that initiated the donate call
    /// @param amount0 The amount donated in currency0
    /// @param amount1 The amount donated in currency1
    event Donate(PoolId indexed id, address indexed sender, uint256 amount0, uint256 amount1);

    /// @notice All interactions on the contract that account deltas require unlocking. A caller that calls `unlock` must implement
    /// `IUnlockCallback(msg.sender).unlockCallback(data)`, where they interact with the remaining functions on this contract.
    /// @dev The only functions callable without an unlocking are `initialize` and `updateDynamicLPFee`
    /// @param data Any data to pass to the callback, via `IUnlockCallback(msg.sender).unlockCallback(data)`
    /// @return The data returned by the call to `IUnlockCallback(msg.sender).unlockCallback(data)`
    function unlock(bytes calldata data) external returns (bytes memory);

    /// @notice Initialize the state for a given pool ID
    /// @dev A swap fee totaling MAX_SWAP_FEE (100%) makes exact output swaps impossible since the input is entirely consumed by the fee
    /// @param key The pool key for the pool to initialize
    /// @param sqrtPriceX96 The initial square root price
    /// @return tick The initial tick of the pool
    function initialize(PoolKey memory key, uint160 sqrtPriceX96) external returns (int24 tick);

    /// @notice Modify the liquidity for the given pool
    /// @dev Poke by calling with a zero liquidityDelta
    /// @param key The pool to modify liquidity in
    /// @param params The parameters for modifying the liquidity
    /// @param hookData The data to pass through to the add/removeLiquidity hooks
    /// @return callerDelta The balance delta of the caller of modifyLiquidity. This is the total of both principal, fee deltas, and hook deltas if applicable
    /// @return feesAccrued The balance delta of the fees generated in the liquidity range. Returned for informational purposes
    /// @dev Note that feesAccrued can be artificially inflated by a malicious actor and integrators should be careful using the value
    /// For pools with a single liquidity position, actors can donate to themselves to inflate feeGrowthGlobal (and consequently feesAccrued)
    /// atomically donating and collecting fees in the same unlockCallback may make the inflated value more extreme
    function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData)
        external
        returns (BalanceDelta callerDelta, BalanceDelta feesAccrued);

    /// @notice Swap against the given pool
    /// @param key The pool to swap in
    /// @param params The parameters for swapping
    /// @param hookData The data to pass through to the swap hooks
    /// @return swapDelta The balance delta of the address swapping
    /// @dev Swapping on low liquidity pools may cause unexpected swap amounts when liquidity available is less than amountSpecified.
    /// Additionally note that if interacting with hooks that have the BEFORE_SWAP_RETURNS_DELTA_FLAG or AFTER_SWAP_RETURNS_DELTA_FLAG
    /// the hook may alter the swap input/output. Integrators should perform checks on the returned swapDelta.
    function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData)
        external
        returns (BalanceDelta swapDelta);

    /// @notice Donate the given currency amounts to the in-range liquidity providers of a pool
    /// @dev Calls to donate can be frontrun adding just-in-time liquidity, with the aim of receiving a portion donated funds.
    /// Donors should keep this in mind when designing donation mechanisms.
    /// @dev This function donates to in-range LPs at slot0.tick. In certain edge-cases of the swap algorithm, the `sqrtPrice` of
    /// a pool can be at the lower boundary of tick `n`, but the `slot0.tick` of the pool is already `n - 1`. In this case a call to
    /// `donate` would donate to tick `n - 1` (slot0.tick) not tick `n` (getTickAtSqrtPrice(slot0.sqrtPriceX96)).
    /// Read the comments in `Pool.swap()` for more information about this.
    /// @param key The key of the pool to donate to
    /// @param amount0 The amount of currency0 to donate
    /// @param amount1 The amount of currency1 to donate
    /// @param hookData The data to pass through to the donate hooks
    /// @return BalanceDelta The delta of the caller after the donate
    function donate(PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData)
        external
        returns (BalanceDelta);

    /// @notice Writes the current ERC20 balance of the specified currency to transient storage
    /// This is used to checkpoint balances for the manager and derive deltas for the caller.
    /// @dev This MUST be called before any ERC20 tokens are sent into the contract, but can be skipped
    /// for native tokens because the amount to settle is determined by the sent value.
    /// However, if an ERC20 token has been synced and not settled, and the caller instead wants to settle
    /// native funds, this function can be called with the native currency to then be able to settle the native currency
    function sync(Currency currency) external;

    /// @notice Called by the user to net out some value owed to the user
    /// @dev Will revert if the requested amount is not available, consider using `mint` instead
    /// @dev Can also be used as a mechanism for free flash loans
    /// @param currency The currency to withdraw from the pool manager
    /// @param to The address to withdraw to
    /// @param amount The amount of currency to withdraw
    function take(Currency currency, address to, uint256 amount) external;

    /// @notice Called by the user to pay what is owed
    /// @return paid The amount of currency settled
    function settle() external payable returns (uint256 paid);

    /// @notice Called by the user to pay on behalf of another address
    /// @param recipient The address to credit for the payment
    /// @return paid The amount of currency settled
    function settleFor(address recipient) external payable returns (uint256 paid);

    /// @notice WARNING - Any currency that is cleared, will be non-retrievable, and locked in the contract permanently.
    /// A call to clear will zero out a positive balance WITHOUT a corresponding transfer.
    /// @dev This could be used to clear a balance that is considered dust.
    /// Additionally, the amount must be the exact positive balance. This is to enforce that the caller is aware of the amount being cleared.
    function clear(Currency currency, uint256 amount) external;

    /// @notice Called by the user to move value into ERC6909 balance
    /// @param to The address to mint the tokens to
    /// @param id The currency address to mint to ERC6909s, as a uint256
    /// @param amount The amount of currency to mint
    /// @dev The id is converted to a uint160 to correspond to a currency address
    /// If the upper 12 bytes are not 0, they will be 0-ed out
    function mint(address to, uint256 id, uint256 amount) external;

    /// @notice Called by the user to move value from ERC6909 balance
    /// @param from The address to burn the tokens from
    /// @param id The currency address to burn from ERC6909s, as a uint256
    /// @param amount The amount of currency to burn
    /// @dev The id is converted to a uint160 to correspond to a currency address
    /// If the upper 12 bytes are not 0, they will be 0-ed out
    function burn(address from, uint256 id, uint256 amount) external;

    /// @notice Updates the pools lp fees for the a pool that has enabled dynamic lp fees.
    /// @dev A swap fee totaling MAX_SWAP_FEE (100%) makes exact output swaps impossible since the input is entirely consumed by the fee
    /// @param key The key of the pool to update dynamic LP fees for
    /// @param newDynamicLPFee The new dynamic pool LP fee
    function updateDynamicLPFee(PoolKey memory key, uint24 newDynamicLPFee) external;
}


================================================
FILE: src/interfaces/IProtocolFees.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Currency} from "../types/Currency.sol";
import {PoolId} from "../types/PoolId.sol";
import {PoolKey} from "../types/PoolKey.sol";

/// @notice Interface for all protocol-fee related functions in the pool manager
interface IProtocolFees {
    /// @notice Thrown when protocol fee is set too high
    error ProtocolFeeTooLarge(uint24 fee);

    /// @notice Thrown when collectProtocolFees or setProtocolFee is not called by the controller.
    error InvalidCaller();

    /// @notice Thrown when collectProtocolFees is attempted on a token that is synced.
    error ProtocolFeeCurrencySynced();

    /// @notice Emitted when the protocol fee controller address is updated in setProtocolFeeController.
    event ProtocolFeeControllerUpdated(address indexed protocolFeeController);

    /// @notice Emitted when the protocol fee is updated for a pool.
    event ProtocolFeeUpdated(PoolId indexed id, uint24 protocolFee);

    /// @notice Given a currency address, returns the protocol fees accrued in that currency
    /// @param currency The currency to check
    /// @return amount The amount of protocol fees accrued in the currency
    function protocolFeesAccrued(Currency currency) external view returns (uint256 amount);

    /// @notice Sets the protocol fee for the given pool
    /// @param key The key of the pool to set a protocol fee for
    /// @param newProtocolFee The fee to set
    function setProtocolFee(PoolKey memory key, uint24 newProtocolFee) external;

    /// @notice Sets the protocol fee controller
    /// @param controller The new protocol fee controller
    function setProtocolFeeController(address controller) external;

    /// @notice Collects the protocol fees for a given recipient and currency, returning the amount collected
    /// @dev This will revert if the contract is unlocked
    /// @param recipient The address to receive the protocol fees
    /// @param currency The currency to withdraw
    /// @param amount The amount of currency to withdraw
    /// @return amountCollected The amount of currency successfully withdrawn
    function collectProtocolFees(address recipient, Currency currency, uint256 amount)
        external
        returns (uint256 amountCollected);

    /// @notice Returns the current protocol fee controller address
    /// @return address The current protocol fee controller address
    function protocolFeeController() external view returns (address);
}


================================================
FILE: src/interfaces/callback/IUnlockCallback.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Interface for the callback executed when an address unlocks the pool manager
interface IUnlockCallback {
    /// @notice Called by the pool manager on `msg.sender` when the manager is unlocked
    /// @param data The data that was passed to the call to unlock
    /// @return Any data that you want to be returned from the unlock call
    function unlockCallback(bytes calldata data) external returns (bytes memory);
}


================================================
FILE: src/interfaces/external/IERC20Minimal.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Minimal ERC20 interface for Uniswap
/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3
interface IERC20Minimal {
    /// @notice Returns an account's balance in the token
    /// @param account The account for which to look up the number of tokens it has, i.e. its balance
    /// @return The number of tokens held by the account
    function balanceOf(address account) external view returns (uint256);

    /// @notice Transfers the amount of token from the `msg.sender` to the recipient
    /// @param recipient The account that will receive the amount transferred
    /// @param amount The number of tokens to send from the sender to the recipient
    /// @return Returns true for a successful transfer, false for an unsuccessful transfer
    function transfer(address recipient, uint256 amount) external returns (bool);

    /// @notice Returns the current allowance given to a spender by an owner
    /// @param owner The account of the token owner
    /// @param spender The account of the token spender
    /// @return The current allowance granted by `owner` to `spender`
    function allowance(address owner, address spender) external view returns (uint256);

    /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
    /// @param spender The account which will be allowed to spend a given amount of the owners tokens
    /// @param amount The amount of tokens allowed to be used by `spender`
    /// @return Returns true for a successful approval, false for unsuccessful
    function approve(address spender, uint256 amount) external returns (bool);

    /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
    /// @param sender The account from which the transfer will be initiated
    /// @param recipient The recipient of the transfer
    /// @param amount The amount of the transfer
    /// @return Returns true for a successful transfer, false for unsuccessful
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
    /// @param from The account from which the tokens were sent, i.e. the balance decreased
    /// @param to The account to which the tokens were sent, i.e. the balance increased
    /// @param value The amount of tokens that were transferred
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
    /// @param owner The account that approved spending of its tokens
    /// @param spender The account for which the spending allowance was modified
    /// @param value The new allowance from the owner to the spender
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


================================================
FILE: src/interfaces/external/IERC6909Claims.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Interface for claims over a contract balance, wrapped as a ERC6909
interface IERC6909Claims {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OperatorSet(address indexed owner, address indexed operator, bool approved);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount);

    event Transfer(address caller, address indexed from, address indexed to, uint256 indexed id, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                                 FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Owner balance of an id.
    /// @param owner The address of the owner.
    /// @param id The id of the token.
    /// @return amount The balance of the token.
    function balanceOf(address owner, uint256 id) external view returns (uint256 amount);

    /// @notice Spender allowance of an id.
    /// @param owner The address of the owner.
    /// @param spender The address of the spender.
    /// @param id The id of the token.
    /// @return amount The allowance of the token.
    function allowance(address owner, address spender, uint256 id) external view returns (uint256 amount);

    /// @notice Checks if a spender is approved by an owner as an operator
    /// @param owner The address of the owner.
    /// @param spender The address of the spender.
    /// @return approved The approval status.
    function isOperator(address owner, address spender) external view returns (bool approved);

    /// @notice Transfers an amount of an id from the caller to a receiver.
    /// @param receiver The address of the receiver.
    /// @param id The id of the token.
    /// @param amount The amount of the token.
    /// @return bool True, always, unless the function reverts
    function transfer(address receiver, uint256 id, uint256 amount) external returns (bool);

    /// @notice Transfers an amount of an id from a sender to a receiver.
    /// @param sender The address of the sender.
    /// @param receiver The address of the receiver.
    /// @param id The id of the token.
    /// @param amount The amount of the token.
    /// @return bool True, always, unless the function reverts
    function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool);

    /// @notice Approves an amount of an id to a spender.
    /// @param spender The address of the spender.
    /// @param id The id of the token.
    /// @param amount The amount of the token.
    /// @return bool True, always
    function approve(address spender, uint256 id, uint256 amount) external returns (bool);

    /// @notice Sets or removes an operator for the caller.
    /// @param operator The address of the operator.
    /// @param approved The approval status.
    /// @return bool True, always
    function setOperator(address operator, bool approved) external returns (bool);
}


================================================
FILE: src/libraries/BitMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
/// @author Solady (https://github.com/Vectorized/solady/blob/8200a70e8dc2a77ecb074fc2e99a2a0d36547522/src/utils/LibBit.sol)
library BitMath {
    /// @notice Returns the index of the most significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @param x the value for which to compute the most significant bit, must be greater than 0
    /// @return r the index of the most significant bit
    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0);

        assembly ("memory-safe") {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020500060203020504000106050205030304010505030400000000))
        }
    }

    /// @notice Returns the index of the least significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @param x the value for which to compute the least significant bit, must be greater than 0
    /// @return r the index of the least significant bit
    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0);

        assembly ("memory-safe") {
            // Isolate the least significant bit.
            x := and(x, sub(0, x))
            // For the upper 3 bits of the result, use a De Bruijn-like lookup.
            // Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
            // forgefmt: disable-next-item
            r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
                0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
                0x8040405543005266443200005020610674053026020000107506200176117077)))
            // For the lower 5 bits of the result, use a De Bruijn lookup.
            // forgefmt: disable-next-item
            r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
        }
    }
}


================================================
FILE: src/libraries/CurrencyDelta.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import {Currency} from "../types/Currency.sol";

/// @title a library to store callers' currency deltas in transient storage
/// @dev this library implements the equivalent of a mapping, as transient storage can only be accessed in assembly
library CurrencyDelta {
    /// @notice calculates which storage slot a delta should be stored in for a given account and currency
    function _computeSlot(address target, Currency currency) internal pure returns (bytes32 hashSlot) {
        assembly ("memory-safe") {
            mstore(0, and(target, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(32, and(currency, 0xffffffffffffffffffffffffffffffffffffffff))
            hashSlot := keccak256(0, 64)
        }
    }

    function getDelta(Currency currency, address target) internal view returns (int256 delta) {
        bytes32 hashSlot = _computeSlot(target, currency);
        assembly ("memory-safe") {
            delta := tload(hashSlot)
        }
    }

    /// @notice applies a new currency delta for a given account and currency
    /// @return previous The prior value
    /// @return next The modified result
    function applyDelta(Currency currency, address target, int128 delta)
        internal
        returns (int256 previous, int256 next)
    {
        bytes32 hashSlot = _computeSlot(target, currency);

        assembly ("memory-safe") {
            previous := tload(hashSlot)
        }
        next = previous + delta;
        assembly ("memory-safe") {
            tstore(hashSlot, next)
        }
    }
}


================================================
FILE: src/libraries/CurrencyReserves.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import {Currency} from "../types/Currency.sol";
import {CustomRevert} from "./CustomRevert.sol";

library CurrencyReserves {
    using CustomRevert for bytes4;

    /// bytes32(uint256(keccak256("ReservesOf")) - 1)
    bytes32 constant RESERVES_OF_SLOT = 0x1e0745a7db1623981f0b2a5d4232364c00787266eb75ad546f190e6cebe9bd95;
    /// bytes32(uint256(keccak256("Currency")) - 1)
    bytes32 constant CURRENCY_SLOT = 0x27e098c505d44ec3574004bca052aabf76bd35004c182099d8c575fb238593b9;

    function getSyncedCurrency() internal view returns (Currency currency) {
        assembly ("memory-safe") {
            currency := tload(CURRENCY_SLOT)
        }
    }

    function resetCurrency() internal {
        assembly ("memory-safe") {
            tstore(CURRENCY_SLOT, 0)
        }
    }

    function syncCurrencyAndReserves(Currency currency, uint256 value) internal {
        assembly ("memory-safe") {
            tstore(CURRENCY_SLOT, and(currency, 0xffffffffffffffffffffffffffffffffffffffff))
            tstore(RESERVES_OF_SLOT, value)
        }
    }

    function getSyncedReserves() internal view returns (uint256 value) {
        assembly ("memory-safe") {
            value := tload(RESERVES_OF_SLOT)
        }
    }
}


================================================
FILE: src/libraries/CustomRevert.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Library for reverting with custom errors efficiently
/// @notice Contains functions for reverting with custom errors with different argument types efficiently
/// @dev To use this library, declare `using CustomRevert for bytes4;` and replace `revert CustomError()` with
/// `CustomError.selector.revertWith()`
/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately
library CustomRevert {
    /// @dev ERC-7751 error for wrapping bubbled up reverts
    error WrappedError(address target, bytes4 selector, bytes reason, bytes details);

    /// @dev Reverts with the selector of a custom error in the scratch space
    function revertWith(bytes4 selector) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            revert(0, 0x04)
        }
    }

    /// @dev Reverts with a custom error with an address argument in the scratch space
    function revertWith(bytes4 selector, address addr) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(0, 0x24)
        }
    }

    /// @dev Reverts with a custom error with an int24 argument in the scratch space
    function revertWith(bytes4 selector, int24 value) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            mstore(0x04, signextend(2, value))
            revert(0, 0x24)
        }
    }

    /// @dev Reverts with a custom error with a uint160 argument in the scratch space
    function revertWith(bytes4 selector, uint160 value) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            mstore(0x04, and(value, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(0, 0x24)
        }
    }

    /// @dev Reverts with a custom error with two int24 arguments
    function revertWith(bytes4 selector, int24 value1, int24 value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), signextend(2, value1))
            mstore(add(fmp, 0x24), signextend(2, value2))
            revert(fmp, 0x44)
        }
    }

    /// @dev Reverts with a custom error with two uint160 arguments
    function revertWith(bytes4 selector, uint160 value1, uint160 value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(fmp, 0x44)
        }
    }

    /// @dev Reverts with a custom error with two address arguments
    function revertWith(bytes4 selector, address value1, address value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(fmp, 0x44)
        }
    }

    /// @notice bubble up the revert message returned by a call and revert with a wrapped ERC-7751 error
    /// @dev this method can be vulnerable to revert data bombs
    function bubbleUpAndRevertWith(
        address revertingContract,
        bytes4 revertingFunctionSelector,
        bytes4 additionalContext
    ) internal pure {
        bytes4 wrappedErrorSelector = WrappedError.selector;
        assembly ("memory-safe") {
            // Ensure the size of the revert data is a multiple of 32 bytes
            let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32)

            let fmp := mload(0x40)

            // Encode wrapped error selector, address, function selector, offset, additional context, size, revert reason
            mstore(fmp, wrappedErrorSelector)
            mstore(add(fmp, 0x04), and(revertingContract, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(
                add(fmp, 0x24),
                and(revertingFunctionSelector, 0xffffffff00000000000000000000000000000000000000000000000000000000)
            )
            // offset revert reason
            mstore(add(fmp, 0x44), 0x80)
            // offset additional context
            mstore(add(fmp, 0x64), add(0xa0, encodedDataSize))
            // size revert reason
            mstore(add(fmp, 0x84), returndatasize())
            // revert reason
            returndatacopy(add(fmp, 0xa4), 0, returndatasize())
            // size additional context
            mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04)
            // additional context
            mstore(
                add(fmp, add(0xc4, encodedDataSize)),
                and(additionalContext, 0xffffffff00000000000000000000000000000000000000000000000000000000)
            )
            revert(fmp, add(0xe4, encodedDataSize))
        }
    }
}


================================================
FILE: src/libraries/FixedPoint128.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title FixedPoint128
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
library FixedPoint128 {
    uint256 internal constant Q128 = 0x100000000000000000000000000000000;
}


================================================
FILE: src/libraries/FixedPoint96.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
    uint8 internal constant RESOLUTION = 96;
    uint256 internal constant Q96 = 0x1000000000000000000000000;
}


================================================
FILE: src/libraries/FullMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0 = a * b; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly ("memory-safe") {
                let mm := mulmod(a, b, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                assembly ("memory-safe") {
                    result := div(prod0, denominator)
                }
                return result;
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly ("memory-safe") {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly ("memory-safe") {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly ("memory-safe") {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly ("memory-safe") {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly ("memory-safe") {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the preconditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) != 0) {
                require(++result > 0);
            }
        }
    }
}


================================================
FILE: src/libraries/Hooks.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {PoolKey} from "../types/PoolKey.sol";
import {IHooks} from "../interfaces/IHooks.sol";
import {SafeCast} from "./SafeCast.sol";
import {LPFeeLibrary} from "./LPFeeLibrary.sol";
import {BalanceDelta, toBalanceDelta, BalanceDeltaLibrary} from "../types/BalanceDelta.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "../types/BeforeSwapDelta.sol";
import {IPoolManager} from "../interfaces/IPoolManager.sol";
import {ModifyLiquidityParams, SwapParams} from "../types/PoolOperation.sol";
import {ParseBytes} from "./ParseBytes.sol";
import {CustomRevert} from "./CustomRevert.sol";

/// @notice V4 decides whether to invoke specific hooks by inspecting the least significant bits
/// of the address that the hooks contract is deployed to.
/// For example, a hooks contract deployed to address: 0x0000000000000000000000000000000000002400
/// has the lowest bits '10 0100 0000 0000' which would cause the 'before initialize' and 'after add liquidity' hooks to be used.
library Hooks {
    using LPFeeLibrary for uint24;
    using Hooks for IHooks;
    using SafeCast for int256;
    using BeforeSwapDeltaLibrary for BeforeSwapDelta;
    using ParseBytes for bytes;
    using CustomRevert for bytes4;

    uint160 internal constant ALL_HOOK_MASK = uint160((1 << 14) - 1);

    uint160 internal constant BEFORE_INITIALIZE_FLAG = 1 << 13;
    uint160 internal constant AFTER_INITIALIZE_FLAG = 1 << 12;

    uint160 internal constant BEFORE_ADD_LIQUIDITY_FLAG = 1 << 11;
    uint160 internal constant AFTER_ADD_LIQUIDITY_FLAG = 1 << 10;

    uint160 internal constant BEFORE_REMOVE_LIQUIDITY_FLAG = 1 << 9;
    uint160 internal constant AFTER_REMOVE_LIQUIDITY_FLAG = 1 << 8;

    uint160 internal constant BEFORE_SWAP_FLAG = 1 << 7;
    uint160 internal constant AFTER_SWAP_FLAG = 1 << 6;

    uint160 internal constant BEFORE_DONATE_FLAG = 1 << 5;
    uint160 internal constant AFTER_DONATE_FLAG = 1 << 4;

    uint160 internal constant BEFORE_SWAP_RETURNS_DELTA_FLAG = 1 << 3;
    uint160 internal constant AFTER_SWAP_RETURNS_DELTA_FLAG = 1 << 2;
    uint160 internal constant AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG = 1 << 1;
    uint160 internal constant AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG = 1 << 0;

    struct Permissions {
        bool beforeInitialize;
        bool afterInitialize;
        bool beforeAddLiquidity;
        bool afterAddLiquidity;
        bool beforeRemoveLiquidity;
        bool afterRemoveLiquidity;
        bool beforeSwap;
        bool afterSwap;
        bool beforeDonate;
        bool afterDonate;
        bool beforeSwapReturnDelta;
        bool afterSwapReturnDelta;
        bool afterAddLiquidityReturnDelta;
        bool afterRemoveLiquidityReturnDelta;
    }

    /// @notice Thrown if the address will not lead to the specified hook calls being called
    /// @param hooks The address of the hooks contract
    error HookAddressNotValid(address hooks);

    /// @notice Hook did not return its selector
    error InvalidHookResponse();

    /// @notice Additional context for ERC-7751 wrapped error when a hook call fails
    error HookCallFailed();

    /// @notice The hook's delta changed the swap from exactIn to exactOut or vice versa
    error HookDeltaExceedsSwapAmount();

    /// @notice Utility function intended to be used in hook constructors to ensure
    /// the deployed hooks address causes the intended hooks to be called
    /// @param permissions The hooks that are intended to be called
    /// @dev permissions param is memory as the function will be called from constructors
    function validateHookPermissions(IHooks self, Permissions memory permissions) internal pure {
        if (
            permissions.beforeInitialize != self.hasPermission(BEFORE_INITIALIZE_FLAG)
                || permissions.afterInitialize != self.hasPermission(AFTER_INITIALIZE_FLAG)
                || permissions.beforeAddLiquidity != self.hasPermission(BEFORE_ADD_LIQUIDITY_FLAG)
                || permissions.afterAddLiquidity != self.hasPermission(AFTER_ADD_LIQUIDITY_FLAG)
                || permissions.beforeRemoveLiquidity != self.hasPermission(BEFORE_REMOVE_LIQUIDITY_FLAG)
                || permissions.afterRemoveLiquidity != self.hasPermission(AFTER_REMOVE_LIQUIDITY_FLAG)
                || permissions.beforeSwap != self.hasPermission(BEFORE_SWAP_FLAG)
                || permissions.afterSwap != self.hasPermission(AFTER_SWAP_FLAG)
                || permissions.beforeDonate != self.hasPermission(BEFORE_DONATE_FLAG)
                || permissions.afterDonate != self.hasPermission(AFTER_DONATE_FLAG)
                || permissions.beforeSwapReturnDelta != self.hasPermission(BEFORE_SWAP_RETURNS_DELTA_FLAG)
                || permissions.afterSwapReturnDelta != self.hasPermission(AFTER_SWAP_RETURNS_DELTA_FLAG)
                || permissions.afterAddLiquidityReturnDelta != self.hasPermission(AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG)
                || permissions.afterRemoveLiquidityReturnDelta
                    != self.hasPermission(AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)
        ) {
            HookAddressNotValid.selector.revertWith(address(self));
        }
    }

    /// @notice Ensures that the hook address includes at least one hook flag or dynamic fees, or is the 0 address
    /// @param self The hook to verify
    /// @param fee The fee of the pool the hook is used with
    /// @return bool True if the hook address is valid
    function isValidHookAddress(IHooks self, uint24 fee) internal pure returns (bool) {
        // The hook can only have a flag to return a hook delta on an action if it also has the corresponding action flag
        if (!self.hasPermission(BEFORE_SWAP_FLAG) && self.hasPermission(BEFORE_SWAP_RETURNS_DELTA_FLAG)) return false;
        if (!self.hasPermission(AFTER_SWAP_FLAG) && self.hasPermission(AFTER_SWAP_RETURNS_DELTA_FLAG)) return false;
        if (!self.hasPermission(AFTER_ADD_LIQUIDITY_FLAG) && self.hasPermission(AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG))
        {
            return false;
        }
        if (
            !self.hasPermission(AFTER_REMOVE_LIQUIDITY_FLAG)
                && self.hasPermission(AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)
        ) return false;

        // If there is no hook contract set, then fee cannot be dynamic
        // If a hook contract is set, it must have at least 1 flag set, or have a dynamic fee
        return address(self) == address(0)
            ? !fee.isDynamicFee()
            : (uint160(address(self)) & ALL_HOOK_MASK > 0 || fee.isDynamicFee());
    }

    /// @notice performs a hook call using the given calldata on the given hook that doesn't return a delta
    /// @return result The complete data returned by the hook
    function callHook(IHooks self, bytes memory data) internal returns (bytes memory result) {
        bool success;
        assembly ("memory-safe") {
            success := call(gas(), self, 0, add(data, 0x20), mload(data), 0, 0)
        }
        // Revert with FailedHookCall, containing any error message to bubble up
        if (!success) CustomRevert.bubbleUpAndRevertWith(address(self), bytes4(data), HookCallFailed.selector);

        // The call was successful, fetch the returned data
        assembly ("memory-safe") {
            // allocate result byte array from the free memory pointer
            result := mload(0x40)
            // store new free memory pointer at the end of the array padded to 32 bytes
            mstore(0x40, add(result, and(add(returndatasize(), 0x3f), not(0x1f))))
            // store length in memory
            mstore(result, returndatasize())
            // copy return data to result
            returndatacopy(add(result, 0x20), 0, returndatasize())
        }

        // Length must be at least 32 to contain the selector. Check expected selector and returned selector match.
        if (result.length < 32 || result.parseSelector() != data.parseSelector()) {
            InvalidHookResponse.selector.revertWith();
        }
    }

    /// @notice performs a hook call using the given calldata on the given hook
    /// @return int256 The delta returned by the hook
    function callHookWithReturnDelta(IHooks self, bytes memory data, bool parseReturn) internal returns (int256) {
        bytes memory result = callHook(self, data);

        // If this hook wasn't meant to return something, default to 0 delta
        if (!parseReturn) return 0;

        // A length of 64 bytes is required to return a bytes4, and a 32 byte delta
        if (result.length != 64) InvalidHookResponse.selector.revertWith();
        return result.parseReturnDelta();
    }

    /// @notice modifier to prevent calling a hook if they initiated the action
    modifier noSelfCall(IHooks self) {
        if (msg.sender != address(self)) {
            _;
        }
    }

    /// @notice calls beforeInitialize hook if permissioned and validates return value
    function beforeInitialize(IHooks self, PoolKey memory key, uint160 sqrtPriceX96) internal noSelfCall(self) {
        if (self.hasPermission(BEFORE_INITIALIZE_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.beforeInitialize, (msg.sender, key, sqrtPriceX96)));
        }
    }

    /// @notice calls afterInitialize hook if permissioned and validates return value
    function afterInitialize(IHooks self, PoolKey memory key, uint160 sqrtPriceX96, int24 tick)
        internal
        noSelfCall(self)
    {
        if (self.hasPermission(AFTER_INITIALIZE_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.afterInitialize, (msg.sender, key, sqrtPriceX96, tick)));
        }
    }

    /// @notice calls beforeModifyLiquidity hook if permissioned and validates return value
    function beforeModifyLiquidity(
        IHooks self,
        PoolKey memory key,
        ModifyLiquidityParams memory params,
        bytes calldata hookData
    ) internal noSelfCall(self) {
        if (params.liquidityDelta > 0 && self.hasPermission(BEFORE_ADD_LIQUIDITY_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.beforeAddLiquidity, (msg.sender, key, params, hookData)));
        } else if (params.liquidityDelta <= 0 && self.hasPermission(BEFORE_REMOVE_LIQUIDITY_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.beforeRemoveLiquidity, (msg.sender, key, params, hookData)));
        }
    }

    /// @notice calls afterModifyLiquidity hook if permissioned and validates return value
    function afterModifyLiquidity(
        IHooks self,
        PoolKey memory key,
        ModifyLiquidityParams memory params,
        BalanceDelta delta,
        BalanceDelta feesAccrued,
        bytes calldata hookData
    ) internal returns (BalanceDelta callerDelta, BalanceDelta hookDelta) {
        if (msg.sender == address(self)) return (delta, BalanceDeltaLibrary.ZERO_DELTA);

        callerDelta = delta;
        if (params.liquidityDelta > 0) {
            if (self.hasPermission(AFTER_ADD_LIQUIDITY_FLAG)) {
                hookDelta = BalanceDelta.wrap(
                    self.callHookWithReturnDelta(
                        abi.encodeCall(
                            IHooks.afterAddLiquidity, (msg.sender, key, params, delta, feesAccrued, hookData)
                        ),
                        self.hasPermission(AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG)
                    )
                );
                callerDelta = callerDelta - hookDelta;
            }
        } else {
            if (self.hasPermission(AFTER_REMOVE_LIQUIDITY_FLAG)) {
                hookDelta = BalanceDelta.wrap(
                    self.callHookWithReturnDelta(
                        abi.encodeCall(
                            IHooks.afterRemoveLiquidity, (msg.sender, key, params, delta, feesAccrued, hookData)
                        ),
                        self.hasPermission(AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)
                    )
                );
                callerDelta = callerDelta - hookDelta;
            }
        }
    }

    /// @notice calls beforeSwap hook if permissioned and validates return value
    function beforeSwap(IHooks self, PoolKey memory key, SwapParams memory params, bytes calldata hookData)
        internal
        returns (int256 amountToSwap, BeforeSwapDelta hookReturn, uint24 lpFeeOverride)
    {
        amountToSwap = params.amountSpecified;
        if (msg.sender == address(self)) return (amountToSwap, BeforeSwapDeltaLibrary.ZERO_DELTA, lpFeeOverride);

        if (self.hasPermission(BEFORE_SWAP_FLAG)) {
            bytes memory result = callHook(self, abi.encodeCall(IHooks.beforeSwap, (msg.sender, key, params, hookData)));

            // A length of 96 bytes is required to return a bytes4, a 32 byte delta, and an LP fee
            if (result.length != 96) InvalidHookResponse.selector.revertWith();

            // dynamic fee pools that want to override the cache fee, return a valid fee with the override flag. If override flag
            // is set but an invalid fee is returned, the transaction will revert. Otherwise the current LP fee will be used
            if (key.fee.isDynamicFee()) lpFeeOverride = result.parseFee();

            // skip this logic for the case where the hook return is 0
            if (self.hasPermission(BEFORE_SWAP_RETURNS_DELTA_FLAG)) {
                hookReturn = BeforeSwapDelta.wrap(result.parseReturnDelta());

                // any return in unspecified is passed to the afterSwap hook for handling
                int128 hookDeltaSpecified = hookReturn.getSpecifiedDelta();

                // Update the swap amount according to the hook's return, and check that the swap type doesn't change (exact input/output)
                if (hookDeltaSpecified != 0) {
                    bool exactInput = amountToSwap < 0;
                    amountToSwap += hookDeltaSpecified;
                    if (exactInput ? amountToSwap > 0 : amountToSwap < 0) {
                        HookDeltaExceedsSwapAmount.selector.revertWith();
                    }
                }
            }
        }
    }

    /// @notice calls afterSwap hook if permissioned and validates return value
    function afterSwap(
        IHooks self,
        PoolKey memory key,
        SwapParams memory params,
        BalanceDelta swapDelta,
        bytes calldata hookData,
        BeforeSwapDelta beforeSwapHookReturn
    ) internal returns (BalanceDelta, BalanceDelta) {
        if (msg.sender == address(self)) return (swapDelta, BalanceDeltaLibrary.ZERO_DELTA);

        int128 hookDeltaSpecified = beforeSwapHookReturn.getSpecifiedDelta();
        int128 hookDeltaUnspecified = beforeSwapHookReturn.getUnspecifiedDelta();

        if (self.hasPermission(AFTER_SWAP_FLAG)) {
            hookDeltaUnspecified += self.callHookWithReturnDelta(
                abi.encodeCall(IHooks.afterSwap, (msg.sender, key, params, swapDelta, hookData)),
                self.hasPermission(AFTER_SWAP_RETURNS_DELTA_FLAG)
            ).toInt128();
        }

        BalanceDelta hookDelta;
        if (hookDeltaUnspecified != 0 || hookDeltaSpecified != 0) {
            hookDelta = (params.amountSpecified < 0 == params.zeroForOne)
                ? toBalanceDelta(hookDeltaSpecified, hookDeltaUnspecified)
                : toBalanceDelta(hookDeltaUnspecified, hookDeltaSpecified);

            // the caller has to pay for (or receive) the hook's delta
            swapDelta = swapDelta - hookDelta;
        }
        return (swapDelta, hookDelta);
    }

    /// @notice calls beforeDonate hook if permissioned and validates return value
    function beforeDonate(IHooks self, PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData)
        internal
        noSelfCall(self)
    {
        if (self.hasPermission(BEFORE_DONATE_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.beforeDonate, (msg.sender, key, amount0, amount1, hookData)));
        }
    }

    /// @notice calls afterDonate hook if permissioned and validates return value
    function afterDonate(IHooks self, PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData)
        internal
        noSelfCall(self)
    {
        if (self.hasPermission(AFTER_DONATE_FLAG)) {
            self.callHook(abi.encodeCall(IHooks.afterDonate, (msg.sender, key, amount0, amount1, hookData)));
        }
    }

    function hasPermission(IHooks self, uint160 flag) internal pure returns (bool) {
        return uint160(address(self)) & flag != 0;
    }
}


================================================
FILE: src/libraries/LPFeeLibrary.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {CustomRevert} from "./CustomRevert.sol";

/// @notice Library of helper functions for a pools LP fee
library LPFeeLibrary {
    using LPFeeLibrary for uint24;
    using CustomRevert for bytes4;

    /// @notice Thrown when the static or dynamic fee on a pool exceeds 100%.
    error LPFeeTooLarge(uint24 fee);

    /// @notice An lp fee of exactly 0b1000000... signals a dynamic fee pool. This isn't a valid static fee as it is > MAX_LP_FEE
    uint24 public constant DYNAMIC_FEE_FLAG = 0x800000;

    /// @notice the second bit of the fee returned by beforeSwap is used to signal if the stored LP fee should be overridden in this swap
    // only dynamic-fee pools can return a fee via the beforeSwap hook
    uint24 public constant OVERRIDE_FEE_FLAG = 0x400000;

    /// @notice mask to remove the override fee flag from a fee returned by the beforeSwaphook
    uint24 public constant REMOVE_OVERRIDE_MASK = 0xBFFFFF;

    /// @notice the lp fee is represented in hundredths of a bip, so the max is 100%
    uint24 public constant MAX_LP_FEE = 1000000;

    /// @notice returns true if a pool's LP fee signals that the pool has a dynamic fee
    /// @param self The fee to check
    /// @return bool True of the fee is dynamic
    function isDynamicFee(uint24 self) internal pure returns (bool) {
        return self == DYNAMIC_FEE_FLAG;
    }

    /// @notice returns true if an LP fee is valid, aka not above the maximum permitted fee
    /// @param self The fee to check
    /// @return bool True of the fee is valid
    function isValid(uint24 self) internal pure returns (bool) {
        return self <= MAX_LP_FEE;
    }

    /// @notice validates whether an LP fee is larger than the maximum, and reverts if invalid
    /// @param self The fee to validate
    function validate(uint24 self) internal pure {
        if (!self.isValid()) LPFeeTooLarge.selector.revertWith(self);
    }

    /// @notice gets and validates the initial LP fee for a pool. Dynamic fee pools have an initial fee of 0.
    /// @dev if a dynamic fee pool wants a non-0 initial fee, it should call `updateDynamicLPFee` in the afterInitialize hook
    /// @param self The fee to get the initial LP from
    /// @return initialFee 0 if the fee is dynamic, otherwise the fee (if valid)
    function getInitialLPFee(uint24 self) internal pure returns (uint24) {
        // the initial fee for a dynamic fee pool is 0
        if (self.isDynamicFee()) return 0;
        self.validate();
        return self;
    }

    /// @notice returns true if the fee has the override flag set (2nd highest bit of the uint24)
    /// @param self The fee to check
    /// @return bool True of the fee has the override flag set
    function isOverride(uint24 self) internal pure returns (bool) {
        return self & OVERRIDE_FEE_FLAG != 0;
    }

    /// @notice returns a fee with the override flag removed
    /// @param self The fee to remove the override flag from
    /// @return fee The fee without the override flag set
    function removeOverrideFlag(uint24 self) internal pure returns (uint24) {
        return self & REMOVE_OVERRIDE_MASK;
    }

    /// @notice Removes the override flag and validates the fee (reverts if the fee is too large)
    /// @param self The fee to remove the override flag from, and then validate
    /// @return fee The fee without the override flag set (if valid)
    function removeOverrideFlagAndValidate(uint24 self) internal pure returns (uint24 fee) {
        fee = self.removeOverrideFlag();
        fee.validate();
    }
}


================================================
FILE: src/libraries/LiquidityMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Math library for liquidity
library LiquidityMath {
    /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows
    /// @param x The liquidity before change
    /// @param y The delta by which liquidity should be changed
    /// @return z The liquidity delta
    function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) {
        assembly ("memory-safe") {
            z := add(and(x, 0xffffffffffffffffffffffffffffffff), signextend(15, y))
            if shr(128, z) {
                // revert SafeCastOverflow()
                mstore(0, 0x93dafdf1)
                revert(0x1c, 0x04)
            }
        }
    }
}


================================================
FILE: src/libraries/Lock.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

/// @notice This is a temporary library that allows us to use transient storage (tstore/tload)
/// TODO: This library can be deleted when we have the transient keyword support in solidity.
library Lock {
    // The slot holding the unlocked state, transiently. bytes32(uint256(keccak256("Unlocked")) - 1)
    bytes32 internal constant IS_UNLOCKED_SLOT = 0xc090fc4683624cfc3884e9d8de5eca132f2d0ec062aff75d43c0465d5ceeab23;

    function unlock() internal {
        assembly ("memory-safe") {
            // unlock
            tstore(IS_UNLOCKED_SLOT, true)
        }
    }

    function lock() internal {
        assembly ("memory-safe") {
            tstore(IS_UNLOCKED_SLOT, false)
        }
    }

    function isUnlocked() internal view returns (bool unlocked) {
        assembly ("memory-safe") {
            unlocked := tload(IS_UNLOCKED_SLOT)
        }
    }
}


================================================
FILE: src/libraries/NonzeroDeltaCount.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

/// @notice This is a temporary library that allows us to use transient storage (tstore/tload)
/// for the nonzero delta count.
/// TODO: This library can be deleted when we have the transient keyword support in solidity.
library NonzeroDeltaCount {
    // The slot holding the number of nonzero deltas. bytes32(uint256(keccak256("NonzeroDeltaCount")) - 1)
    bytes32 internal constant NONZERO_DELTA_COUNT_SLOT =
        0x7d4b3164c6e45b97e7d87b7125a44c5828d005af88f9d751cfd78729c5d99a0b;

    function read() internal view returns (uint256 count) {
        assembly ("memory-safe") {
            count := tload(NONZERO_DELTA_COUNT_SLOT)
        }
    }

    function increment() internal {
        assembly ("memory-safe") {
            let count := tload(NONZERO_DELTA_COUNT_SLOT)
            count := add(count, 1)
            tstore(NONZERO_DELTA_COUNT_SLOT, count)
        }
    }

    /// @notice Potential to underflow. Ensure checks are performed by integrating contracts to ensure this does not happen.
    /// Current usage ensures this will not happen because we call decrement with known boundaries (only up to the number of times we call increment).
    function decrement() internal {
        assembly ("memory-safe") {
            let count := tload(NONZERO_DELTA_COUNT_SLOT)
            count := sub(count, 1)
            tstore(NONZERO_DELTA_COUNT_SLOT, count)
        }
    }
}


================================================
FILE: src/libraries/ParseBytes.sol
================================================
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @notice Parses bytes returned from hooks and the byte selector used to check return selectors from hooks.
/// @dev parseSelector also is used to parse the expected selector
/// For parsing hook returns, note that all hooks return either bytes4 or (bytes4, 32-byte-delta) or (bytes4, 32-byte-delta, uint24).
library ParseBytes {
    function parseSelector(bytes memory result) internal pure returns (bytes4 selector) {
        // equivalent: (selector,) = abi.decode(result, (bytes4, int256));
        assembly ("memory-safe") {
            selector := mload(add(result, 0x20))
        }
    }

    function parseFee(bytes memory result) internal pure returns (uint24 lpFee) {
        // equivalent: (,, lpFee) = abi.decode(result, (bytes4, int256, uint24));
        assembly ("memory-safe") {
            lpFee := mload(add(result, 0x60))
        }
    }

    function parseReturnDelta(bytes memory result) internal pure returns (int256 hookReturn) {
        // equivalent: (, hookReturnDelta) = abi.decode(result, (bytes4, int256));
        assembly ("memory-safe") {
            hookReturn := mload(add(result, 0x40))
        }
    }
}


================================================
FILE: src/libraries/Pool.sol
================================================
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {SafeCast} from "./SafeCast.sol";
import {TickBitmap} from "./TickBitmap.sol";
import {Position} from "./Position.sol";
import {UnsafeMath} from "./UnsafeMath.sol";
import {FixedPoint128} from "./FixedPoint128.sol";
import {TickMath} from "./TickMath.sol";
import {SqrtPriceMath} from "./SqrtPriceMath.sol";
import {SwapMath} from "./SwapMath.sol";
import {BalanceDelta, toBalanceDelta, BalanceDeltaLibrary} from "../types/BalanceDelta.sol";
import {Slot0} from "../types/Slot0.sol";
import {ProtocolFeeLibrary} from "./ProtocolFeeLibrary.sol";
import {LiquidityMath} from "./LiquidityMath.sol";
import {LPFeeLibrary} from "./LPFeeLibrary.sol";
import {CustomRevert} from "./CustomRevert.sol";

/// @notice a library with all actions that can be performed on a pool
library Pool {
    using SafeCast for *;
    using TickBitmap for mapping(int16 => uint256);
    using Position for mapping(bytes32 => Position.State);
    using Position for Position.State;
    using Pool for State;
    using ProtocolFeeLibrary for *;
    using LPFeeLibrary for uint24;
    using CustomRevert for bytes4;

    /// @notice Thrown when tickLower is not below tickUpper
    /// @param tickLower The invalid tickLower
    /// @param tickUpper The invalid tickUpper
    error TicksMisordered(int24 tickLower, int24 tickUpper);

    /// @notice Thrown when tickLower is less than min tick
    /// @param tickLower The invalid tickLower
    error TickLowerOutOfBounds(int24 tickLower);

    /// @notice Thrown when tickUpper exceeds max tick
    /// @param tickUpper The invalid tickUpper
    error TickUpperOutOfBounds(int24 tickUpper);

    /// @notice For the tick spacing, the tick has too much liquidity
    error TickLiquidityOverflow(int24 tick);

    /// @notice Thrown when trying to initialize an already initialized pool
    error PoolAlreadyInitialized();

    /// @notice Thrown when trying to interact with a non-initialized pool
    error PoolNotInitialized();

    /// @notice Thrown when sqrtPriceLimitX96 on a swap has already exceeded its limit
    /// @param sqrtPriceCurrentX96 The invalid, already surpassed sqrtPriceLimitX96
    /// @param sqrtPriceLimitX96 The surpassed price limit
    error PriceLimitAlreadyExceeded(uint160 sqrtPriceCurrentX96, uint160 sqrtPriceLimitX96);

    /// @notice Thrown when sqrtPriceLimitX96 lies outside of valid tick/price range
    /// @param sqrtPriceLimitX96 The invalid, out-of-bounds sqrtPriceLimitX96
    error PriceLimitOutOfBounds(uint160 sqrtPriceLimitX96);

    /// @notice Thrown by donate if there is currently 0 liquidity, since the fees will not go to any liquidity providers
    error NoLiquidityToReceiveFees();

    /// @notice Thrown when trying to swap with max lp fee and specifying an output amount
    error InvalidFeeForExactOut();

    // info stored for each initialized individual tick
    struct TickInfo {
        // the total position liquidity that references this tick
        uint128 liquidityGross;
        // amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left),
        int128 liquidityNet;
        // fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick)
        // only has relative meaning, not absolute — the value depends on when the tick is initialized
        uint256 feeGrowthOutside0X128;
        uint256 feeGrowthOutside1X128;
    }

    /// @notice The state of a pool
    /// @dev Note that feeGrowthGlobal can be artificially inflated
    /// For pools with a single liquidity position, actors can donate to themselves to freely inflate feeGrowthGlobal
    /// atomically donating and collecting fees in the same unlockCallback may make the inflated value more extreme
    struct State {
        Slot0 slot0;
        uint256 feeGrowthGlobal0X128;
        uint256 feeGrowthGlobal1X128;
        uint128 liquidity;
        mapping(int24 tick => TickInfo) ticks;
        mapping(int16 wordPos => uint256) tickBitmap;
        mapping(bytes32 positionKey => Position.State) positions;
    }

    /// @dev Common checks for valid tick inputs.
    function checkTicks(int24 tickLower, int24 tickUpper) private pure {
        if (tickLower >= tickUpper) TicksMisordered.selector.revertWith(tickLower, tickUpper);
        if (tickLower < TickMath.MIN_TICK) TickLowerOutOfBounds.selector.revertWith(tickLower);
        if (tickUpper > TickMath.MAX_TICK) TickUpperOutOfBounds.selector.revertWith(tickUpper);
    }

    function initialize(State storage self, uint160 sqrtPriceX96, uint24 lpFee) internal returns (int24 tick) {
        if (self.slot0.sqrtPriceX96() != 0) PoolAlreadyInitialized.selector.revertWith();

        tick = TickMath.getTickAtSqrtPrice(sqrtPriceX96);

        // the initial protocolFee is 0 so doesn't need to be set
        self.slot0 = Slot0.wrap(bytes32(0)).setSqrtPriceX96(sqrtPriceX96).setTick(tick).setLpFee(lpFee);
    }

    function setProtocolFee(State storage self, uint24 protocolFee) internal {
        self.checkPoolInitialized();
        self.slot0 = self.slot0.setProtocolFee(protocolFee);
    }

    /// @notice Only dynamic fee pools may update the lp fee.
    function setLPFee(State storage self, uint24 lpFee) internal {
        self.checkPoolInitialized();
        self.slot0 = self.slot0.setLpFee(lpFee);
    }

    struct ModifyLiquidityParams {
        // the address that owns the position
        address owner;
        // the lower and upper tick of the position
        int24 tickLower;
        int24 tickUpper;
        // any change in liquidity
        int128 liquidityDelta;
        // the spacing between ticks
        int24 tickSpacing;
        // used to distinguish positions of the same owner, at the same tick range
        bytes32 salt;
    }

    struct ModifyLiquidityState {
        bool flippedLower;
        uint128 liquidityGrossAfterLower;
        bool flippedUpper;
        uint128 liquidityGrossAfterUpper;
    }

    /// @notice Effect changes to a position in a pool
    /// @dev PoolManager checks that the pool is initialized before calling
    /// @param params the position details and the change to the position's liquidity to effect
    /// @return delta the deltas of the token balances of the pool, from the liquidity change
    /// @return feeDelta the fees generated by the liquidity range
    function modifyLiquidity(State storage self, ModifyLiquidityParams memory params)
        internal
        returns (BalanceDelta delta, BalanceDelta feeDelta)
    {
        int128 liquidityDelta = params.liquidityDelta;
        int24 tickLower = params.tickLower;
        int24 tickUpper = params.tickUpper;
        checkTicks(tickLower, tickUpper);

        {
            ModifyLiquidityState memory state;

            // if we need to update the ticks, do it
            if (liquidityDelta != 0) {
                (state.flippedLower, state.liquidityGrossAfterLower) =
                    updateTick(self, tickLower, liquidityDelta, false);
                (state.flippedUpper, state.liquidityGrossAfterUpper) = updateTick(self, tickUpper, liquidityDelta, true);

                // `>` and `>=` are logically equivalent here but `>=` is cheaper
                if (liquidityDelta >= 0) {
                    uint128 maxLiquidityPerTick = tickSpacingToMaxLiquidityPerTick(params.tickSpacing);
                    if (state.liquidityGrossAfterLower > maxLiquidityPerTick) {
                        TickLiquidityOverflow.selector.revertWith(tickLower);
                    }
                    if (state.liquidityGrossAfterUpper > maxLiquidityPerTick) {
                        TickLiquidityOverflow.selector.revertWith(tickUpper);
                    }
                }

                if (state.flippedLower) {
                    self.tickBitmap.flipTick(tickLower, params.tickSpacing);
                }
                if (state.flippedUpper) {
                    self.tickBitmap.flipTick(tickUpper, params.tickSpacing);
                }
            }

            {
                (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) =
                    getFeeGrowthInside(self, tickLower, tickUpper);

                Position.State storage position = self.positions.get(params.owner, tickLower, tickUpper, params.salt);
                (uint256 feesOwed0, uint256 feesOwed1) =
                    position.update(liquidityDelta, feeGrowthInside0X128, feeGrowthInside1X128);

                // Fees earned from LPing are calculated, and returned
                feeDelta = toBalanceDelta(feesOwed0.toInt128(), feesOwed1.toInt128());
            }

            // clear any tick data that is no longer needed
            if (liquidityDelta < 0) {
                if (state.flippedLower) {
                    clearTick(self, tickLower);
                }
                if (state.flippedUpper) {
                    clearTick(self, tickUpper);
                }
            }
        }

        if (liquidityDelta != 0) {
            Slot0 _slot0 = self.slot0;
            (int24 tick, uint160 sqrtPriceX96) = (_slot0.tick(), _slot0.sqrtPriceX96());
            if (tick < tickLower) {
                // current tick is below the passed range; liquidity can only become in range by crossing from left to
                // right, when we'll need _more_ currency0 (it's becoming more valuable) so user must provide it
                delta = toBalanceDelta(
                    SqrtPriceMath.getAmount0Delta(
                        TickMath.getSqrtPriceAtTick(tickLower), TickMath.getSqrtPriceAtTick(tickUpper), liquidityDelta
                    ).toInt128(),
                    0
                );
            } else if (tick < tickUpper) {
                delta = toBalanceDelta(
                    SqrtPriceMath.getAmount0Delta(sqrtPriceX96, TickMath.getSqrtPriceAtTick(tickUpper), liquidityDelta)
                        .toInt128(),
                    SqrtPriceMath.getAmount1Delta(TickMath.getSqrtPriceAtTick(tickLower), sqrtPriceX96, liquidityDelta)
                        .toInt128()
                );

                self.liquidity = LiquidityMath.addDelta(self.liquidity, liquidityDelta);
            } else {
                // current tick is above the passed range; liquidity can only become in range by crossing from right to
                // left, when we'll need _more_ currency1 (it's becoming more valuable) so user must provide it
                delta = toBalanceDelta(
                    0,
                    SqrtPriceMath.getAmount1Delta(
                        TickMath.getSqrtPriceAtTick(tickLower), TickMath.getSqrtPriceAtTick(tickUpper), liquidityDelta
                    ).toInt128()
                );
            }
        }
    }

    // Tracks the state of a pool throughout a swap, and returns these values at the end of the swap
    struct SwapResult {
        // the current sqrt(price)
        uint160 sqrtPriceX96;
        // the tick associated with the current price
        int24 tick;
        // the current liquidity in range
        uint128 liquidity;
    }

    struct StepComputations {
        // the price at the beginning of the step
        uint160 sqrtPriceStartX96;
        // the next tick to swap to from the current tick in the swap direction
        int24 tickNext;
        // whether tickNext is initialized or not
        bool initialized;
        // sqrt(price) for the next tick (1/0)
        uint160 sqrtPriceNextX96;
        // how much is being swapped in in this step
        uint256 amountIn;
        // how much is being swapped out
        uint256 amountOut;
        // how much fee is being paid in
        uint256 feeAmount;
        // the global fee growth of the input token. updated in storage at the end of swap
        uint256 feeGrowthGlobalX128;
    }

    struct SwapParams {
        int256 amountSpecified;
        int24 tickSpacing;
        bool zeroForOne;
        uint160 sqrtPriceLimitX96;
        uint24 lpFeeOverride;
    }

    /// @notice Executes a swap against the state, and returns the amount deltas of the pool
    /// @dev PoolManager checks that the pool is initialized before calling
    function swap(State storage self, SwapParams memory params)
        internal
        returns (BalanceDelta swapDelta, uint256 amountToProtocol, uint24 swapFee, SwapResult memory result)
    {
        Slot0 slot0Start = self.slot0;
        bool zeroForOne = params.zeroForOne;

        uint256 protocolFee =
            zeroForOne ? slot0Start.protocolFee().getZeroForOneFee() : slot0Start.protocolFee().getOneForZeroFee();

        // the amount remaining to be swapped in/out of the input/output asset. initially set to the amountSpecified
        int256 amountSpecifiedRemaining = params.amountSpecified;
        // the amount swapped out/in of the output/input asset. initially set to 0
        int256 amountCalculated = 0;
        // initialize to the current sqrt(price)
        result.sqrtPriceX96 = slot0Start.sqrtPriceX96();
        // initialize to the current tick
        result.tick = slot0Start.tick();
        // initialize to the current liquidity
        result.liquidity = self.liquidity;

        // if the beforeSwap hook returned a valid fee override, use that as the LP fee, otherwise load from storage
        // lpFee, swapFee, and protocolFee are all in pips
        {
            uint24 lpFee = params.lpFeeOverride.isOverride()
                ? params.lpFeeOverride.removeOverrideFlagAndValidate()
                : slot0Start.lpFee();

            swapFee = protocolFee == 0 ? lpFee : uint16(protocolFee).calculateSwapFee(lpFee);
        }

        // a swap fee totaling MAX_SWAP_FEE (100%) makes exact output swaps impossible since the input is entirely consumed by the fee
        if (swapFee >= SwapMath.MAX_SWAP_FEE) {
            // if exactOutput
            if (params.amountSpecified > 0) {
                InvalidFeeForExactOut.selector.revertWith();
            }
        }

        // swapFee is the pool's fee in pips (LP fee + protocol fee)
        // when the amount swapped is 0, there is no protocolFee applied and the fee amount paid to the protocol is set to 0
        if (params.amountSpecified == 0) return (BalanceDeltaLibrary.ZERO_DELTA, 0, swapFee, result);

        if (zeroForOne) {
            if (params.sqrtPriceLimitX96 >= slot0Start.sqrtPriceX96()) {
                PriceLimitAlreadyExceeded.selector.revertWith(slot0Start.sqrtPriceX96(), params.sqrtPriceLimitX96);
            }
            // Swaps can never occur at MIN_TICK, only at MIN_TICK + 1, except at initialization of a pool
            // Under certain circumstances outlined below, the tick will preemptively reach MIN_TICK without swapping there
            if (params.sqrtPriceLimitX96 <= TickMath.MIN_SQRT_PRICE) {
                PriceLimitOutOfBounds.selector.revertWith(params.sqrtPriceLimitX96);
            }
        } else {
            if (params.sqrtPriceLimitX96 <= slot0Start.sqrtPriceX96()) {
                PriceLimitAlreadyExceeded.selector.revertWith(slot0Start.sqrtPriceX96(), params.sqrtPriceLimitX96);
            }
            if (params.sqrtPriceLimitX96 >= TickMath.MAX_SQRT_PRICE) {
                PriceLimitOutOfBounds.selector.revertWith(params.sqrtPriceLimitX96);
            }
        }

        StepComputations memory step;
        step.feeGrowthGlobalX128 = zeroForOne ? self.feeGrowthGlobal0X128 : self.feeGrowthGlobal1X128;

        // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit
        while (!(amountSpecifiedRemaining == 0 || result.sqrtPriceX96 == params.sqrtPriceLimitX96)) {
            step.sqrtPriceStartX96 = result.sqrtPriceX96;

            (step.tickNext, step.initialized) =
                self.tickBitmap.nextInitializedTickWithinOneWord(result.tick, params.tickSpacing, zeroForOne);

            // ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds
            if (step.tickNext <= TickMath.MIN_TICK) {
                step.tickNext = TickMath.MIN_TICK;
            }
            if (step.tickNext >= TickMath.MAX_TICK) {
                step.tickNext = TickMath.MAX_TICK;
            }

            // get the price for the next tick
            step.sqrtPriceNextX96 = TickMath.getSqrtPriceAtTick(step.tickNext);

            // compute values to swap to the target tick, price limit, or point where input/output amount is exhausted
            (result.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount) = SwapMath.computeSwapStep(
                result.sqrtPriceX96,
                SwapMath.getSqrtPriceTarget(zeroForOne, step.sqrtPriceNextX96, params.sqrtPriceLimitX96),
                result.liquidity,
                amountSpecifiedRemaining,
                swapFee
            );

            // if exactOutput
            if (params.amountSpecified > 0) {
                unchecked {
                    amountSpecifiedRemaining -= step.amountOut.toInt256();
                }
                amountCalculated -= (step.amountIn + step.feeAmount).toInt256();
            } else {
                // safe because we test that amountSpecified > amountIn + feeAmount in SwapMath
                unchecked {
                    amountSpecifiedRemaining += (step.amountIn + step.feeAmount).toInt256();
                }
                amountCalculated += step.amountOut.toInt256();
            }

            // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee
            if (protocolFee > 0) {
                unchecked {
                    // step.amountIn does not include the swap fee, as it's already been taken from it,
                    // so add it back to get the total amountIn and use that to calculate the amount of fees owed to the protocol
                    // cannot overflow due to limits on the size of protocolFee and params.amountSpecified
                    // this rounds down to favor LPs over the protocol
                    uint256 delta = (swapFee == protocolFee)
                        ? step.feeAmount // lp fee is 0, so the entire fee is owed to the protocol instead
                        : (step.amountIn + step.feeAmount) * protocolFee / ProtocolFeeLibrary.PIPS_DENOMINATOR;
                    // subtract it from the total fee and add it to the protocol fee
                    step.feeAmount -= delta;
                    amountToProtocol += delta;
                }
            }

   
Download .txt
gitextract_ps96d9yk/

├── .gitattributes
├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.yml
│   │   └── FEATURE_IMPROVEMENT.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── deploy.yaml
│       ├── lint.yml
│       ├── mythx.yml
│       ├── tests-merge.yml
│       └── tests-pr.yml
├── .gitignore
├── .gitmodules
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .solhint.json
├── CONTRIBUTING.md
├── README.md
├── SECURITY.md
├── docs/
│   └── whitepaper/
│       └── latex/
│           ├── main-zh.tex
│           ├── main.bib
│           └── main.tex
├── echidna.config.yml
├── foundry.toml
├── justfile
├── licenses/
│   ├── BUSL_LICENSE
│   └── MIT_LICENSE
├── package.json
├── remappings.txt
├── snapshots/
│   ├── ClearTest.json
│   ├── CustomAccountingTest.json
│   ├── ERC6909ClaimsTest.json
│   ├── ExtsloadTest.json
│   ├── ModifyLiquidityTest.json
│   ├── PoolManagerInitializeTest.json
│   ├── PoolManagerTest.json
│   ├── ProtocolFeesTest.json
│   ├── SkipCallsTest.json
│   ├── SqrtPriceMathTest.json
│   ├── StateLibraryTest.json
│   ├── SwapMathTest.json
│   ├── SyncTest.json
│   ├── TestBitMath.json
│   ├── TestDelegateCall.json
│   ├── TestDynamicFees.json
│   ├── TestDynamicReturnFees.json
│   ├── TickBitmapTest.json
│   ├── TickMathTestTest.json
│   └── TickTest.json
├── src/
│   ├── ERC6909.sol
│   ├── ERC6909Claims.sol
│   ├── Extsload.sol
│   ├── Exttload.sol
│   ├── NoDelegateCall.sol
│   ├── PoolManager.sol
│   ├── ProtocolFees.sol
│   ├── interfaces/
│   │   ├── IExtsload.sol
│   │   ├── IExttload.sol
│   │   ├── IHooks.sol
│   │   ├── IPoolManager.sol
│   │   ├── IProtocolFees.sol
│   │   ├── callback/
│   │   │   └── IUnlockCallback.sol
│   │   └── external/
│   │       ├── IERC20Minimal.sol
│   │       └── IERC6909Claims.sol
│   ├── libraries/
│   │   ├── BitMath.sol
│   │   ├── CurrencyDelta.sol
│   │   ├── CurrencyReserves.sol
│   │   ├── CustomRevert.sol
│   │   ├── FixedPoint128.sol
│   │   ├── FixedPoint96.sol
│   │   ├── FullMath.sol
│   │   ├── Hooks.sol
│   │   ├── LPFeeLibrary.sol
│   │   ├── LiquidityMath.sol
│   │   ├── Lock.sol
│   │   ├── NonzeroDeltaCount.sol
│   │   ├── ParseBytes.sol
│   │   ├── Pool.sol
│   │   ├── Position.sol
│   │   ├── ProtocolFeeLibrary.sol
│   │   ├── SafeCast.sol
│   │   ├── SqrtPriceMath.sol
│   │   ├── StateLibrary.sol
│   │   ├── SwapMath.sol
│   │   ├── TickBitmap.sol
│   │   ├── TickMath.sol
│   │   ├── TransientStateLibrary.sol
│   │   └── UnsafeMath.sol
│   ├── test/
│   │   ├── ActionsRouter.sol
│   │   ├── BaseTestHooks.sol
│   │   ├── CurrencyTest.sol
│   │   ├── CustomCurveHook.sol
│   │   ├── DeltaReturningHook.sol
│   │   ├── DynamicFeesTestHook.sol
│   │   ├── DynamicReturnFeeTestHook.sol
│   │   ├── EmptyRevertContract.sol
│   │   ├── EmptyTestHooks.sol
│   │   ├── FeeTakingHook.sol
│   │   ├── Fuzzers.sol
│   │   ├── HooksTest.sol
│   │   ├── LPFeeTakingHook.sol
│   │   ├── LiquidityMathTest.sol
│   │   ├── MockContract.sol
│   │   ├── MockERC6909Claims.sol
│   │   ├── MockHooks.sol
│   │   ├── NativeERC20.sol
│   │   ├── NoDelegateCallTest.sol
│   │   ├── PoolClaimsTest.sol
│   │   ├── PoolDonateTest.sol
│   │   ├── PoolEmptyUnlockTest.sol
│   │   ├── PoolModifyLiquidityTest.sol
│   │   ├── PoolModifyLiquidityTestNoChecks.sol
│   │   ├── PoolNestedActionsTest.sol
│   │   ├── PoolSwapTest.sol
│   │   ├── PoolTakeTest.sol
│   │   ├── PoolTestBase.sol
│   │   ├── ProtocolFeesImplementation.sol
│   │   ├── ProxyPoolManager.sol
│   │   ├── SkipCallsTestHook.sol
│   │   ├── SqrtPriceMathEchidnaTest.sol
│   │   ├── SwapRouterNoChecks.sol
│   │   ├── TestERC20.sol
│   │   ├── TestInvalidERC20.sol
│   │   ├── TickMathEchidnaTest.sol
│   │   ├── TickMathTest.sol
│   │   └── TickOverflowSafetyEchidnaTest.sol
│   └── types/
│       ├── BalanceDelta.sol
│       ├── BeforeSwapDelta.sol
│       ├── Currency.sol
│       ├── PoolId.sol
│       ├── PoolKey.sol
│       ├── PoolOperation.sol
│       └── Slot0.sol
└── test/
    ├── CurrencyReserves.t.sol
    ├── CustomAccounting.t.sol
    ├── DynamicFees.t.sol
    ├── DynamicReturnFees.t.sol
    ├── ERC6909Claims.t.sol
    ├── Extsload.t.sol
    ├── ModifyLiquidity.t.sol
    ├── NoDelegateCall.t.sol
    ├── PoolManager.clear.t.sol
    ├── PoolManager.gas.spec.ts
    ├── PoolManager.swap.t.sol
    ├── PoolManager.t.sol
    ├── PoolManagerInitialize.t.sol
    ├── ProtocolFeesImplementation.t.sol
    ├── SkipCallsTestHook.t.sol
    ├── Sync.t.sol
    ├── Tick.t.sol
    ├── bin/
    │   └── v3Factory.bytecode
    ├── js-scripts/
    │   ├── build.js
    │   ├── dist/
    │   │   ├── getModifyLiquidityResult.js
    │   │   ├── getSqrtPriceAtTick.js
    │   │   └── getTickAtSqrtPrice.js
    │   ├── package.json
    │   ├── src/
    │   │   ├── getModifyLiquidityResult.ts
    │   │   ├── getSqrtPriceAtTick.ts
    │   │   ├── getTickAtSqrtPrice.ts
    │   │   └── utils/
    │   │       └── shared.ts
    │   └── tsconfig.json
    ├── libraries/
    │   ├── BitMath.t.sol
    │   ├── FullMath.t.sol
    │   ├── Hooks.t.sol
    │   ├── LPFeeLibrary.t.sol
    │   ├── LiquidityMath.t.sol
    │   ├── Lock.t.sol
    │   ├── NonzeroDeltaCount.t.sol
    │   ├── Pool.t.sol
    │   ├── PoolId.t.sol
    │   ├── Position.t.sol
    │   ├── ProtocolFeeLibrary.t.sol
    │   ├── SafeCast.t.sol
    │   ├── SqrtPriceMath.t.sol
    │   ├── StateLibrary.t.sol
    │   ├── SwapMath.t.sol
    │   ├── TickBitmap.t.sol
    │   ├── TickMath.t.sol
    │   └── UnsafeMath.t.sol
    ├── types/
    │   ├── BalanceDelta.t.sol
    │   ├── Currency.t.sol
    │   └── Slot0.t.sol
    └── utils/
        ├── AmountHelpers.sol
        ├── Constants.sol
        ├── CurrencySettler.sol
        ├── Deployers.sol
        ├── JavascriptFfi.sol
        ├── LiquidityAmounts.sol
        ├── Logger.sol
        ├── NestedActions.t.sol
        ├── SortTokens.sol
        ├── SwapHelper.t.sol
        └── V3Helper.sol
Download .txt
SYMBOL INDEX (556 symbols across 5 files)

FILE: test/js-scripts/dist/getModifyLiquidityResult.js
  method "node_modules/bn.js/lib/bn.js" (line 30) | "node_modules/bn.js/lib/bn.js"(exports2, module2) {
  method "node_modules/@ethersproject/logger/lib/_version.js" (line 2836) | "node_modules/@ethersproject/logger/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/logger/lib/index.js" (line 2846) | "node_modules/@ethersproject/logger/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/_version.js" (line 3124) | "node_modules/@ethersproject/bytes/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/index.js" (line 3134) | "node_modules/@ethersproject/bytes/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/_version.js" (line 3518) | "node_modules/@ethersproject/bignumber/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/bignumber.js" (line 3528) | "node_modules/@ethersproject/bignumber/lib/bignumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/fixednumber.js" (line 3818) | "node_modules/@ethersproject/bignumber/lib/fixednumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/index.js" (line 4183) | "node_modules/@ethersproject/bignumber/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/_version.js" (line 4216) | "node_modules/@ethersproject/properties/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/index.js" (line 4226) | "node_modules/@ethersproject/properties/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/_version.js" (line 4461) | "node_modules/@ethersproject/abi/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/fragments.js" (line 4471) | "node_modules/@ethersproject/abi/lib/fragments.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js" (line 5377) | "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js"(exports2) {
  method "node_modules/js-sha3/src/sha3.js" (line 5562) | "node_modules/js-sha3/src/sha3.js"(exports2, module2) {
  method "node_modules/@ethersproject/keccak256/lib/index.js" (line 6211) | "node_modules/@ethersproject/keccak256/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/_version.js" (line 6229) | "node_modules/@ethersproject/rlp/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/index.js" (line 6239) | "node_modules/@ethersproject/rlp/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/_version.js" (line 6361) | "node_modules/@ethersproject/address/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/index.js" (line 6371) | "node_modules/@ethersproject/address/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/address.js" (line 6507) | "node_modules/@ethersproject/abi/lib/coders/address.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/anonymous.js" (line 6563) | "node_modules/@ethersproject/abi/lib/coders/anonymous.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/array.js" (line 6614) | "node_modules/@ethersproject/abi/lib/coders/array.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/boolean.js" (line 6846) | "node_modules/@ethersproject/abi/lib/coders/boolean.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/bytes.js" (line 6895) | "node_modules/@ethersproject/abi/lib/coders/bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js" (line 6962) | "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/null.js" (line 7020) | "node_modules/@ethersproject/abi/lib/coders/null.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/addresses.js" (line 7073) | "node_modules/@ethersproject/constants/lib/addresses.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/bignumbers.js" (line 7083) | "node_modules/@ethersproject/constants/lib/bignumbers.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/hashes.js" (line 7109) | "node_modules/@ethersproject/constants/lib/hashes.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/strings.js" (line 7119) | "node_modules/@ethersproject/constants/lib/strings.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/index.js" (line 7129) | "node_modules/@ethersproject/constants/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/number.js" (line 7175) | "node_modules/@ethersproject/abi/lib/coders/number.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/_version.js" (line 7249) | "node_modules/@ethersproject/strings/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/utf8.js" (line 7259) | "node_modules/@ethersproject/strings/lib/utf8.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/bytes32.js" (line 7479) | "node_modules/@ethersproject/strings/lib/bytes32.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/idna.js" (line 7514) | "node_modules/@ethersproject/strings/lib/idna.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/index.js" (line 7704) | "node_modules/@ethersproject/strings/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/string.js" (line 7746) | "node_modules/@ethersproject/abi/lib/coders/string.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/tuple.js" (line 7796) | "node_modules/@ethersproject/abi/lib/coders/tuple.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/abi-coder.js" (line 7885) | "node_modules/@ethersproject/abi/lib/abi-coder.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/id.js" (line 8004) | "node_modules/@ethersproject/hash/lib/id.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/_version.js" (line 8019) | "node_modules/@ethersproject/hash/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/namehash.js" (line 8029) | "node_modules/@ethersproject/hash/lib/namehash.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/message.js" (line 8079) | "node_modules/@ethersproject/hash/lib/message.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/typed-data.js" (line 8103) | "node_modules/@ethersproject/hash/lib/typed-data.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/index.js" (line 8655) | "node_modules/@ethersproject/hash/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/interface.js" (line 8686) | "node_modules/@ethersproject/abi/lib/interface.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/index.js" (line 9304) | "node_modules/@ethersproject/abi/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/_version.js" (line 9358) | "node_modules/@ethersproject/abstract-provider/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/index.js" (line 9368) | "node_modules/@ethersproject/abstract-provider/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/_version.js" (line 9624) | "node_modules/@ethersproject/abstract-signer/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/index.js" (line 9634) | "node_modules/@ethersproject/abstract-signer/lib/index.js"(exports2) {
  method "node_modules/elliptic/package.json" (line 10125) | "node_modules/elliptic/package.json"(exports2, module2) {
  method "node_modules/minimalistic-assert/index.js" (line 10187) | "node_modules/minimalistic-assert/index.js"(exports2, module2) {
  method "node_modules/minimalistic-crypto-utils/lib/utils.js" (line 10202) | "node_modules/minimalistic-crypto-utils/lib/utils.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/utils.js" (line 10261) | "node_modules/elliptic/lib/elliptic/utils.js"(exports2) {
  method "node_modules/brorand/index.js" (line 10364) | "node_modules/brorand/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/base.js" (line 10421) | "node_modules/elliptic/lib/elliptic/curve/base.js"(exports2, module2) {
  method "node_modules/inherits/inherits_browser.js" (line 10743) | "node_modules/inherits/inherits_browser.js"(exports2, module2) {
  method "node_modules/inherits/inherits.js" (line 10775) | "node_modules/inherits/inherits.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/short.js" (line 10789) | "node_modules/elliptic/lib/elliptic/curve/short.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/mont.js" (line 11487) | "node_modules/elliptic/lib/elliptic/curve/mont.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/edwards.js" (line 11615) | "node_modules/elliptic/lib/elliptic/curve/edwards.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/index.js" (line 11916) | "node_modules/elliptic/lib/elliptic/curve/index.js"(exports2) {
  method "node_modules/hash.js/lib/hash/utils.js" (line 11928) | "node_modules/hash.js/lib/hash/utils.js"(exports2) {
  method "node_modules/hash.js/lib/hash/common.js" (line 12173) | "node_modules/hash.js/lib/hash/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/common.js" (line 12252) | "node_modules/hash.js/lib/hash/sha/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/1.js" (line 12298) | "node_modules/hash.js/lib/hash/sha/1.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/256.js" (line 12370) | "node_modules/hash.js/lib/hash/sha/256.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/224.js" (line 12522) | "node_modules/hash.js/lib/hash/sha/224.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/512.js" (line 12558) | "node_modules/hash.js/lib/hash/sha/512.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/384.js" (line 12997) | "node_modules/hash.js/lib/hash/sha/384.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha.js" (line 13041) | "node_modules/hash.js/lib/hash/sha.js"(exports2) {
  method "node_modules/hash.js/lib/hash/ripemd.js" (line 13053) | "node_modules/hash.js/lib/hash/ripemd.js"(exports2) {
  method "node_modules/hash.js/lib/hash/hmac.js" (line 13494) | "node_modules/hash.js/lib/hash/hmac.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash.js" (line 13535) | "node_modules/hash.js/lib/hash.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js" (line 13553) | "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js"(exports2, ...
  method "node_modules/elliptic/lib/elliptic/curves.js" (line 14339) | "node_modules/elliptic/lib/elliptic/curves.js"(exports2) {
  method "node_modules/hmac-drbg/lib/hmac-drbg.js" (line 14515) | "node_modules/hmac-drbg/lib/hmac-drbg.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/key.js" (line 14609) | "node_modules/elliptic/lib/elliptic/ec/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/signature.js" (line 14703) | "node_modules/elliptic/lib/elliptic/ec/signature.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/index.js" (line 14849) | "node_modules/elliptic/lib/elliptic/ec/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/key.js" (line 15029) | "node_modules/elliptic/lib/elliptic/eddsa/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/signature.js" (line 15103) | "node_modules/elliptic/lib/elliptic/eddsa/signature.js"(exports2, module...
  method "node_modules/elliptic/lib/elliptic/eddsa/index.js" (line 15152) | "node_modules/elliptic/lib/elliptic/eddsa/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic.js" (line 15237) | "node_modules/elliptic/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/elliptic.js" (line 15252) | "node_modules/@ethersproject/signing-key/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/_version.js" (line 15267) | "node_modules/@ethersproject/signing-key/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/index.js" (line 15277) | "node_modules/@ethersproject/signing-key/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/_version.js" (line 15368) | "node_modules/@ethersproject/transactions/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/index.js" (line 15378) | "node_modules/@ethersproject/transactions/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/_version.js" (line 15780) | "node_modules/@ethersproject/contracts/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/index.js" (line 15790) | "node_modules/@ethersproject/contracts/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/basex/lib/index.js" (line 17007) | "node_modules/@ethersproject/basex/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js" (line 17095) | "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/index.js" (line 17113) | "node_modules/@ethersproject/pbkdf2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/types.js" (line 17126) | "node_modules/@ethersproject/sha2/lib/types.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/_version.js" (line 17140) | "node_modules/@ethersproject/sha2/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/sha2.js" (line 17150) | "node_modules/@ethersproject/sha2/lib/sha2.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/index.js" (line 17187) | "node_modules/@ethersproject/sha2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/_version.js" (line 17213) | "node_modules/@ethersproject/wordlists/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlist.js" (line 17223) | "node_modules/@ethersproject/wordlists/lib/wordlist.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-cz.js" (line 17283) | "node_modules/@ethersproject/wordlists/lib/lang-cz.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-en.js" (line 17345) | "node_modules/@ethersproject/wordlists/lib/lang-en.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-es.js" (line 17407) | "node_modules/@ethersproject/wordlists/lib/lang-es.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-fr.js" (line 17498) | "node_modules/@ethersproject/wordlists/lib/lang-fr.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ja.js" (line 17588) | "node_modules/@ethersproject/wordlists/lib/lang-ja.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ko.js" (line 17732) | "node_modules/@ethersproject/wordlists/lib/lang-ko.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-it.js" (line 17824) | "node_modules/@ethersproject/wordlists/lib/lang-it.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-zh.js" (line 17886) | "node_modules/@ethersproject/wordlists/lib/lang-zh.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlists.js" (line 17983) | "node_modules/@ethersproject/wordlists/lib/wordlists.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/index.js" (line 18012) | "node_modules/@ethersproject/wordlists/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/_version.js" (line 18032) | "node_modules/@ethersproject/hdnode/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/index.js" (line 18042) | "node_modules/@ethersproject/hdnode/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/random.js" (line 18353) | "node_modules/@ethersproject/random/lib/random.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/shuffle.js" (line 18368) | "node_modules/@ethersproject/random/lib/shuffle.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/index.js" (line 18388) | "node_modules/@ethersproject/random/lib/index.js"(exports2) {
  method "node_modules/aes-js/index.js" (line 18405) | "node_modules/aes-js/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/_version.js" (line 18957) | "node_modules/@ethersproject/json-wallets/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/utils.js" (line 18967) | "node_modules/@ethersproject/json-wallets/lib/utils.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/crowdsale.js" (line 19033) | "node_modules/@ethersproject/json-wallets/lib/crowdsale.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/inspect.js" (line 19115) | "node_modules/@ethersproject/json-wallets/lib/inspect.js"(exports2) {
  method "node_modules/scrypt-js/scrypt.js" (line 19166) | "node_modules/scrypt-js/scrypt.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/keystore.js" (line 19634) | "node_modules/@ethersproject/json-wallets/lib/keystore.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/index.js" (line 20050) | "node_modules/@ethersproject/json-wallets/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/_version.js" (line 20110) | "node_modules/@ethersproject/wallet/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/index.js" (line 20120) | "node_modules/@ethersproject/wallet/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/_version.js" (line 20453) | "node_modules/@ethersproject/networks/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/index.js" (line 20463) | "node_modules/@ethersproject/networks/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/base64.js" (line 20674) | "node_modules/@ethersproject/base64/lib/base64.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/index.js" (line 20692) | "node_modules/@ethersproject/base64/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/_version.js" (line 20708) | "node_modules/@ethersproject/web/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/geturl.js" (line 20718) | "node_modules/@ethersproject/web/lib/geturl.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/index.js" (line 20927) | "node_modules/@ethersproject/web/lib/index.js"(exports2) {
  method "node_modules/bech32/index.js" (line 21417) | "node_modules/bech32/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/_version.js" (line 21561) | "node_modules/@ethersproject/providers/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/formatter.js" (line 21571) | "node_modules/@ethersproject/providers/lib/formatter.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/base-provider.js" (line 22005) | "node_modules/@ethersproject/providers/lib/base-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-provider.js" (line 24367) | "node_modules/@ethersproject/providers/lib/json-rpc-provider.js"(exports...
  method "node_modules/ws/lib/constants.js" (line 25203) | "node_modules/ws/lib/constants.js"(exports2, module2) {
  method "node_modules/ws/lib/buffer-util.js" (line 25219) | "node_modules/ws/lib/buffer-util.js"(exports2, module2) {
  method "node_modules/ws/lib/limiter.js" (line 25296) | "node_modules/ws/lib/limiter.js"(exports2, module2) {
  method "node_modules/ws/lib/permessage-deflate.js" (line 25346) | "node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
  method "node_modules/ws/lib/validation.js" (line 25722) | "node_modules/ws/lib/validation.js"(exports2, module2) {
  method "node_modules/ws/lib/receiver.js" (line 25778) | "node_modules/ws/lib/receiver.js"(exports2, module2) {
  method "node_modules/ws/lib/sender.js" (line 26188) | "node_modules/ws/lib/sender.js"(exports2, module2) {
  method "node_modules/ws/lib/event-target.js" (line 26547) | "node_modules/ws/lib/event-target.js"(exports2, module2) {
  method "node_modules/ws/lib/extension.js" (line 26684) | "node_modules/ws/lib/extension.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket.js" (line 26974) | "node_modules/ws/lib/websocket.js"(exports2, module2) {
  method "node_modules/ws/lib/stream.js" (line 27612) | "node_modules/ws/lib/stream.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket-server.js" (line 27725) | "node_modules/ws/lib/websocket-server.js"(exports2, module2) {
  method "node_modules/ws/index.js" (line 28015) | "node_modules/ws/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/ws.js" (line 28028) | "node_modules/@ethersproject/providers/lib/ws.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/websocket-provider.js" (line 28042) | "node_modules/@ethersproject/providers/lib/websocket-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js" (line 28453) | "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js"(exp...
  method "node_modules/@ethersproject/providers/lib/alchemy-provider.js" (line 28663) | "node_modules/@ethersproject/providers/lib/alchemy-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/cloudflare-provider.js" (line 28794) | "node_modules/@ethersproject/providers/lib/cloudflare-provider.js"(expor...
  method "node_modules/@ethersproject/providers/lib/etherscan-provider.js" (line 28967) | "node_modules/@ethersproject/providers/lib/etherscan-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/fallback-provider.js" (line 29562) | "node_modules/@ethersproject/providers/lib/fallback-provider.js"(exports...
  method "node_modules/@ethersproject/providers/lib/ipc-provider.js" (line 30333) | "node_modules/@ethersproject/providers/lib/ipc-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/infura-provider.js" (line 30417) | "node_modules/@ethersproject/providers/lib/infura-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js" (line 30577) | "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js"(e...
  method "node_modules/@ethersproject/providers/lib/nodesmith-provider.js" (line 30682) | "node_modules/@ethersproject/providers/lib/nodesmith-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/pocket-provider.js" (line 30756) | "node_modules/@ethersproject/providers/lib/pocket-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/web3-provider.js" (line 30891) | "node_modules/@ethersproject/providers/lib/web3-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/index.js" (line 31056) | "node_modules/@ethersproject/providers/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/_version.js" (line 31198) | "node_modules/@ethersproject/solidity/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/index.js" (line 31208) | "node_modules/@ethersproject/solidity/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/_version.js" (line 31307) | "node_modules/@ethersproject/units/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/index.js" (line 31317) | "node_modules/@ethersproject/units/lib/index.js"(exports2) {
  method "node_modules/ethers/lib/utils.js" (line 31408) | "node_modules/ethers/lib/utils.js"(exports2) {
  method "node_modules/ethers/lib/_version.js" (line 31754) | "node_modules/ethers/lib/_version.js"(exports2) {
  method "node_modules/ethers/lib/ethers.js" (line 31764) | "node_modules/ethers/lib/ethers.js"(exports2) {
  method "node_modules/ethers/lib/index.js" (line 31851) | "node_modules/ethers/lib/index.js"(exports2) {
  method "node_modules/jsbi/dist/jsbi-cjs.js" (line 31945) | "node_modules/jsbi/dist/jsbi-cjs.js"(exports2, module2) {
  method "node_modules/decimal.js/decimal.js" (line 32979) | "node_modules/decimal.js/decimal.js"(exports2, module2) {
  method "node_modules/tiny-invariant/dist/tiny-invariant.cjs.js" (line 35146) | "node_modules/tiny-invariant/dist/tiny-invariant.cjs.js"(exports2, modul...
  method "node_modules/decimal.js-light/decimal.js" (line 35167) | "node_modules/decimal.js-light/decimal.js"(exports2, module2) {
  method "node_modules/big.js/big.js" (line 36153) | "node_modules/big.js/big.js"(exports2, module2) {
  method "node_modules/toformat/toFormat.js" (line 36561) | "node_modules/toformat/toFormat.js"(exports2, module2) {
  method "node_modules/@uniswap/sdk-core/dist/sdk-core.cjs.production.min.js" (line 36676) | "node_modules/@uniswap/sdk-core/dist/sdk-core.cjs.production.min.js"(exp...
  method "node_modules/@uniswap/sdk-core/dist/sdk-core.cjs.development.js" (line 37019) | "node_modules/@uniswap/sdk-core/dist/sdk-core.cjs.development.js"(export...
  method "node_modules/@uniswap/sdk-core/dist/index.js" (line 37852) | "node_modules/@uniswap/sdk-core/dist/index.js"(exports2, module2) {
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/IMulticall.sol/IMulticall.json" (line 37864) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/IMult...
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json" (line 37900) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/NonfungiblePosit...
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/ISelfPermit.sol/ISelfPermit.json" (line 39136) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/ISelf...
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/IPeripheryPaymentsWithFee.sol/IPeripheryPaymentsWithFee.json" (line 39305) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/interfaces/IPeri...
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json" (line 39431) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/...
  method "node_modules/@uniswap/swap-router-contracts/artifacts/contracts/lens/QuoterV2.sol/QuoterV2.json" (line 39639) | "node_modules/@uniswap/swap-router-contracts/artifacts/contracts/lens/Qu...
  method "node_modules/@uniswap/v3-staker/artifacts/contracts/UniswapV3Staker.sol/UniswapV3Staker.json" (line 39921) | "node_modules/@uniswap/v3-staker/artifacts/contracts/UniswapV3Staker.sol...
  method "node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json" (line 40642) | "node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/S...
  method "node_modules/@uniswap/v3-sdk/dist/v3-sdk.cjs.production.min.js" (line 41222) | "node_modules/@uniswap/v3-sdk/dist/v3-sdk.cjs.production.min.js"(exports...
  method "node_modules/@uniswap/v3-sdk/dist/v3-sdk.cjs.development.js" (line 42590) | "node_modules/@uniswap/v3-sdk/dist/v3-sdk.cjs.development.js"(exports2) {
  method "node_modules/@uniswap/v3-sdk/dist/index.js" (line 45127) | "node_modules/@uniswap/v3-sdk/dist/index.js"(exports2, module2) {
  function getSqrtPriceAtTick (line 45146) | function getSqrtPriceAtTick(tick) {
  function getAmount0Delta (line 45149) | function getAmount0Delta(sqrtPriceAX96, sqrtPriceBX96, liquidity2) {
  function getAmount1Delta (line 45156) | function getAmount1Delta(sqrtPriceAX96, sqrtPriceBX96, liquidity2) {
  function modifyLiquidity (line 45173) | function modifyLiquidity(_tickLower, _tickUpper, _liquidity, slot0Tick2,...

FILE: test/js-scripts/dist/getSqrtPriceAtTick.js
  method "node_modules/decimal.js/decimal.js" (line 30) | "node_modules/decimal.js/decimal.js"(exports2, module2) {
  method "node_modules/bn.js/lib/bn.js" (line 2197) | "node_modules/bn.js/lib/bn.js"(exports2, module2) {
  method "node_modules/@ethersproject/logger/lib/_version.js" (line 5003) | "node_modules/@ethersproject/logger/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/logger/lib/index.js" (line 5013) | "node_modules/@ethersproject/logger/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/_version.js" (line 5291) | "node_modules/@ethersproject/bytes/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/index.js" (line 5301) | "node_modules/@ethersproject/bytes/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/_version.js" (line 5685) | "node_modules/@ethersproject/bignumber/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/bignumber.js" (line 5695) | "node_modules/@ethersproject/bignumber/lib/bignumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/fixednumber.js" (line 5985) | "node_modules/@ethersproject/bignumber/lib/fixednumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/index.js" (line 6350) | "node_modules/@ethersproject/bignumber/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/_version.js" (line 6383) | "node_modules/@ethersproject/properties/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/index.js" (line 6393) | "node_modules/@ethersproject/properties/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/_version.js" (line 6628) | "node_modules/@ethersproject/abi/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/fragments.js" (line 6638) | "node_modules/@ethersproject/abi/lib/fragments.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js" (line 7544) | "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js"(exports2) {
  method "node_modules/js-sha3/src/sha3.js" (line 7729) | "node_modules/js-sha3/src/sha3.js"(exports2, module2) {
  method "node_modules/@ethersproject/keccak256/lib/index.js" (line 8378) | "node_modules/@ethersproject/keccak256/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/_version.js" (line 8396) | "node_modules/@ethersproject/rlp/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/index.js" (line 8406) | "node_modules/@ethersproject/rlp/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/_version.js" (line 8528) | "node_modules/@ethersproject/address/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/index.js" (line 8538) | "node_modules/@ethersproject/address/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/address.js" (line 8674) | "node_modules/@ethersproject/abi/lib/coders/address.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/anonymous.js" (line 8730) | "node_modules/@ethersproject/abi/lib/coders/anonymous.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/array.js" (line 8781) | "node_modules/@ethersproject/abi/lib/coders/array.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/boolean.js" (line 9013) | "node_modules/@ethersproject/abi/lib/coders/boolean.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/bytes.js" (line 9062) | "node_modules/@ethersproject/abi/lib/coders/bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js" (line 9129) | "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/null.js" (line 9187) | "node_modules/@ethersproject/abi/lib/coders/null.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/addresses.js" (line 9240) | "node_modules/@ethersproject/constants/lib/addresses.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/bignumbers.js" (line 9250) | "node_modules/@ethersproject/constants/lib/bignumbers.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/hashes.js" (line 9276) | "node_modules/@ethersproject/constants/lib/hashes.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/strings.js" (line 9286) | "node_modules/@ethersproject/constants/lib/strings.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/index.js" (line 9296) | "node_modules/@ethersproject/constants/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/number.js" (line 9342) | "node_modules/@ethersproject/abi/lib/coders/number.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/_version.js" (line 9416) | "node_modules/@ethersproject/strings/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/utf8.js" (line 9426) | "node_modules/@ethersproject/strings/lib/utf8.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/bytes32.js" (line 9646) | "node_modules/@ethersproject/strings/lib/bytes32.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/idna.js" (line 9681) | "node_modules/@ethersproject/strings/lib/idna.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/index.js" (line 9871) | "node_modules/@ethersproject/strings/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/string.js" (line 9913) | "node_modules/@ethersproject/abi/lib/coders/string.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/tuple.js" (line 9963) | "node_modules/@ethersproject/abi/lib/coders/tuple.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/abi-coder.js" (line 10052) | "node_modules/@ethersproject/abi/lib/abi-coder.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/id.js" (line 10171) | "node_modules/@ethersproject/hash/lib/id.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/_version.js" (line 10186) | "node_modules/@ethersproject/hash/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/namehash.js" (line 10196) | "node_modules/@ethersproject/hash/lib/namehash.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/message.js" (line 10246) | "node_modules/@ethersproject/hash/lib/message.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/typed-data.js" (line 10270) | "node_modules/@ethersproject/hash/lib/typed-data.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/index.js" (line 10822) | "node_modules/@ethersproject/hash/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/interface.js" (line 10853) | "node_modules/@ethersproject/abi/lib/interface.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/index.js" (line 11471) | "node_modules/@ethersproject/abi/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/_version.js" (line 11525) | "node_modules/@ethersproject/abstract-provider/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/index.js" (line 11535) | "node_modules/@ethersproject/abstract-provider/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/_version.js" (line 11791) | "node_modules/@ethersproject/abstract-signer/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/index.js" (line 11801) | "node_modules/@ethersproject/abstract-signer/lib/index.js"(exports2) {
  method "node_modules/elliptic/package.json" (line 12292) | "node_modules/elliptic/package.json"(exports2, module2) {
  method "node_modules/minimalistic-assert/index.js" (line 12354) | "node_modules/minimalistic-assert/index.js"(exports2, module2) {
  method "node_modules/minimalistic-crypto-utils/lib/utils.js" (line 12369) | "node_modules/minimalistic-crypto-utils/lib/utils.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/utils.js" (line 12428) | "node_modules/elliptic/lib/elliptic/utils.js"(exports2) {
  method "node_modules/brorand/index.js" (line 12531) | "node_modules/brorand/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/base.js" (line 12588) | "node_modules/elliptic/lib/elliptic/curve/base.js"(exports2, module2) {
  method "node_modules/inherits/inherits_browser.js" (line 12910) | "node_modules/inherits/inherits_browser.js"(exports2, module2) {
  method "node_modules/inherits/inherits.js" (line 12942) | "node_modules/inherits/inherits.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/short.js" (line 12956) | "node_modules/elliptic/lib/elliptic/curve/short.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/mont.js" (line 13654) | "node_modules/elliptic/lib/elliptic/curve/mont.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/edwards.js" (line 13782) | "node_modules/elliptic/lib/elliptic/curve/edwards.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/index.js" (line 14083) | "node_modules/elliptic/lib/elliptic/curve/index.js"(exports2) {
  method "node_modules/hash.js/lib/hash/utils.js" (line 14095) | "node_modules/hash.js/lib/hash/utils.js"(exports2) {
  method "node_modules/hash.js/lib/hash/common.js" (line 14340) | "node_modules/hash.js/lib/hash/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/common.js" (line 14419) | "node_modules/hash.js/lib/hash/sha/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/1.js" (line 14465) | "node_modules/hash.js/lib/hash/sha/1.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/256.js" (line 14537) | "node_modules/hash.js/lib/hash/sha/256.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/224.js" (line 14689) | "node_modules/hash.js/lib/hash/sha/224.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/512.js" (line 14725) | "node_modules/hash.js/lib/hash/sha/512.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/384.js" (line 15164) | "node_modules/hash.js/lib/hash/sha/384.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha.js" (line 15208) | "node_modules/hash.js/lib/hash/sha.js"(exports2) {
  method "node_modules/hash.js/lib/hash/ripemd.js" (line 15220) | "node_modules/hash.js/lib/hash/ripemd.js"(exports2) {
  method "node_modules/hash.js/lib/hash/hmac.js" (line 15661) | "node_modules/hash.js/lib/hash/hmac.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash.js" (line 15702) | "node_modules/hash.js/lib/hash.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js" (line 15720) | "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js"(exports2, ...
  method "node_modules/elliptic/lib/elliptic/curves.js" (line 16506) | "node_modules/elliptic/lib/elliptic/curves.js"(exports2) {
  method "node_modules/hmac-drbg/lib/hmac-drbg.js" (line 16682) | "node_modules/hmac-drbg/lib/hmac-drbg.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/key.js" (line 16776) | "node_modules/elliptic/lib/elliptic/ec/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/signature.js" (line 16870) | "node_modules/elliptic/lib/elliptic/ec/signature.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/index.js" (line 17016) | "node_modules/elliptic/lib/elliptic/ec/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/key.js" (line 17196) | "node_modules/elliptic/lib/elliptic/eddsa/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/signature.js" (line 17270) | "node_modules/elliptic/lib/elliptic/eddsa/signature.js"(exports2, module...
  method "node_modules/elliptic/lib/elliptic/eddsa/index.js" (line 17319) | "node_modules/elliptic/lib/elliptic/eddsa/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic.js" (line 17404) | "node_modules/elliptic/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/elliptic.js" (line 17419) | "node_modules/@ethersproject/signing-key/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/_version.js" (line 17434) | "node_modules/@ethersproject/signing-key/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/index.js" (line 17444) | "node_modules/@ethersproject/signing-key/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/_version.js" (line 17535) | "node_modules/@ethersproject/transactions/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/index.js" (line 17545) | "node_modules/@ethersproject/transactions/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/_version.js" (line 17947) | "node_modules/@ethersproject/contracts/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/index.js" (line 17957) | "node_modules/@ethersproject/contracts/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/basex/lib/index.js" (line 19174) | "node_modules/@ethersproject/basex/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js" (line 19262) | "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/index.js" (line 19280) | "node_modules/@ethersproject/pbkdf2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/types.js" (line 19293) | "node_modules/@ethersproject/sha2/lib/types.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/_version.js" (line 19307) | "node_modules/@ethersproject/sha2/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/sha2.js" (line 19317) | "node_modules/@ethersproject/sha2/lib/sha2.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/index.js" (line 19354) | "node_modules/@ethersproject/sha2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/_version.js" (line 19380) | "node_modules/@ethersproject/wordlists/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlist.js" (line 19390) | "node_modules/@ethersproject/wordlists/lib/wordlist.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-cz.js" (line 19450) | "node_modules/@ethersproject/wordlists/lib/lang-cz.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-en.js" (line 19512) | "node_modules/@ethersproject/wordlists/lib/lang-en.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-es.js" (line 19574) | "node_modules/@ethersproject/wordlists/lib/lang-es.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-fr.js" (line 19665) | "node_modules/@ethersproject/wordlists/lib/lang-fr.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ja.js" (line 19755) | "node_modules/@ethersproject/wordlists/lib/lang-ja.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ko.js" (line 19899) | "node_modules/@ethersproject/wordlists/lib/lang-ko.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-it.js" (line 19991) | "node_modules/@ethersproject/wordlists/lib/lang-it.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-zh.js" (line 20053) | "node_modules/@ethersproject/wordlists/lib/lang-zh.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlists.js" (line 20150) | "node_modules/@ethersproject/wordlists/lib/wordlists.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/index.js" (line 20179) | "node_modules/@ethersproject/wordlists/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/_version.js" (line 20199) | "node_modules/@ethersproject/hdnode/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/index.js" (line 20209) | "node_modules/@ethersproject/hdnode/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/random.js" (line 20520) | "node_modules/@ethersproject/random/lib/random.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/shuffle.js" (line 20535) | "node_modules/@ethersproject/random/lib/shuffle.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/index.js" (line 20555) | "node_modules/@ethersproject/random/lib/index.js"(exports2) {
  method "node_modules/aes-js/index.js" (line 20572) | "node_modules/aes-js/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/_version.js" (line 21124) | "node_modules/@ethersproject/json-wallets/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/utils.js" (line 21134) | "node_modules/@ethersproject/json-wallets/lib/utils.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/crowdsale.js" (line 21200) | "node_modules/@ethersproject/json-wallets/lib/crowdsale.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/inspect.js" (line 21282) | "node_modules/@ethersproject/json-wallets/lib/inspect.js"(exports2) {
  method "node_modules/scrypt-js/scrypt.js" (line 21333) | "node_modules/scrypt-js/scrypt.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/keystore.js" (line 21801) | "node_modules/@ethersproject/json-wallets/lib/keystore.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/index.js" (line 22217) | "node_modules/@ethersproject/json-wallets/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/_version.js" (line 22277) | "node_modules/@ethersproject/wallet/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/index.js" (line 22287) | "node_modules/@ethersproject/wallet/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/_version.js" (line 22620) | "node_modules/@ethersproject/networks/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/index.js" (line 22630) | "node_modules/@ethersproject/networks/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/base64.js" (line 22841) | "node_modules/@ethersproject/base64/lib/base64.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/index.js" (line 22859) | "node_modules/@ethersproject/base64/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/_version.js" (line 22875) | "node_modules/@ethersproject/web/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/geturl.js" (line 22885) | "node_modules/@ethersproject/web/lib/geturl.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/index.js" (line 23094) | "node_modules/@ethersproject/web/lib/index.js"(exports2) {
  method "node_modules/bech32/index.js" (line 23584) | "node_modules/bech32/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/_version.js" (line 23728) | "node_modules/@ethersproject/providers/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/formatter.js" (line 23738) | "node_modules/@ethersproject/providers/lib/formatter.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/base-provider.js" (line 24172) | "node_modules/@ethersproject/providers/lib/base-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-provider.js" (line 26534) | "node_modules/@ethersproject/providers/lib/json-rpc-provider.js"(exports...
  method "node_modules/ws/lib/constants.js" (line 27370) | "node_modules/ws/lib/constants.js"(exports2, module2) {
  method "node_modules/ws/lib/buffer-util.js" (line 27386) | "node_modules/ws/lib/buffer-util.js"(exports2, module2) {
  method "node_modules/ws/lib/limiter.js" (line 27463) | "node_modules/ws/lib/limiter.js"(exports2, module2) {
  method "node_modules/ws/lib/permessage-deflate.js" (line 27513) | "node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
  method "node_modules/ws/lib/validation.js" (line 27889) | "node_modules/ws/lib/validation.js"(exports2, module2) {
  method "node_modules/ws/lib/receiver.js" (line 27945) | "node_modules/ws/lib/receiver.js"(exports2, module2) {
  method "node_modules/ws/lib/sender.js" (line 28355) | "node_modules/ws/lib/sender.js"(exports2, module2) {
  method "node_modules/ws/lib/event-target.js" (line 28714) | "node_modules/ws/lib/event-target.js"(exports2, module2) {
  method "node_modules/ws/lib/extension.js" (line 28851) | "node_modules/ws/lib/extension.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket.js" (line 29141) | "node_modules/ws/lib/websocket.js"(exports2, module2) {
  method "node_modules/ws/lib/stream.js" (line 29779) | "node_modules/ws/lib/stream.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket-server.js" (line 29892) | "node_modules/ws/lib/websocket-server.js"(exports2, module2) {
  method "node_modules/ws/index.js" (line 30182) | "node_modules/ws/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/ws.js" (line 30195) | "node_modules/@ethersproject/providers/lib/ws.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/websocket-provider.js" (line 30209) | "node_modules/@ethersproject/providers/lib/websocket-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js" (line 30620) | "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js"(exp...
  method "node_modules/@ethersproject/providers/lib/alchemy-provider.js" (line 30830) | "node_modules/@ethersproject/providers/lib/alchemy-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/cloudflare-provider.js" (line 30961) | "node_modules/@ethersproject/providers/lib/cloudflare-provider.js"(expor...
  method "node_modules/@ethersproject/providers/lib/etherscan-provider.js" (line 31134) | "node_modules/@ethersproject/providers/lib/etherscan-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/fallback-provider.js" (line 31729) | "node_modules/@ethersproject/providers/lib/fallback-provider.js"(exports...
  method "node_modules/@ethersproject/providers/lib/ipc-provider.js" (line 32500) | "node_modules/@ethersproject/providers/lib/ipc-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/infura-provider.js" (line 32584) | "node_modules/@ethersproject/providers/lib/infura-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js" (line 32744) | "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js"(e...
  method "node_modules/@ethersproject/providers/lib/nodesmith-provider.js" (line 32849) | "node_modules/@ethersproject/providers/lib/nodesmith-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/pocket-provider.js" (line 32923) | "node_modules/@ethersproject/providers/lib/pocket-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/web3-provider.js" (line 33058) | "node_modules/@ethersproject/providers/lib/web3-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/index.js" (line 33223) | "node_modules/@ethersproject/providers/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/_version.js" (line 33365) | "node_modules/@ethersproject/solidity/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/index.js" (line 33375) | "node_modules/@ethersproject/solidity/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/_version.js" (line 33474) | "node_modules/@ethersproject/units/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/index.js" (line 33484) | "node_modules/@ethersproject/units/lib/index.js"(exports2) {
  method "node_modules/ethers/lib/utils.js" (line 33575) | "node_modules/ethers/lib/utils.js"(exports2) {
  method "node_modules/ethers/lib/_version.js" (line 33921) | "node_modules/ethers/lib/_version.js"(exports2) {
  method "node_modules/ethers/lib/ethers.js" (line 33931) | "node_modules/ethers/lib/ethers.js"(exports2) {
  method "node_modules/ethers/lib/index.js" (line 34018) | "node_modules/ethers/lib/index.js"(exports2) {

FILE: test/js-scripts/dist/getTickAtSqrtPrice.js
  method "node_modules/decimal.js/decimal.js" (line 30) | "node_modules/decimal.js/decimal.js"(exports2, module2) {
  method "node_modules/bn.js/lib/bn.js" (line 2197) | "node_modules/bn.js/lib/bn.js"(exports2, module2) {
  method "node_modules/@ethersproject/logger/lib/_version.js" (line 5003) | "node_modules/@ethersproject/logger/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/logger/lib/index.js" (line 5013) | "node_modules/@ethersproject/logger/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/_version.js" (line 5291) | "node_modules/@ethersproject/bytes/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bytes/lib/index.js" (line 5301) | "node_modules/@ethersproject/bytes/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/_version.js" (line 5685) | "node_modules/@ethersproject/bignumber/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/bignumber.js" (line 5695) | "node_modules/@ethersproject/bignumber/lib/bignumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/fixednumber.js" (line 5985) | "node_modules/@ethersproject/bignumber/lib/fixednumber.js"(exports2) {
  method "node_modules/@ethersproject/bignumber/lib/index.js" (line 6350) | "node_modules/@ethersproject/bignumber/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/_version.js" (line 6383) | "node_modules/@ethersproject/properties/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/properties/lib/index.js" (line 6393) | "node_modules/@ethersproject/properties/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/_version.js" (line 6628) | "node_modules/@ethersproject/abi/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/fragments.js" (line 6638) | "node_modules/@ethersproject/abi/lib/fragments.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js" (line 7544) | "node_modules/@ethersproject/abi/lib/coders/abstract-coder.js"(exports2) {
  method "node_modules/js-sha3/src/sha3.js" (line 7729) | "node_modules/js-sha3/src/sha3.js"(exports2, module2) {
  method "node_modules/@ethersproject/keccak256/lib/index.js" (line 8378) | "node_modules/@ethersproject/keccak256/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/_version.js" (line 8396) | "node_modules/@ethersproject/rlp/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/rlp/lib/index.js" (line 8406) | "node_modules/@ethersproject/rlp/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/_version.js" (line 8528) | "node_modules/@ethersproject/address/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/address/lib/index.js" (line 8538) | "node_modules/@ethersproject/address/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/address.js" (line 8674) | "node_modules/@ethersproject/abi/lib/coders/address.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/anonymous.js" (line 8730) | "node_modules/@ethersproject/abi/lib/coders/anonymous.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/array.js" (line 8781) | "node_modules/@ethersproject/abi/lib/coders/array.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/boolean.js" (line 9013) | "node_modules/@ethersproject/abi/lib/coders/boolean.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/bytes.js" (line 9062) | "node_modules/@ethersproject/abi/lib/coders/bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js" (line 9129) | "node_modules/@ethersproject/abi/lib/coders/fixed-bytes.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/null.js" (line 9187) | "node_modules/@ethersproject/abi/lib/coders/null.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/addresses.js" (line 9240) | "node_modules/@ethersproject/constants/lib/addresses.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/bignumbers.js" (line 9250) | "node_modules/@ethersproject/constants/lib/bignumbers.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/hashes.js" (line 9276) | "node_modules/@ethersproject/constants/lib/hashes.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/strings.js" (line 9286) | "node_modules/@ethersproject/constants/lib/strings.js"(exports2) {
  method "node_modules/@ethersproject/constants/lib/index.js" (line 9296) | "node_modules/@ethersproject/constants/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/number.js" (line 9342) | "node_modules/@ethersproject/abi/lib/coders/number.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/_version.js" (line 9416) | "node_modules/@ethersproject/strings/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/utf8.js" (line 9426) | "node_modules/@ethersproject/strings/lib/utf8.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/bytes32.js" (line 9646) | "node_modules/@ethersproject/strings/lib/bytes32.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/idna.js" (line 9681) | "node_modules/@ethersproject/strings/lib/idna.js"(exports2) {
  method "node_modules/@ethersproject/strings/lib/index.js" (line 9871) | "node_modules/@ethersproject/strings/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/string.js" (line 9913) | "node_modules/@ethersproject/abi/lib/coders/string.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/coders/tuple.js" (line 9963) | "node_modules/@ethersproject/abi/lib/coders/tuple.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/abi-coder.js" (line 10052) | "node_modules/@ethersproject/abi/lib/abi-coder.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/id.js" (line 10171) | "node_modules/@ethersproject/hash/lib/id.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/_version.js" (line 10186) | "node_modules/@ethersproject/hash/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/namehash.js" (line 10196) | "node_modules/@ethersproject/hash/lib/namehash.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/message.js" (line 10246) | "node_modules/@ethersproject/hash/lib/message.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/typed-data.js" (line 10270) | "node_modules/@ethersproject/hash/lib/typed-data.js"(exports2) {
  method "node_modules/@ethersproject/hash/lib/index.js" (line 10822) | "node_modules/@ethersproject/hash/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/interface.js" (line 10853) | "node_modules/@ethersproject/abi/lib/interface.js"(exports2) {
  method "node_modules/@ethersproject/abi/lib/index.js" (line 11471) | "node_modules/@ethersproject/abi/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/_version.js" (line 11525) | "node_modules/@ethersproject/abstract-provider/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-provider/lib/index.js" (line 11535) | "node_modules/@ethersproject/abstract-provider/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/_version.js" (line 11791) | "node_modules/@ethersproject/abstract-signer/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/abstract-signer/lib/index.js" (line 11801) | "node_modules/@ethersproject/abstract-signer/lib/index.js"(exports2) {
  method "node_modules/elliptic/package.json" (line 12292) | "node_modules/elliptic/package.json"(exports2, module2) {
  method "node_modules/minimalistic-assert/index.js" (line 12354) | "node_modules/minimalistic-assert/index.js"(exports2, module2) {
  method "node_modules/minimalistic-crypto-utils/lib/utils.js" (line 12369) | "node_modules/minimalistic-crypto-utils/lib/utils.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/utils.js" (line 12428) | "node_modules/elliptic/lib/elliptic/utils.js"(exports2) {
  method "node_modules/brorand/index.js" (line 12531) | "node_modules/brorand/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/base.js" (line 12588) | "node_modules/elliptic/lib/elliptic/curve/base.js"(exports2, module2) {
  method "node_modules/inherits/inherits_browser.js" (line 12910) | "node_modules/inherits/inherits_browser.js"(exports2, module2) {
  method "node_modules/inherits/inherits.js" (line 12942) | "node_modules/inherits/inherits.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/short.js" (line 12956) | "node_modules/elliptic/lib/elliptic/curve/short.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/mont.js" (line 13654) | "node_modules/elliptic/lib/elliptic/curve/mont.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/edwards.js" (line 13782) | "node_modules/elliptic/lib/elliptic/curve/edwards.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/curve/index.js" (line 14083) | "node_modules/elliptic/lib/elliptic/curve/index.js"(exports2) {
  method "node_modules/hash.js/lib/hash/utils.js" (line 14095) | "node_modules/hash.js/lib/hash/utils.js"(exports2) {
  method "node_modules/hash.js/lib/hash/common.js" (line 14340) | "node_modules/hash.js/lib/hash/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/common.js" (line 14419) | "node_modules/hash.js/lib/hash/sha/common.js"(exports2) {
  method "node_modules/hash.js/lib/hash/sha/1.js" (line 14465) | "node_modules/hash.js/lib/hash/sha/1.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/256.js" (line 14537) | "node_modules/hash.js/lib/hash/sha/256.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/224.js" (line 14689) | "node_modules/hash.js/lib/hash/sha/224.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/512.js" (line 14725) | "node_modules/hash.js/lib/hash/sha/512.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha/384.js" (line 15164) | "node_modules/hash.js/lib/hash/sha/384.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash/sha.js" (line 15208) | "node_modules/hash.js/lib/hash/sha.js"(exports2) {
  method "node_modules/hash.js/lib/hash/ripemd.js" (line 15220) | "node_modules/hash.js/lib/hash/ripemd.js"(exports2) {
  method "node_modules/hash.js/lib/hash/hmac.js" (line 15661) | "node_modules/hash.js/lib/hash/hmac.js"(exports2, module2) {
  method "node_modules/hash.js/lib/hash.js" (line 15702) | "node_modules/hash.js/lib/hash.js"(exports2) {
  method "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js" (line 15720) | "node_modules/elliptic/lib/elliptic/precomputed/secp256k1.js"(exports2, ...
  method "node_modules/elliptic/lib/elliptic/curves.js" (line 16506) | "node_modules/elliptic/lib/elliptic/curves.js"(exports2) {
  method "node_modules/hmac-drbg/lib/hmac-drbg.js" (line 16682) | "node_modules/hmac-drbg/lib/hmac-drbg.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/key.js" (line 16776) | "node_modules/elliptic/lib/elliptic/ec/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/signature.js" (line 16870) | "node_modules/elliptic/lib/elliptic/ec/signature.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/ec/index.js" (line 17016) | "node_modules/elliptic/lib/elliptic/ec/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/key.js" (line 17196) | "node_modules/elliptic/lib/elliptic/eddsa/key.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic/eddsa/signature.js" (line 17270) | "node_modules/elliptic/lib/elliptic/eddsa/signature.js"(exports2, module...
  method "node_modules/elliptic/lib/elliptic/eddsa/index.js" (line 17319) | "node_modules/elliptic/lib/elliptic/eddsa/index.js"(exports2, module2) {
  method "node_modules/elliptic/lib/elliptic.js" (line 17404) | "node_modules/elliptic/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/elliptic.js" (line 17419) | "node_modules/@ethersproject/signing-key/lib/elliptic.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/_version.js" (line 17434) | "node_modules/@ethersproject/signing-key/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/signing-key/lib/index.js" (line 17444) | "node_modules/@ethersproject/signing-key/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/_version.js" (line 17535) | "node_modules/@ethersproject/transactions/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/transactions/lib/index.js" (line 17545) | "node_modules/@ethersproject/transactions/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/_version.js" (line 17947) | "node_modules/@ethersproject/contracts/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/contracts/lib/index.js" (line 17957) | "node_modules/@ethersproject/contracts/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/basex/lib/index.js" (line 19174) | "node_modules/@ethersproject/basex/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js" (line 19262) | "node_modules/@ethersproject/pbkdf2/lib/pbkdf2.js"(exports2) {
  method "node_modules/@ethersproject/pbkdf2/lib/index.js" (line 19280) | "node_modules/@ethersproject/pbkdf2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/types.js" (line 19293) | "node_modules/@ethersproject/sha2/lib/types.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/_version.js" (line 19307) | "node_modules/@ethersproject/sha2/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/sha2.js" (line 19317) | "node_modules/@ethersproject/sha2/lib/sha2.js"(exports2) {
  method "node_modules/@ethersproject/sha2/lib/index.js" (line 19354) | "node_modules/@ethersproject/sha2/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/_version.js" (line 19380) | "node_modules/@ethersproject/wordlists/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlist.js" (line 19390) | "node_modules/@ethersproject/wordlists/lib/wordlist.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-cz.js" (line 19450) | "node_modules/@ethersproject/wordlists/lib/lang-cz.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-en.js" (line 19512) | "node_modules/@ethersproject/wordlists/lib/lang-en.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-es.js" (line 19574) | "node_modules/@ethersproject/wordlists/lib/lang-es.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-fr.js" (line 19665) | "node_modules/@ethersproject/wordlists/lib/lang-fr.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ja.js" (line 19755) | "node_modules/@ethersproject/wordlists/lib/lang-ja.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-ko.js" (line 19899) | "node_modules/@ethersproject/wordlists/lib/lang-ko.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-it.js" (line 19991) | "node_modules/@ethersproject/wordlists/lib/lang-it.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/lang-zh.js" (line 20053) | "node_modules/@ethersproject/wordlists/lib/lang-zh.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/wordlists.js" (line 20150) | "node_modules/@ethersproject/wordlists/lib/wordlists.js"(exports2) {
  method "node_modules/@ethersproject/wordlists/lib/index.js" (line 20179) | "node_modules/@ethersproject/wordlists/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/_version.js" (line 20199) | "node_modules/@ethersproject/hdnode/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/hdnode/lib/index.js" (line 20209) | "node_modules/@ethersproject/hdnode/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/random.js" (line 20520) | "node_modules/@ethersproject/random/lib/random.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/shuffle.js" (line 20535) | "node_modules/@ethersproject/random/lib/shuffle.js"(exports2) {
  method "node_modules/@ethersproject/random/lib/index.js" (line 20555) | "node_modules/@ethersproject/random/lib/index.js"(exports2) {
  method "node_modules/aes-js/index.js" (line 20572) | "node_modules/aes-js/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/_version.js" (line 21124) | "node_modules/@ethersproject/json-wallets/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/utils.js" (line 21134) | "node_modules/@ethersproject/json-wallets/lib/utils.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/crowdsale.js" (line 21200) | "node_modules/@ethersproject/json-wallets/lib/crowdsale.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/inspect.js" (line 21282) | "node_modules/@ethersproject/json-wallets/lib/inspect.js"(exports2) {
  method "node_modules/scrypt-js/scrypt.js" (line 21333) | "node_modules/scrypt-js/scrypt.js"(exports2, module2) {
  method "node_modules/@ethersproject/json-wallets/lib/keystore.js" (line 21801) | "node_modules/@ethersproject/json-wallets/lib/keystore.js"(exports2) {
  method "node_modules/@ethersproject/json-wallets/lib/index.js" (line 22217) | "node_modules/@ethersproject/json-wallets/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/_version.js" (line 22277) | "node_modules/@ethersproject/wallet/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/wallet/lib/index.js" (line 22287) | "node_modules/@ethersproject/wallet/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/_version.js" (line 22620) | "node_modules/@ethersproject/networks/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/networks/lib/index.js" (line 22630) | "node_modules/@ethersproject/networks/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/base64.js" (line 22841) | "node_modules/@ethersproject/base64/lib/base64.js"(exports2) {
  method "node_modules/@ethersproject/base64/lib/index.js" (line 22859) | "node_modules/@ethersproject/base64/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/_version.js" (line 22875) | "node_modules/@ethersproject/web/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/geturl.js" (line 22885) | "node_modules/@ethersproject/web/lib/geturl.js"(exports2) {
  method "node_modules/@ethersproject/web/lib/index.js" (line 23094) | "node_modules/@ethersproject/web/lib/index.js"(exports2) {
  method "node_modules/bech32/index.js" (line 23584) | "node_modules/bech32/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/_version.js" (line 23728) | "node_modules/@ethersproject/providers/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/formatter.js" (line 23738) | "node_modules/@ethersproject/providers/lib/formatter.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/base-provider.js" (line 24172) | "node_modules/@ethersproject/providers/lib/base-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-provider.js" (line 26534) | "node_modules/@ethersproject/providers/lib/json-rpc-provider.js"(exports...
  method "node_modules/ws/lib/constants.js" (line 27370) | "node_modules/ws/lib/constants.js"(exports2, module2) {
  method "node_modules/ws/lib/buffer-util.js" (line 27386) | "node_modules/ws/lib/buffer-util.js"(exports2, module2) {
  method "node_modules/ws/lib/limiter.js" (line 27463) | "node_modules/ws/lib/limiter.js"(exports2, module2) {
  method "node_modules/ws/lib/permessage-deflate.js" (line 27513) | "node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
  method "node_modules/ws/lib/validation.js" (line 27889) | "node_modules/ws/lib/validation.js"(exports2, module2) {
  method "node_modules/ws/lib/receiver.js" (line 27945) | "node_modules/ws/lib/receiver.js"(exports2, module2) {
  method "node_modules/ws/lib/sender.js" (line 28355) | "node_modules/ws/lib/sender.js"(exports2, module2) {
  method "node_modules/ws/lib/event-target.js" (line 28714) | "node_modules/ws/lib/event-target.js"(exports2, module2) {
  method "node_modules/ws/lib/extension.js" (line 28851) | "node_modules/ws/lib/extension.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket.js" (line 29141) | "node_modules/ws/lib/websocket.js"(exports2, module2) {
  method "node_modules/ws/lib/stream.js" (line 29779) | "node_modules/ws/lib/stream.js"(exports2, module2) {
  method "node_modules/ws/lib/websocket-server.js" (line 29892) | "node_modules/ws/lib/websocket-server.js"(exports2, module2) {
  method "node_modules/ws/index.js" (line 30182) | "node_modules/ws/index.js"(exports2, module2) {
  method "node_modules/@ethersproject/providers/lib/ws.js" (line 30195) | "node_modules/@ethersproject/providers/lib/ws.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/websocket-provider.js" (line 30209) | "node_modules/@ethersproject/providers/lib/websocket-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js" (line 30620) | "node_modules/@ethersproject/providers/lib/url-json-rpc-provider.js"(exp...
  method "node_modules/@ethersproject/providers/lib/alchemy-provider.js" (line 30830) | "node_modules/@ethersproject/providers/lib/alchemy-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/cloudflare-provider.js" (line 30961) | "node_modules/@ethersproject/providers/lib/cloudflare-provider.js"(expor...
  method "node_modules/@ethersproject/providers/lib/etherscan-provider.js" (line 31134) | "node_modules/@ethersproject/providers/lib/etherscan-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/fallback-provider.js" (line 31729) | "node_modules/@ethersproject/providers/lib/fallback-provider.js"(exports...
  method "node_modules/@ethersproject/providers/lib/ipc-provider.js" (line 32500) | "node_modules/@ethersproject/providers/lib/ipc-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/infura-provider.js" (line 32584) | "node_modules/@ethersproject/providers/lib/infura-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js" (line 32744) | "node_modules/@ethersproject/providers/lib/json-rpc-batch-provider.js"(e...
  method "node_modules/@ethersproject/providers/lib/nodesmith-provider.js" (line 32849) | "node_modules/@ethersproject/providers/lib/nodesmith-provider.js"(export...
  method "node_modules/@ethersproject/providers/lib/pocket-provider.js" (line 32923) | "node_modules/@ethersproject/providers/lib/pocket-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/web3-provider.js" (line 33058) | "node_modules/@ethersproject/providers/lib/web3-provider.js"(exports2) {
  method "node_modules/@ethersproject/providers/lib/index.js" (line 33223) | "node_modules/@ethersproject/providers/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/_version.js" (line 33365) | "node_modules/@ethersproject/solidity/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/solidity/lib/index.js" (line 33375) | "node_modules/@ethersproject/solidity/lib/index.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/_version.js" (line 33474) | "node_modules/@ethersproject/units/lib/_version.js"(exports2) {
  method "node_modules/@ethersproject/units/lib/index.js" (line 33484) | "node_modules/@ethersproject/units/lib/index.js"(exports2) {
  method "node_modules/ethers/lib/utils.js" (line 33575) | "node_modules/ethers/lib/utils.js"(exports2) {
  method "node_modules/ethers/lib/_version.js" (line 33921) | "node_modules/ethers/lib/_version.js"(exports2) {
  method "node_modules/ethers/lib/ethers.js" (line 33931) | "node_modules/ethers/lib/ethers.js"(exports2) {
  method "node_modules/ethers/lib/index.js" (line 34018) | "node_modules/ethers/lib/index.js"(exports2) {

FILE: test/js-scripts/src/getModifyLiquidityResult.ts
  function modifyLiquidity (line 18) | function modifyLiquidity(

FILE: test/js-scripts/src/utils/shared.ts
  constant JSBI_ZERO (line 5) | const JSBI_ZERO = JSBI.BigInt(0);
  function getSqrtPriceAtTick (line 7) | function getSqrtPriceAtTick(tick: string): string {
  function getAmount0Delta (line 11) | function getAmount0Delta(sqrtPriceAX96: JSBI, sqrtPriceBX96: JSBI, liqui...
  function getAmount1Delta (line 19) | function getAmount1Delta(sqrtPriceAX96: JSBI, sqrtPriceBX96: JSBI, liqui...
Condensed preview — 193 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,926K chars).
[
  {
    "path": ".gitattributes",
    "chars": 32,
    "preview": "*.sol linguist-language=Solidity"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 21,
    "preview": "* @uniswap/protocols\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.yml",
    "chars": 1092,
    "preview": "name: Bug report\ndescription: File a bug report to help us improve the code\ntitle: \"[Bug]: \"\nlabels: [\"bug\"]\n\nbody:\n  - "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_IMPROVEMENT.yml",
    "chars": 1543,
    "preview": "name: Feature Improvement\ndescription: Suggest an improvement to v4-core.\nlabels: [\"triage\"]\n\nbody:\n  - type: markdown\n "
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 89,
    "preview": "## Related Issue\n\nWhich issue does this pull request resolve?\n\n## Description of changes\n"
  },
  {
    "path": ".github/workflows/deploy.yaml",
    "chars": 1119,
    "preview": "name: Release\non:\n  # manual trigger\n  workflow_dispatch:\n\njobs:\n  deploy:\n    name: release\n    runs-on:\n      group: n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 951,
    "preview": "name: Lint\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  run-linters:\n    name: Run linters\n    runs-"
  },
  {
    "path": ".github/workflows/mythx.yml",
    "chars": 2374,
    "preview": "name: Mythx\n\non:\n  workflow_dispatch:\n\njobs:\n  mythx:\n    name: Submit to Mythx\n    runs-on: ubuntu-latest\n\n    steps:\n "
  },
  {
    "path": ".github/workflows/tests-merge.yml",
    "chars": 707,
    "preview": "name: Tests\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  forge-tests:\n    name: Forge Tests\n    runs-on: ubuntu-late"
  },
  {
    "path": ".github/workflows/tests-pr.yml",
    "chars": 856,
    "preview": "name: Tests\n\non:\n  pull_request:\n    branches:\n      - main\n      - dev\n      - audit/*\n\njobs:\n  forge-tests:\n    name: "
  },
  {
    "path": ".gitignore",
    "chars": 138,
    "preview": "# if you add a file here, add it to `.npmignore` too\nartifacts/\ncache/\ncrytic-export/\nnode_modules/\ntypechain/\nfoundry-o"
  },
  {
    "path": ".gitmodules",
    "chars": 331,
    "preview": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n[submodule \"lib/solmate"
  },
  {
    "path": ".npmignore",
    "chars": 80,
    "preview": "artifacts/\ncache/\ncrytic-export/\nnode_modules/\ntypechain/\nfoundry-out/\n.vscode/\n"
  },
  {
    "path": ".prettierignore",
    "chars": 64,
    "preview": ".prettierrc\nfoundry.toml\nout\nlib/\ncache/\n*.sol\ndist/\nsnapshots/\n"
  },
  {
    "path": ".prettierrc",
    "chars": 486,
    "preview": "{\n  \"printWidth\": 120,\n  \"tabWidth\": 2,\n  \"useTabs\": false,\n  \"singleQuote\": false,\n  \"bracketSpacing\": true,\n  \"trailin"
  },
  {
    "path": ".solhint.json",
    "chars": 81,
    "preview": "{\n  \"plugins\": [\"prettier\"],\n  \"rules\": {\n    \"prettier/prettier\": \"error\"\n  }\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4836,
    "preview": "# Contribution Guidelines\n\nThanks for your interest in contributing to v4 of the Uniswap Protocol! The contracts in this"
  },
  {
    "path": "README.md",
    "chars": 4310,
    "preview": "# Uniswap v4 Core\n\n[![Lint](https://github.com/Uniswap/v4-core/actions/workflows/lint.yml/badge.svg)](https://github.com"
  },
  {
    "path": "SECURITY.md",
    "chars": 398,
    "preview": "# Uniswap Labs Security\n\n## Vulnerability Disclosure and Bug Bounty\n\nBug bounty details can be found in https://uniswap."
  },
  {
    "path": "docs/whitepaper/latex/main-zh.tex",
    "chars": 10049,
    "preview": "\\documentclass[sigconf,nonacm,prologue,table]{acmart}\n\\usepackage{ctex}\n\n\\usepackage{listings}\n\n%% labels\n%% sections:  "
  },
  {
    "path": "docs/whitepaper/latex/main.bib",
    "chars": 2111,
    "preview": "@online{Adams18,\n  author =       \"Hayden Adams\",\n  year =         \"2018\",\n  month =        nov,\n  title =        \"Unisw"
  },
  {
    "path": "docs/whitepaper/latex/main.tex",
    "chars": 21015,
    "preview": "\\documentclass[sigconf,nonacm,prologue,table]{acmart}\n\\usepackage{listings}\n\n%% labels\n%% sections:    \"sec\"\n%% definiti"
  },
  {
    "path": "echidna.config.yml",
    "chars": 3031,
    "preview": "#format can be \"text\" or \"json\" for different output (human or machine readable)\nformat: \"text\"\n#checkAsserts checks ass"
  },
  {
    "path": "foundry.toml",
    "chars": 609,
    "preview": "[profile.default]\noptimizer_runs = 44444444\nvia_ir = true\nffi = true\nfs_permissions = [{ access = \"read-write\", path = \""
  },
  {
    "path": "justfile",
    "chars": 278,
    "preview": "\ntest *args: (test-forge args)\nbuild *args: (build-forge args)\nprep *args: fix (test-forge args)\n\n\ntest-forge *args: bui"
  },
  {
    "path": "licenses/BUSL_LICENSE",
    "chars": 4388,
    "preview": "Business Source License 1.1\n\nLicense text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.\n\"Business Sour"
  },
  {
    "path": "licenses/MIT_LICENSE",
    "chars": 1065,
    "preview": "Copyright 2023 Universal Navigation Inc. \n\nPermission is hereby granted, free of charge, to any person obtaining a copy "
  },
  {
    "path": "package.json",
    "chars": 485,
    "preview": "{\n  \"name\": \"@uniswap/v4-core\",\n  \"version\": \"1.0.2\",\n  \"description\": \"🦄 Core smart contracts of Uniswap v4\",\n  \"reposi"
  },
  {
    "path": "remappings.txt",
    "chars": 205,
    "preview": "@ensdomains/=node_modules/@ensdomains/\n@openzeppelin/=lib/openzeppelin-contracts/\nds-test/=lib/forge-std/lib/ds-test/src"
  },
  {
    "path": "snapshots/ClearTest.json",
    "chars": 21,
    "preview": "{\n  \"clear\": \"1717\"\n}"
  },
  {
    "path": "snapshots/CustomAccountingTest.json",
    "chars": 165,
    "preview": "{\n  \"addLiquidity CA fee\": \"170695\",\n  \"removeLiquidity CA fee\": \"141199\",\n  \"swap CA custom curve + swap noop\": \"124402"
  },
  {
    "path": "snapshots/ERC6909ClaimsTest.json",
    "chars": 313,
    "preview": "{\n  \"ERC6909Claims approve\": \"46323\",\n  \"ERC6909Claims burn\": \"29389\",\n  \"ERC6909Claims mint\": \"46603\",\n  \"ERC6909Claims"
  },
  {
    "path": "snapshots/ExtsloadTest.json",
    "chars": 38,
    "preview": "{\n  \"sparse external sload\": \"22164\"\n}"
  },
  {
    "path": "snapshots/ModifyLiquidityTest.json",
    "chars": 130,
    "preview": "{\n  \"add liquidity to already existing position with salt\": \"144401\",\n  \"create new liquidity to a position with salt\": "
  },
  {
    "path": "snapshots/PoolManagerInitializeTest.json",
    "chars": 27,
    "preview": "{\n  \"initialize\": \"51532\"\n}"
  },
  {
    "path": "snapshots/PoolManagerTest.json",
    "chars": 1103,
    "preview": "{\n  \"addLiquidity with empty hook\": \"274012\",\n  \"addLiquidity with native token\": \"135001\",\n  \"donate gas with 1 token\":"
  },
  {
    "path": "snapshots/ProtocolFeesTest.json",
    "chars": 33,
    "preview": "{\n  \"set protocol fee\": \"31730\"\n}"
  },
  {
    "path": "snapshots/SkipCallsTest.json",
    "chars": 56,
    "preview": "{\n  \"swap skips hook call if hook is caller\": \"206030\"\n}"
  },
  {
    "path": "snapshots/SqrtPriceMathTest.json",
    "chars": 512,
    "preview": "{\n  \"getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse\": \"243\",\n  \"getAmount0Delta_gasCostForAmount0WhereRoundUpIsTru"
  },
  {
    "path": "snapshots/StateLibraryTest.json",
    "chars": 387,
    "preview": "{\n  \"extsload getFeeGrowthGlobals\": \"4774\",\n  \"extsload getFeeGrowthInside\": \"2375\",\n  \"extsload getLiquidity\": \"2375\",\n"
  },
  {
    "path": "snapshots/SwapMathTest.json",
    "chars": 385,
    "preview": "{\n  \"SwapMath_oneForZero_exactInCapped\": \"1188\",\n  \"SwapMath_oneForZero_exactInPartial\": \"1274\",\n  \"SwapMath_oneForZero_"
  },
  {
    "path": "snapshots/SyncTest.json",
    "chars": 27,
    "preview": "{\n  \"getReserves\": \"5973\"\n}"
  },
  {
    "path": "snapshots/TestBitMath.json",
    "chars": 293,
    "preview": "{\n  \"BitMathLeastSignificantBitMaxUint128\": \"648\",\n  \"BitMathLeastSignificantBitMaxUint256\": \"648\",\n  \"BitMathLeastSigni"
  },
  {
    "path": "snapshots/TestDelegateCall.json",
    "chars": 28,
    "preview": "{\n  \"NoDelegateCall\": \"51\"\n}"
  },
  {
    "path": "snapshots/TestDynamicFees.json",
    "chars": 88,
    "preview": "{\n  \"swap with dynamic fee\": \"139153\",\n  \"update dynamic fee in before swap\": \"147743\"\n}"
  },
  {
    "path": "snapshots/TestDynamicReturnFees.json",
    "chars": 46,
    "preview": "{\n  \"swap with return dynamic fee\": \"145475\"\n}"
  },
  {
    "path": "snapshots/TickBitmapTest.json",
    "chars": 601,
    "preview": "{\n  \"flipTick_flippingATickThatResultsInDeletingAWord\": \"5109\",\n  \"flipTick_flippingFirstTickInWordToInitialized\": \"2220"
  },
  {
    "path": "snapshots/TickMathTestTest.json",
    "chars": 85,
    "preview": "{\n  \"TickMathGetSqrtPriceAtTick\": \"72349\",\n  \"TickMathGetTickAtSqrtPrice\": \"195022\"\n}"
  },
  {
    "path": "snapshots/TickTest.json",
    "chars": 199,
    "preview": "{\n  \"tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing\": \"25\",\n  \"tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpa"
  },
  {
    "path": "src/ERC6909.sol",
    "chars": 3497,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC6909Claims} from \"./interfaces/external/IERC6909Cla"
  },
  {
    "path": "src/ERC6909Claims.sol",
    "chars": 958,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {ERC6909} from \"./ERC6909.sol\";\n\n/// @notice ERC6909Clai"
  },
  {
    "path": "src/Extsload.sol",
    "chars": 2609,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IExtsload} from \"./interfaces/IExtsload.sol\";\n\n/// @not"
  },
  {
    "path": "src/Exttload.sol",
    "chars": 1603,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IExttload} from \"./interfaces/IExttload.sol\";\n\n/// @no"
  },
  {
    "path": "src/NoDelegateCall.sol",
    "chars": 1248,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {CustomRevert} from \"./libraries/CustomRevert.sol\";\n\n///"
  },
  {
    "path": "src/PoolManager.sol",
    "chars": 17613,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport {Hooks} from \"./libraries/Hooks.sol\";\nimport {Pool}"
  },
  {
    "path": "src/ProtocolFees.sol",
    "chars": 3036,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Currency} from \"./types/Currency.sol\";\nimport {Currency"
  },
  {
    "path": "src/interfaces/IExtsload.sol",
    "chars": 1023,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Interface for functions to access any storage slot "
  },
  {
    "path": "src/interfaces/IExttload.sol",
    "chars": 699,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n/// @notice Interface for functions to access any transient st"
  },
  {
    "path": "src/interfaces/IHooks.sol",
    "chars": 8229,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolKey} from \"../types/PoolKey.sol\";\nimport {BalanceDe"
  },
  {
    "path": "src/interfaces/IPoolManager.sol",
    "chars": 12835,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport {PoolKe"
  },
  {
    "path": "src/interfaces/IProtocolFees.sol",
    "chars": 2489,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport {PoolId}"
  },
  {
    "path": "src/interfaces/callback/IUnlockCallback.sol",
    "chars": 488,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Interface for the callback executed when an address"
  },
  {
    "path": "src/interfaces/external/IERC20Minimal.sol",
    "chars": 3041,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Minimal ERC20 interface for Uniswap\n/// @notice Cont"
  },
  {
    "path": "src/interfaces/external/IERC6909Claims.sol",
    "chars": 3162,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Interface for claims over a contract balance, wrapp"
  },
  {
    "path": "src/libraries/BitMath.sol",
    "chars": 2609,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title BitMath\n/// @dev This library provides functionality"
  },
  {
    "path": "src/libraries/CurrencyDelta.sol",
    "chars": 1606,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\n\n/// @tit"
  },
  {
    "path": "src/libraries/CurrencyReserves.sol",
    "chars": 1289,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport {C"
  },
  {
    "path": "src/libraries/CustomRevert.sol",
    "chars": 5174,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Library for reverting with custom errors efficiently"
  },
  {
    "path": "src/libraries/FixedPoint128.sol",
    "chars": 297,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title FixedPoint128\n/// @notice A library for handling bin"
  },
  {
    "path": "src/libraries/FixedPoint96.sol",
    "chars": 366,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title FixedPoint96\n/// @notice A library for handling bina"
  },
  {
    "path": "src/libraries/FullMath.sol",
    "chars": 5459,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Contains 512-bit math functions\n/// @notice Facilita"
  },
  {
    "path": "src/libraries/Hooks.sol",
    "chars": 16511,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolKey} from \"../types/PoolKey.sol\";\nimport {IHooks} f"
  },
  {
    "path": "src/libraries/LPFeeLibrary.sol",
    "chars": 3596,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {CustomRevert} from \"./CustomRevert.sol\";\n\n/// @notice L"
  },
  {
    "path": "src/libraries/LiquidityMath.sol",
    "chars": 742,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Math library for liquidity\nlibrary LiquidityMath {\n "
  },
  {
    "path": "src/libraries/Lock.sol",
    "chars": 930,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.24;\n\n/// @notice This is a temporary library that allows us to"
  },
  {
    "path": "src/libraries/NonzeroDeltaCount.sol",
    "chars": 1460,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.24;\n\n/// @notice This is a temporary library that allows us to"
  },
  {
    "path": "src/libraries/ParseBytes.sol",
    "chars": 1200,
    "preview": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/// @notice Parses bytes returned from hooks and the byte sele"
  },
  {
    "path": "src/libraries/Pool.sol",
    "chars": 30033,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport {SafeCast} from \"./SafeCast.sol\";\nimport {TickBitma"
  },
  {
    "path": "src/libraries/Position.sol",
    "chars": 4813,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport {FullMath} from \"./FullMath.sol\";\nimport {FixedPoin"
  },
  {
    "path": "src/libraries/ProtocolFeeLibrary.sol",
    "chars": 2113,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice library of functions related to protocol fees\nlibra"
  },
  {
    "path": "src/libraries/SafeCast.sol",
    "chars": 2269,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {CustomRevert} from \"./CustomRevert.sol\";\n\n/// @title Sa"
  },
  {
    "path": "src/libraries/SqrtPriceMath.sol",
    "chars": 14076,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\nimport {FullMath} fro"
  },
  {
    "path": "src/libraries/StateLibrary.sol",
    "chars": 16027,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolId} from \"../types/PoolId.sol\";\nimport {IPoolManage"
  },
  {
    "path": "src/libraries/SwapMath.sol",
    "chars": 6968,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {FullMath} from \"./FullMath.sol\";\nimport {SqrtPriceMath}"
  },
  {
    "path": "src/libraries/TickBitmap.sol",
    "chars": 6266,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {BitMath} from \"./BitMath.sol\";\n\n/// @title Packed tick "
  },
  {
    "path": "src/libraries/TickMath.sol",
    "chars": 12382,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {BitMath} from \"./BitMath.sol\";\nimport {CustomRevert} fr"
  },
  {
    "path": "src/libraries/TransientStateLibrary.sol",
    "chars": 2361,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IPoolManager} from \"../interfaces/IPoolManager.sol\";\ni"
  },
  {
    "path": "src/libraries/UnsafeMath.sol",
    "chars": 1161,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Math functions that do not check inputs or outputs\n/"
  },
  {
    "path": "src/test/ActionsRouter.sol",
    "chars": 6608,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport \"forge-std/Test.sol\";\nimport {IPoolManager} from"
  },
  {
    "path": "src/test/BaseTestHooks.sol",
    "chars": 3408,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {IHooks} from \"../interfaces/IHooks.sol\";\nimport"
  },
  {
    "path": "src/test/CurrencyTest.sol",
    "chars": 902,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Currency, CurrencyLibrary} from \"../types/Curre"
  },
  {
    "path": "src/test/CustomCurveHook.sol",
    "chars": 2767,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {I"
  },
  {
    "path": "src/test/DeltaReturningHook.sol",
    "chars": 3575,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {I"
  },
  {
    "path": "src/test/DynamicFeesTestHook.sol",
    "chars": 1345,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {BaseTestHooks} from \"./BaseTestHooks.sol\";\nimpo"
  },
  {
    "path": "src/test/DynamicReturnFeeTestHook.sol",
    "chars": 1313,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {BaseTestHooks} from \"./BaseTestHooks.sol\";\nimpo"
  },
  {
    "path": "src/test/EmptyRevertContract.sol",
    "chars": 246,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\ncontract EmptyRevertContract {\n    // a contract to sim"
  },
  {
    "path": "src/test/EmptyTestHooks.sol",
    "chars": 3745,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {I"
  },
  {
    "path": "src/test/FeeTakingHook.sol",
    "chars": 3569,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {S"
  },
  {
    "path": "src/test/Fuzzers.sol",
    "chars": 8272,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Vm} from \"forge-std/Vm.sol\";\nimport {StdUtils} from \"f"
  },
  {
    "path": "src/test/HooksTest.sol",
    "chars": 2874,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {I"
  },
  {
    "path": "src/test/LPFeeTakingHook.sol",
    "chars": 2468,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {S"
  },
  {
    "path": "src/test/LiquidityMathTest.sol",
    "chars": 289,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {LiquidityMath} from \"../libraries/LiquidityMath"
  },
  {
    "path": "src/test/MockContract.sol",
    "chars": 2037,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Proxy} from \"@openzeppelin/contracts/proxy/Prox"
  },
  {
    "path": "src/test/MockERC6909Claims.sol",
    "chars": 676,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {ERC6909Claims} from \"../ERC6909Claims.sol\";\n\n//"
  },
  {
    "path": "src/test/MockHooks.sol",
    "chars": 5217,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {I"
  },
  {
    "path": "src/test/NativeERC20.sol",
    "chars": 1661,
    "preview": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport {Test} from \"forge-std/Test.sol\";\n\n/// @dev"
  },
  {
    "path": "src/test/NoDelegateCallTest.sol",
    "chars": 977,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {NoDelegateCall} from \"../NoDelegateCall.sol\";\n\n"
  },
  {
    "path": "src/test/PoolClaimsTest.sol",
    "chars": 1865,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport "
  },
  {
    "path": "src/test/PoolDonateTest.sol",
    "chars": 2851,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Currency, CurrencyLibrary} from \"../types/Curre"
  },
  {
    "path": "src/test/PoolEmptyUnlockTest.sol",
    "chars": 686,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {IPoolManager} from \"../interfaces/IPoolManager."
  },
  {
    "path": "src/test/PoolModifyLiquidityTest.sol",
    "chars": 3796,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {CurrencyLibrary, Currency} from \"../types/Curre"
  },
  {
    "path": "src/test/PoolModifyLiquidityTestNoChecks.sol",
    "chars": 2786,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {CurrencyLibrary, Currency} from \"../types/Curre"
  },
  {
    "path": "src/test/PoolNestedActionsTest.sol",
    "chars": 11016,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {IPoolManager} from \"../interfaces/IPoolManager."
  },
  {
    "path": "src/test/PoolSwapTest.sol",
    "chars": 5002,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {CurrencyLibrary, Currency} from \"../types/Curre"
  },
  {
    "path": "src/test/PoolTakeTest.sol",
    "chars": 2274,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport "
  },
  {
    "path": "src/test/PoolTestBase.sol",
    "chars": 1024,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\n\nimport"
  },
  {
    "path": "src/test/ProtocolFeesImplementation.sol",
    "chars": 1309,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {ProtocolFees} from \"../ProtocolFees.sol\";\nimpor"
  },
  {
    "path": "src/test/ProxyPoolManager.sol",
    "chars": 9112,
    "preview": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.24;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {Poo"
  },
  {
    "path": "src/test/SkipCallsTestHook.sol",
    "chars": 7510,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Hooks} from \"../libraries/Hooks.sol\";\nimport {B"
  },
  {
    "path": "src/test/SqrtPriceMathEchidnaTest.sol",
    "chars": 7440,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {FullMath} from \"../libraries/FullMath.sol\";\nimp"
  },
  {
    "path": "src/test/SwapRouterNoChecks.sol",
    "chars": 1815,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport "
  },
  {
    "path": "src/test/TestERC20.sol",
    "chars": 2172,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {IERC20Minimal} from \"../interfaces/external/IER"
  },
  {
    "path": "src/test/TestInvalidERC20.sol",
    "chars": 2323,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {IERC20Minimal} from \"../interfaces/external/IER"
  },
  {
    "path": "src/test/TickMathEchidnaTest.sol",
    "chars": 955,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {TickMath} from \"../libraries/TickMath.sol\";\n\nco"
  },
  {
    "path": "src/test/TickMathTest.sol",
    "chars": 1297,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {TickMath} from \"../libraries/TickMath.sol\";\n\nco"
  },
  {
    "path": "src/test/TickOverflowSafetyEchidnaTest.sol",
    "chars": 3063,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Pool} from \"../libraries/Pool.sol\";\n\ncontract T"
  },
  {
    "path": "src/types/BalanceDelta.sol",
    "chars": 2339,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {SafeCast} from \"../libraries/SafeCast.sol\";\n\n/// @dev T"
  },
  {
    "path": "src/types/BeforeSwapDelta.sol",
    "chars": 1466,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Return type of the beforeSwap hook.\n// Upper 128 bits is the"
  },
  {
    "path": "src/types/Currency.sol",
    "chars": 5458,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20Minimal} from \"../interfaces/external/IERC20Minim"
  },
  {
    "path": "src/types/PoolId.sol",
    "chars": 539,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolKey} from \"./PoolKey.sol\";\n\ntype PoolId is bytes32;"
  },
  {
    "path": "src/types/PoolKey.sol",
    "chars": 805,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Currency} from \"./Currency.sol\";\nimport {IHooks} from \""
  },
  {
    "path": "src/types/PoolOperation.sol",
    "chars": 907,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {PoolKey} from \"../types/PoolKey.sol\";\nimport {BalanceD"
  },
  {
    "path": "src/types/Slot0.sol",
    "chars": 3404,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @dev Slot0 is a packed version of solidity structure.\n *"
  },
  {
    "path": "test/CurrencyReserves.t.sol",
    "chars": 2259,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {CurrencyReserves} from \"../src/libraries/Curren"
  },
  {
    "path": "test/CustomAccounting.t.sol",
    "chars": 19746,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Deploy"
  },
  {
    "path": "test/DynamicFees.t.sol",
    "chars": 13274,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/DynamicReturnFees.t.sol",
    "chars": 6822,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/ERC6909Claims.t.sol",
    "chars": 12693,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.15;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Currency} fro"
  },
  {
    "path": "test/Extsload.t.sol",
    "chars": 2526,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Extsload} from"
  },
  {
    "path": "test/ModifyLiquidity.t.sol",
    "chars": 15051,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Deploy"
  },
  {
    "path": "test/NoDelegateCall.t.sol",
    "chars": 3484,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolM"
  },
  {
    "path": "test/PoolManager.clear.t.sol",
    "chars": 8063,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"forge-std/Test.sol\";\nimport {IPoolManager} from "
  },
  {
    "path": "test/PoolManager.gas.spec.ts",
    "chars": 24672,
    "preview": "// import { ethers, waffle } from 'hardhat'\n// import { Wallet } from 'ethers'\n// import { PoolManager, PoolSwapTest, Po"
  },
  {
    "path": "test/PoolManager.swap.t.sol",
    "chars": 7735,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport \"forge-std/Test.sol\";\nimport {V3Helper, IUniswap"
  },
  {
    "path": "test/PoolManager.t.sol",
    "chars": 55651,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IHooks"
  },
  {
    "path": "test/PoolManagerInitialize.t.sol",
    "chars": 13715,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IHooks"
  },
  {
    "path": "test/ProtocolFeesImplementation.t.sol",
    "chars": 7767,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.15;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MockERC20} fr"
  },
  {
    "path": "test/SkipCallsTestHook.t.sol",
    "chars": 9632,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/Sync.t.sol",
    "chars": 14944,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MockER"
  },
  {
    "path": "test/Tick.t.sol",
    "chars": 19341,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {stdErr"
  },
  {
    "path": "test/js-scripts/build.js",
    "chars": 376,
    "preview": "const { build } = require(\"esbuild\");\n\nconst entryPoints = [\"getModifyLiquidityResult\", \"getSqrtPriceAtTick\", \"getTickAt"
  },
  {
    "path": "test/js-scripts/dist/getModifyLiquidityResult.js",
    "chars": 2109104,
    "preview": "\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnP"
  },
  {
    "path": "test/js-scripts/dist/getSqrtPriceAtTick.js",
    "chars": 1380935,
    "preview": "\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnP"
  },
  {
    "path": "test/js-scripts/dist/getTickAtSqrtPrice.js",
    "chars": 1380962,
    "preview": "\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnP"
  },
  {
    "path": "test/js-scripts/package.json",
    "chars": 945,
    "preview": "{\n  \"name\": \"v4-js-scripts\",\n  \"description\": \"Scripts for v4 tests\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"acce"
  },
  {
    "path": "test/js-scripts/src/getModifyLiquidityResult.ts",
    "chars": 3084,
    "preview": "import { BigNumber, ethers } from \"ethers\";\nimport JSBI from \"jsbi\";\nimport Decimal from \"decimal.js\";\n\nimport { getSqrt"
  },
  {
    "path": "test/js-scripts/src/getSqrtPriceAtTick.ts",
    "chars": 388,
    "preview": "import Decimal from \"decimal.js\";\nimport { ethers } from \"ethers\";\n\nconst tickArray = process.argv[2].split(\",\");\nconst "
  },
  {
    "path": "test/js-scripts/src/getTickAtSqrtPrice.ts",
    "chars": 415,
    "preview": "import Decimal from \"decimal.js\";\nimport { ethers } from \"ethers\";\n\nconst sqrtPriceArray = process.argv[2].split(\",\");\nc"
  },
  {
    "path": "test/js-scripts/src/utils/shared.ts",
    "chars": 1048,
    "preview": "import Decimal from \"decimal.js\";\nimport JSBI from \"jsbi\";\nimport { SqrtPriceMath } from \"@uniswap/v3-sdk\";\n\nexport cons"
  },
  {
    "path": "test/js-scripts/tsconfig.json",
    "chars": 279,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2018\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"esModuleInterop\": tr"
  },
  {
    "path": "test/libraries/BitMath.t.sol",
    "chars": 4020,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BitMat"
  },
  {
    "path": "test/libraries/FullMath.t.sol",
    "chars": 7633,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {FullMa"
  },
  {
    "path": "test/libraries/Hooks.t.sol",
    "chars": 55542,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/LPFeeLibrary.t.sol",
    "chars": 3181,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport \"../../src/libraries/LPFeeLibrary.sol\";\nimport \""
  },
  {
    "path": "test/libraries/LiquidityMath.t.sol",
    "chars": 2399,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SafeCast} from"
  },
  {
    "path": "test/libraries/Lock.t.sol",
    "chars": 535,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Lock} "
  },
  {
    "path": "test/libraries/NonzeroDeltaCount.t.sol",
    "chars": 1664,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Nonzer"
  },
  {
    "path": "test/libraries/Pool.t.sol",
    "chars": 8762,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/PoolId.t.sol",
    "chars": 507,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolId"
  },
  {
    "path": "test/libraries/Position.t.sol",
    "chars": 3424,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Positi"
  },
  {
    "path": "test/libraries/ProtocolFeeLibrary.t.sol",
    "chars": 4145,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {LPFeeL"
  },
  {
    "path": "test/libraries/SafeCast.t.sol",
    "chars": 3818,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/SqrtPriceMath.t.sol",
    "chars": 14690,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/StateLibrary.t.sol",
    "chars": 23417,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport \"forge-std/Test.sol\";\nimport {IHooks} from \"../../src/i"
  },
  {
    "path": "test/libraries/SwapMath.t.sol",
    "chars": 12118,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/TickBitmap.t.sol",
    "chars": 14422,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/TickMath.t.sol",
    "chars": 10473,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/libraries/UnsafeMath.t.sol",
    "chars": 2253,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Unsafe"
  },
  {
    "path": "test/types/BalanceDelta.t.sol",
    "chars": 5535,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Balanc"
  },
  {
    "path": "test/types/Currency.t.sol",
    "chars": 8043,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {stdErr"
  },
  {
    "path": "test/types/Slot0.t.sol",
    "chars": 1310,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Slot0,"
  },
  {
    "path": "test/utils/AmountHelpers.sol",
    "chars": 1369,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {LiquidityAmounts} from \"./LiquidityAmounts.sol\""
  },
  {
    "path": "test/utils/Constants.sol",
    "chars": 1720,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nlibrary Constants {\n    /// @dev All sqrtPrice calculat"
  },
  {
    "path": "test/utils/CurrencySettler.sol",
    "chars": 2406,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {Currency} from \"../../src/types/Currency.sol\";\nimport "
  },
  {
    "path": "test/utils/Deployers.sol",
    "chars": 11805,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport \"forge-std/Test.sol\";\nimport {MockERC20} from \"s"
  },
  {
    "path": "test/utils/JavascriptFfi.sol",
    "chars": 642,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {CommonBase} from \"forge-std/Base.sol\";\n\nabstrac"
  },
  {
    "path": "test/utils/LiquidityAmounts.sol",
    "chars": 6737,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport \"../../src/libraries/FullMath.sol\";\nimport \"../."
  },
  {
    "path": "test/utils/Logger.sol",
    "chars": 689,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {ModifyLiquidityParams} from \"../../src/types/Po"
  },
  {
    "path": "test/utils/NestedActions.t.sol",
    "chars": 1334,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Deploy"
  },
  {
    "path": "test/utils/SortTokens.sol",
    "chars": 655,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {MockERC20} from \"solmate/src/test/utils/mocks/M"
  },
  {
    "path": "test/utils/SwapHelper.t.sol",
    "chars": 5533,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Vm} fr"
  },
  {
    "path": "test/utils/V3Helper.sol",
    "chars": 1601,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.24;\n\nimport \"forge-std/Test.sol\";\n\ninterface IUniswapV3Facto"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the Uniswap/v4-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 193 files (5.5 MB), approximately 1.4M tokens, and a symbol index with 556 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!