Whitepaper:

v4-core/whitepaper-v4-draft.pdf at main · Uniswap/v4-core

Research:

TWAMM - Paradigm

Contracts:

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

https://github.com/Uniswap/v4-periphery

Notes:

  1. Architecture - Singleton: v2, v3 deployment of new pools involves deploying a new contract (through CREATE2)

    1. v4 has a singleton contract that holds all tokens → to minimize the cost of token transfer between pools
  2. Native ETH: v2 does not support native ETH and requires ETH to be wrapped to WETH → comes with extra gas cost

  3. Feature - Hooks: Uniswap V4 allows anyone to deploy new concentrated liquidity pools with custom functionality. It can be used to manage the swap fee of the pool as well as the withdrawal fees charged to liquidity providers. Hooks can modify pool parameters or add new features and functionality:

    1. Executing large orders over time through TWAMM
    2. Onchain limit orders that fill at tick prices
    3. Volatility-shifting dynamic fees
    4. Internalize MEV for liquidity providers
    5. Median, truncated, or other custom oracle implementation

    when creating a pool → users can set the customized hook contracts, currently, there are eight hook callbacks:

    1. beforeInitialize / afterInitialize
    2. beforeModifyPosition / afterModifyPosition
    3. beforeSwap / afterSwap
    4. beforeDonate / afterDonate

Untitled

  1. Flash accounting: implemented EIP-1153

    v2 / v3 each action ending with a token transfer (such as providing liquidity & swapping). In v4, each operation updates an internal net balance, known as a delta → only making the transfer at the very end to save the gas cost.

    Function take / settle

    /// @inheritdoc IPoolManager
    /// used to borow fund from the pool
    function take(Currency currency, address to, uint256 amount) external override noDelegateCall onlyByLocker {
        _accountDelta(currency, amount.toInt128());
        reservesOf[currency] -= amount;
        currency.transfer(to, amount);
    }
    
    /// @inheritdoc IPoolManager
    /// used to deposit fund back to the pool
    function settle(Currency currency) external payable override noDelegateCall onlyByLocker returns (uint256 paid) {
        uint256 reservesBefore = reservesOf[currency];
        reservesOf[currency] = currency.balanceOfSelf();
        paid = reservesOf[currency] - reservesBefore;
        // subtraction must be safe
        _accountDelta(currency, -(paid.toInt128()));
    }
    

    this design made the internal accounting easier, e.g in swapping. To further reduce the gas cost in internal state update, the Uniswap team implemented EIP-1153 transient storage.

  2. Governance Updates: 2 separate governance fee mechanisms**: swap fee and withdrawal fees.** v2 / v3 can set the swap fee percentage through the governance, with v4, if hook choose to turn on withdrawal fees for a pool, governance also has the ability to take up to a capped percentage of that withdrawal fee.

  3. donate() → tipping design for the in-range liquidity provider

    /// @inheritdoc IPoolManager
      function donate(PoolKey memory key, uint256 amount0, uint256 amount1)
          external
          override
          noDelegateCall
          onlyByLocker
          returns (BalanceDelta delta)
      {
          if (key.hooks.shouldCallBeforeDonate()) {
              if (key.hooks.beforeDonate(msg.sender, key, amount0, amount1) != IHooks.beforeDonate.selector) {
                  revert Hooks.InvalidHookResponse();
              }
          }
    
          delta = _getPool(key).donate(amount0, amount1);  // -> donate action here
    
          _accountPoolBalanceDelta(key, delta);
    
          if (key.hooks.shouldCallAfterDonate()) {
              if (key.hooks.afterDonate(msg.sender, key, amount0, amount1) != IHooks.afterDonate.selector) {
                  revert Hooks.InvalidHookResponse();
              }
          }
      }
    

TWAMM Notes

This paper introduces a new type of automated market maker, or AMM, that helps traders on Ethereum efficiently execute large orders.