6

Is there a way for a contract to check a destination address to see if it's a Uniswap V3 pool?

2
  • 1
    One dummy way is to check if it implements the interface - check that each function exists (unsure even how that should be done) Jun 28 '21 at 5:50
  • 2
    Problam is, anyone can do that. It seems like there ought to be a way to prove that it is legit but the deployer doesn't seem to record what it does apart from the event log. Jun 28 '21 at 7:35
4

All valid Uniswap V3 pools must implement the view functions token0 and token1.

Call those functions on the address in question, and use the addresses returned by those functions to call getPool on the canonical UniswapV3Factory. The address returned by UniswapV3Factory.getPool should match the address of the contract in question. If not, you can be sure that the contract address was NOT deployed using the canonical UniswapV3Factory and thus is not a valid pool.

1
5

The easiest implementation would be to simply check for the destination contract's factory parameter, since the single common denominator of all Uniswap V3 pools is that they all have the same Uniswap V3 factory address as follows:

assert(UniswapV3Pool(destination).factory == 0x1F98431c8aD98523631AE4a59f267346ea31F984);

But then, anyone would be able to deploy a mock contract containing that data. Just like anyone would be able to deploy a contract that implements the Uniswap V3 pair interface.

2
  • 1
    I'm struggling with a way to be sure because there will be an incentive to mimic it. Jun 28 '21 at 7:31
  • 1
    @RobHitchens all the Uniswap V3 pools also share the same contract creator address, which is that Uniswap V3 factory mentioned above. Sadly, there is no way to check with certainty for any contract's creator address in Solidity. Jun 28 '21 at 7:53
1

One way would be to recompute the theoretical pool address (since it's deterministic, but not the same as in V2) and compare to the observed address.

In solidity:

function isUniswapPoolAddress(
    address token0,
    address token1,
    uint24 fee,
    address is_this_a_pool
    ) external returns (bool) {

    bytes POOL_INIT_CODE_HASH = '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54';
        
    address theo_adr;
   
    bytes32 pubKey = keccak256(abi.encodePacked(hex'ff', address(factory_address), keccak256(abi.encode(token0, token1, fee)), POOL_INIT_CODE_HASH));

    //bytes32 to address:
    assembly {
        mstore(0x0, pubKey)
        theo_adr := mload(0x0)
    }
    return is_this_a_pool == theo_adr;
}

In JS/ether:

const factory = '0x1F98431c8aD98523631AE4a59f267346ea31F984'
const POOL_INIT_CODE_HASH = '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54'

const key = ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode([ "address", "address", "uint24"], [token0, token1, fee]));
const keccack = ethers.utils.solidityKeccak256(["bytes", "address", "bytes", "bytes32"], ["0xff", factory, key, POOL_INIT_CODE_HASH]);
console.log(ethers.utils.hexDataSlice(keccak, 12));

//keccak is 64 hex digit/nibbles == 32 bytes -> take rightmost 20 bytes=40 nibbles -> start at 64-40=24nibbles or 12 bytes
const theoretical_address = ethers.utils.hexDataSlice(keccak, 12);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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