Uniswap v4 Core

repository·main·Indexed 25 days ago

https://github.com/uniswap/v4-core

Core smart contracts for Uniswap v4, featuring a singleton architecture managed by PoolManager. It utilizes an unlock/callback mechanism via the IUnlockCallback interface for pool actions such as swap, modifyLiquidity, donate, take, settle, mint, and burn. The protocol supports customizable hook contracts with before and after callbacks for lifecycle events including Initialize, AddLiquidity, RemoveLiquidity, Swap, and Donate.

Tokens
1.7K
Snippets
3
Records
7
Agent score
32%

What's inside uniswap-v4-core

  1. How the Uniswap v4 singleton architecture works

    main

    Uniswap v4 uses a singleton-style architecture where all pool state is managed within a single contract: PoolManager.sol.

    Instead of interacting with individual pool contracts, integrators interact with the PoolManager using an unlock mechanism. To perform actions, an integrator must:

    1. Call unlock on the PoolManager.
    2. Implement the IUnlockCallback interface to receive the unlockCallback call.
    3. Execute pool actions (like swap, modifyLiquidity, etc.) within that callback.

    Key Constraints:

    • Delta Accounting: The PoolManager tracks net balances (the delta field) during an unlock. All accumulated deltas must reach 0 by the time the unlock is released.
    • Hooks: Pools can be initialized with a hook contract that executes {before,after} callbacks for lifecycle events like Initialize, AddLiquidity, RemoveLiquidity, Swap, and Donate. The set of callbacks executed for a pool is fixed after initialization.
  2. Integrate with Uniswap v4 via IUnlockCallback

    main

    To interact with the PoolManager, your contract must implement the IUnlockCallback interface. The workflow involves calling unlock on the PoolManager, which then triggers your contract's unlockCallback function. Inside the callback, you can perform various pool actions such as swap, modifyLiquidity, donate, take, settle, mint, or burn.

    Note that you should implement security checks within unlockCallback to ensure only the PoolManager can call it.

    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();
  3. Configure Echidna testing via echidna.config.yml

    main

    Echidna configuration is managed through a YAML file. This file controls the behavior of the fuzzer, including gas limits, transaction sequences, address management, and compiler arguments.

    Key configuration categories include:

    • Output & Reporting: Control output format (format), assertion checking (checkAsserts), and verbosity (quiet).
    • Fuzzing Parameters: Define the number of test sequences (testLimit), length of sequences (seqLen), and shrinking effort (shrinkLimit).
    • Gas & Economics: Set gas limits for property failures (propMaxGas), sequence termination (testMaxGas), maximum gas price (maxGasprice), and maximum value for payable functions (maxValue).
    • Address & Account Management: Specify the contract address (contractAddr), the deployer (deployer), transaction senders (sender), and default balances (balanceAddr, balanceContract).
    • Compiler & Tooling: Pass arguments to solc (solcArgs) or crytic (cryticArgs).
    format: "text"
    checkAsserts: true
    coverage: false
    # ... other settings
  4. Reference Echidna configuration options

    main

    The following configuration keys are available in echidna.config.yml:

    KeyDescription
    formatOutput format: "text" (human readable) or "json" (machine readable).
    checkAssertsWhether to check assertions.
    coverageEnables coverage-guided testing.
    prefixPrefix for Boolean functions to be treated as properties to be checked.
    propMaxGasGas cost at which a property fails.
    testMaxGasGas limit that terminates a sequence without causing failure.
    maxGaspriceMaximum gas price.
    testLimitNumber of test sequences to run.
    stopOnFailIf true, terminates as soon as any property fails and has been shrunk.
    estimateGas(Experimental) Performs analysis of maximum gas costs for functions.
    seqLenNumber of transactions in a test sequence.
    shrinkLimitEffort spent shrinking failing sequences.
    contractAddrAddress of the contract being tested.
    deployerAddress of the contract deployer (often the privileged owner).
    psenderSender for property transactions (defaults to the deployer).
    senderSet of addresses transactions may originate from.
    balanceAddrDefault balance for addresses.
    balanceContractOverrides balanceAddr for the contract address.
    solcArgsSpecial arguments for solc.
    solcLibssolc libraries.
    cryticArgsSpecial arguments for crytic.
    quietProduces significantly less verbose output.
    initializeData used to initialize the blockchain.
    multi-abiWhether to use multi-ABI mode of testing.
    benchmarkModeEnables benchmark mode.
    timeoutCampaign timeout in seconds.
    seedRandom seed for the fuzzer.
    dictFreqControls frequency of using internal dictionary vs random values.
    maxTimeDelayMaximum time between generated transactions (default: one week).
    maxBlockDelayMaximum blocks elapsed between generated transactions.
    filterFunctionsList of methods to filter.
    filterBlacklistIf true, filterFunctions acts as a blacklist (default: true).
    corpusDirDirectory to save the corpus.
    mutConstsConstants for corpus mutations (experimentation only).
    maxValueMaximum value to send to payable functions.
  5. Available Hook Callbacks

    main

    When a pool is initialized with a hook contract, the hook can implement the following lifecycle callbacks:

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