0

I'm trying to do calculations for determining pool addresses. However my INIT HASH keeps being wrong.

I found some code which calculates pool addresses in a different way

export const POOL_INIT_CODE_HASH =
  '0x010013f177ea1fcbc4520f9a3ca7cd2d1d77959e05aa66484027cb38e712aeed';
export const CONSTRUCTOR_INPUT_HASH =
  '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
export const PREFIX =
  '0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494';

export function computeZkPoolAddress({
  factoryAddress,
  tokenA,
  tokenB,
  fee,
  initCodeHashManualOverride,
}: {
  factoryAddress: string;
  tokenA: Token;
  tokenB: Token;
  fee: FeeAmount;
  initCodeHashManualOverride?: string;
}): string {
  const salt = solidityKeccak256(
    ['bytes'],
    [
      defaultAbiCoder.encode(
        ['address', 'address', 'uint24'],
        [tokenA.address, tokenB.address, fee],
      ),
    ],
  );
  const pool = getAddress(
    hexDataSlice(
      keccak256(
        concat([
          PREFIX,
          zeroPad(factoryAddress, 32),
          salt,
          initCodeHashManualOverride ?? POOL_INIT_CODE_HASH,
          CONSTRUCTOR_INPUT_HASH,
        ]),
      ),
      12,
    ),
  );
  return pool;
}

I tried calculating the init hash using the following answer:

https://ethereum.stackexchange.com/a/107643

However, it gave me bogus pools. I can add and remove liquidity fine but swap doesn't work since the routes can't calculate the pool addresses.

In this example it seems they're using multiple values, I'm wondering how to calculate the prefix here, and the other values?

2 Answers 2

1

To compute the address of a UniswapV3Pool you only need 5 values namely the UniswapV3Factory address, token0, token1, fee and the UniswapV3Pool InitCode Hash. You can use the computePoolAddress function from the @uniswap/v3-sdk to do this:

export function computePoolAddress({
  factoryAddress,
  tokenA,
  tokenB,
  fee,
  initCodeHashManualOverride
}: {
  factoryAddress: string
  tokenA: Token
  tokenB: Token
  fee: FeeAmount
  initCodeHashManualOverride?: string
}): string {
  const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] // does safety checks
  return getCreate2Address(
    factoryAddress,
    keccak256(
      ['bytes'],
      [defaultAbiCoder.encode(['address', 'address', 'uint24'], [token0.address, token1.address, fee])]
    ),
    initCodeHashManualOverride ?? POOL_INIT_CODE_HASH
  )
}

NB: tokenA and tokenB aren't ordered, hence why the above function first orders them into token0 and token1

2
  • Yeah, but the address isn't be calculated properly, I'm using the uniswap standard deployment scripts so the pool init hash shouldn't change. Not sure why it's not working
    – Ritzy Dev
    Sep 18, 2023 at 22:25
  • can you add this context to your question under an edit section? provide all necessary details to help debug your issue including how you're invoking computePoolAddress, also provide the factory address and the network you're trying to do this one
    – MShakeG
    Sep 19, 2023 at 7:00
0

the POOL_INIT_HASH_CODE is calculated by hashing the creation code of the uniswap pool contract. If this contract has been modified then of course this hash will change. For example, I deployed a mock version of the V3 pool contract and made some changes, then i also deployed a mock version of the factory contract and used it to deploy a pool. I then successfully replicated this deployed pool address with the following code,

    // SPDX-License-Identifier: GPL-2.0-or-later
    pragma solidity 0.7.6;
    pragma abicoder v2;
    
    import "contracts/testing/UniswapV3Pool.sol";
    
    contract A { 
    
       function getPoolCreationCode() public view returns (bytes memory) {
           return type(UniswapV3Pool).creationCode;
       }
    
        function hashPoolCode(bytes memory creation_code) public view returns (bytes32 pool_hash){
            pool_hash = keccak256(creation_code);
        }
    
        function computeAddress(address factory, 
                                address tokenA,
                                address tokenB,
                                uint24 fee) 
                                external view returns (address _pool) 
        {
            require(tokenA < tokenB, "token1 > token0");
            //---------------- calculate pool address
                bytes32 _POOL_INIT_CODE_HASH  = hashPoolCode(getPoolCreationCode());
                bytes32 pool_hash = keccak256(
                abi.encodePacked(
                    hex'ff',
                    factory,
                    keccak256(abi.encode(tokenA, tokenB, fee)),
                    _POOL_INIT_CODE_HASH
                )
                );
                bytes20 addressBytes = bytes20(pool_hash << (256 - 160));
                _pool = address(uint160(addressBytes));
    
        }
    
    
    }

The function computeAddress can be found in the PoolAddress.sol library in the v3-periphery contracts. The above implementation is a slight modification of it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.