PoolFinder

Description:

Smart contract deployed on Ethereum with Factory, Oracle features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "hopium/uniswap/main/pool-finder.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import "hopium/uniswap/types/pool.sol";
import "hopium/common/interface/imDirectory.sol";
import "hopium/uniswap/interface/imUniswapOracle.sol";

error TokenIsWETH();
error ZeroAddress();

interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
}

interface IERC20Metadata is IERC20 {
    function decimals() external view returns (uint8);
}

interface IUniswapV2Factory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IUniswapV2Pair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 r0, uint112 r1, uint32 t);
}

interface IUniswapV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

interface IUniswapV3Pool {
    function token0() external view returns (address);
    function token1() external view returns (address);
}

abstract contract Storage {
    mapping(address => Pool) internal cachedPools;

    event PoolChanged(address poolAddress, bool isV3Pool, address t0, address t1, uint8 d0, uint8 d1);
}

abstract contract Helpers is Storage, ImUniswapOracle {

    function _getPoolTokens(address poolAddress, bool isV3Pool) internal view returns (address t0, address t1, uint8 d0, uint8 d1) {
        if (isV3Pool) {
            t0 = IUniswapV3Pool(poolAddress).token0();
            t1 = IUniswapV3Pool(poolAddress).token1();
        } else {
            t0 = IUniswapV2Pair(poolAddress).token0();
            t1 = IUniswapV2Pair(poolAddress).token1();
        }
        d0 = IERC20Metadata(t0).decimals();
        d1 = IERC20Metadata(t1).decimals();
    }

    function _emitPoolChangedEvent(Pool memory pool) internal {
        (address t0, address t1, uint8 d0, uint8 d1) = _getPoolTokens(pool.poolAddress, pool.isV3Pool == 1);
        emit PoolChanged(pool.poolAddress, pool.isV3Pool == 1, t0, t1, d0, d1); 
    }

    function emitPoolChangedEventOnWethUsdPool(address poolAddress, bool isV3Pool) external onlyUniswapOracle {
        (address t0, address t1, uint8 d0, uint8 d1) = _getPoolTokens(poolAddress, isV3Pool);
        emit PoolChanged(poolAddress, isV3Pool, t0, t1, d0, d1); 
    }
}

contract PoolFinder is ImDirectory, Helpers {
    address public immutable wethAddress;
    IUniswapV2Factory public immutable v2Factory;
    IUniswapV3Factory public immutable v3Factory;

    constructor(
        address _directory,
        address _wethAddress,
        address _v2Factory,
        address _v3Factory
        ) ImDirectory(_directory) {
            if (_wethAddress == address(0)) revert ZeroAddress();
            if (_v2Factory  == address(0)) revert ZeroAddress();
            if (_v3Factory == address(0)) revert ZeroAddress();

            wethAddress = _wethAddress;
            v2Factory = IUniswapV2Factory(_v2Factory);
            v3Factory = IUniswapV3Factory(_v3Factory);
        }


    // constant fee tiers — cheapest way (no constructor needed)
    uint24 internal constant V3_FEE0 = 3000;   // 0.3%
    uint24 internal constant V3_FEE1 = 10000;  // 1%
    uint256 internal constant V3_FEE_COUNT = 2;

    uint256 public staleTime = 6 hours;

    function findBestWethPool(address tokenAddress) public view returns (Pool memory pool) {
        if (tokenAddress == address(0)) revert ZeroAddress();
        if (tokenAddress == wethAddress) revert TokenIsWETH();

        address _weth = wethAddress;
        IERC20 Weth = IERC20(_weth);
        uint256 poolWethLiquidity;

        // --- Uniswap V2 ---
        address v2Pair = v2Factory.getPair(tokenAddress, _weth);
        if (v2Pair != address(0)) {
            (uint112 r0, uint112 r1, ) = IUniswapV2Pair(v2Pair).getReserves();
            address t0 = IUniswapV2Pair(v2Pair).token0();
            uint256 w = (t0 == _weth) ? uint256(r0) : uint256(r1);
            if (w > poolWethLiquidity) {
                pool.isV3Pool = 0;
                pool.poolAddress = v2Pair;
                pool.poolFee = 0;
                poolWethLiquidity = w;
            }
        }

        // --- Uniswap V3 --- (iterate with unchecked)
        for (uint256 i; i < V3_FEE_COUNT; ) {
            // emulate constant array indexing
            uint24 fee = (i == 0) ? V3_FEE0 : V3_FEE1;

            address p = v3Factory.getPool(tokenAddress, _weth, fee);
            if (p != address(0)) {
                uint256 w = Weth.balanceOf(p);
                if (w > poolWethLiquidity) {
                    pool.isV3Pool = 1;
                    pool.poolAddress = p;
                    pool.poolFee = fee;
                    poolWethLiquidity = w;
                }
            }
            unchecked { ++i; }
        }

        pool.lastCached = uint64(block.timestamp);
    }

    // ---- READ fn: hit -> return cache; miss -> compute (no writes)
    function getBestWethPool(address tokenAddress) external view returns (Pool memory pool) {
        pool = cachedPools[tokenAddress];
        if (pool.poolAddress != address(0)) return pool;
        return findBestWethPool(tokenAddress);
    }

    // ---- WRITE fn: populate if missing; refresh only when stale; else return cached
    function getBestWethPoolAndUpdateIfStale(address tokenAddress) public returns (Pool memory out) {
        Pool storage slot = cachedPools[tokenAddress];

        // missing?
        if (slot.poolAddress == address(0)) {
            out = findBestWethPool(tokenAddress);
            cachedPools[tokenAddress] = out; // <-- fix
            _emitPoolChangedEvent(out);
            return out;
        }

        // stale?
        if (block.timestamp - slot.lastCached > staleTime) {
            Pool memory fresh = findBestWethPool(tokenAddress);
            if (fresh.poolAddress != slot.poolAddress) {
                cachedPools[tokenAddress] = fresh; // <-- fix
                _emitPoolChangedEvent(fresh);
                return fresh;
            } else {
                slot.lastCached = uint64(block.timestamp); // ok to update a single field
            }
        }

        // fresh cache
        out = slot;
    }

    // ---- WRITE fn: force update cache
    function getBestWethPoolAndForceUpdate(address tokenAddress) public returns (Pool memory out) {
        out = findBestWethPool(tokenAddress);
        cachedPools[tokenAddress] = out;
        _emitPoolChangedEvent(out);
    }

    function setStaleTimePoolCache(uint256 newStaleTime) external onlyOwner {
        staleTime = newStaleTime;
    }
}"
    },
    "hopium/uniswap/interface/imUniswapOracle.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import "hopium/common/interface/imDirectory.sol";
import "hopium/uniswap/interface/iUniswapOracle.sol";

abstract contract ImUniswapOracle is ImDirectory {

    function getUniswapOracle() internal view virtual returns (IUniswapOracle) {
        return IUniswapOracle(fetchFromDirectory("uniswap-oracle"));
    }

    modifier onlyUniswapOracle() {
        require(msg.sender == fetchFromDirectory("uniswap-oracle"), "msg.sender is not uniswap-oracle");
        _;
    }
}"
    },
    "hopium/common/interface/imDirectory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

/// @notice Interface used by the registry to talk to the external directory.
interface IDirectory {
    function owner() external view returns (address);
    function fetchFromDirectory(string memory _key) external view returns (address);
}

abstract contract ImDirectory {
    IDirectory public Directory;

    constructor(address _directory) {
        _setDirectory(_directory); // no modifier here
    }

    function changeDirectoryAddress(address _directory) external onlyOwner {
        _setDirectory(_directory);
    }

    function _setDirectory(address _directory) internal {
        require(_directory != address(0), "Directory cannot be zero address");
        require(_directory.code.length > 0, "Directory must be a contract");

        // Sanity check the interface
        try IDirectory(_directory).owner() returns (address) {
            Directory = IDirectory(_directory);
        } catch {
            revert("Directory address does not implement owner()");
        }
    }

    modifier onlyOwner() {
        require(msg.sender == Directory.owner(), "Caller is not the owner");
        _;
    }

    function owner() public view returns (address) {
        return Directory.owner();
    }

    function fetchFromDirectory(string memory _key) public view returns (address) {
        return Directory.fetchFromDirectory(_key);
    }
}
"
    },
    "hopium/uniswap/types/pool.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

struct Pool {
    address poolAddress; // 20
    uint24  poolFee;     // 3
    uint8   isV3Pool;    // 1 (0/1)
    uint64  lastCached;  // 8
}"
    },
    "hopium/uniswap/interface/iUniswapOracle.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

interface IUniswapOracle {
    function getTokenWethPrice(address tokenAddress) external view returns (uint256 price18);
    function getTokenUsdPrice(address tokenAddress) external view returns (uint256 price18);
    function getWethUsdPrice() external view returns (uint256 price18);
    function getTokenLiquidityWeth(address) external view returns (uint256);
    function getTokenLiquidityUsd(address) external view returns (uint256);
    function getTokenMarketCapWeth(address) external view returns (uint256);
    function getTokenMarketCapUsd(address) external view returns (uint256);
    function getTokenWethPriceByPool(address tokenAddress, address poolAddress, bool isV3Pool) external view returns (uint256);
    function emitPoolChangedEventOnWethUsdPool() external;
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Factory, Oracle|addr:0x5d8ddeabcc41b2bb2eed6307211a9976cf4ea415|verified:true|block:23668114|tx:0x7ed6e521fe7b12dbac04e966dd2db89b1bd499326be224507dc2cf958d8b4253|first_check:1761567274

Submitted on: 2025-10-27 13:14:35

Comments

Log in to comment.

No comments yet.