S Price: $0.562506 (-3.15%)

Contract

0x99eEd78D51709b670d4247236bA14C48B17Fc913

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x61876dCe...F46659944
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
BeefyOracleUniswapV3

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 9 : BeefyOracleUniswapV3.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20MetadataUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

import { UniswapV3OracleLibrary, IUniswapV3Pool } from "../../utils/UniswapV3OracleLibrary.sol";
import { BeefyOracleHelper, IBeefyOracle, BeefyOracleErrors } from "./BeefyOracleHelper.sol";

/// @title Beefy Oracle for UniswapV3
/// @author Beefy, @kexley
/// @notice On-chain oracle using UniswapV3
contract BeefyOracleUniswapV3 {

    /// @notice Fetch price from the UniswapV3 pools using the TWAP observations
    /// @param _data Payload from the central oracle with the addresses of the token route, pool 
    /// route and TWAP periods in seconds
    /// @return price Retrieved price from the chained quotes
    /// @return success Successful price fetch or not
    function getPrice(bytes calldata _data) external returns (uint256 price, bool success) {
        (address[] memory tokens, address[] memory pools, uint256[] memory twapPeriods) = 
            abi.decode(_data, (address[], address[], uint256[]));

        int24[] memory ticks = new int24[](pools.length);
        for (uint i; i < pools.length; i++) {
            (ticks[i],) = UniswapV3OracleLibrary.consult(pools[i], uint32(twapPeriods[i]));
        }

        int256 chainedTick = UniswapV3OracleLibrary.getChainedPrice(tokens, ticks);

        // Do not let the conversion overflow
        if (chainedTick > type(int24).max) return (0, false);

        uint256 amountOut = UniswapV3OracleLibrary.getQuoteAtTick(
            int24(chainedTick),
            10 ** IERC20MetadataUpgradeable(tokens[0]).decimals()
        );

        price = BeefyOracleHelper.priceFromBaseToken(
            msg.sender, tokens[tokens.length - 1], tokens[0], amountOut
        );
        if (price != 0) success = true;
    }

    /// @notice Data validation for new oracle data being added to central oracle
    /// @param _data Encoded addresses of the token route, pool route and TWAP periods
    function validateData(bytes calldata _data) external view {
        (address[] memory tokens, address[] memory pools, uint256[] memory twapPeriods) = 
            abi.decode(_data, (address[], address[], uint256[]));

        if (tokens.length != pools.length + 1 || tokens.length != twapPeriods.length + 1) {
            revert BeefyOracleErrors.ArrayLength();
        }
        
        uint256 basePrice = IBeefyOracle(msg.sender).getPrice(tokens[0]);
        if (basePrice == 0) revert BeefyOracleErrors.NoBasePrice(tokens[0]);

        uint256 poolLength = pools.length;
        for (uint i; i < poolLength;) {
            address fromToken = tokens[i];
            address toToken = tokens[i + 1];
            address pool = pools[i];
            address token0 = IUniswapV3Pool(pool).token0();
            address token1 = IUniswapV3Pool(pool).token1();

            if (fromToken != token0 && fromToken != token1) {
                revert BeefyOracleErrors.TokenNotInPair(fromToken, pool);
            }
            if (toToken != token0 && toToken != token1) {
                revert BeefyOracleErrors.TokenNotInPair(toToken, pool);
            }
            unchecked { ++i; }
        }
    }
}

File 2 of 9 : IERC20MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 3 of 9 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 4 of 9 : BeefyOracleErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @title Beefy Oracle Errors
/// @author Beefy, @kexley
/// @notice Error list for Beefy Oracles
contract BeefyOracleErrors {

    /// @dev No response from the Chainlink feed
    error NoAnswer();

    /// @dev No price for base token
    /// @param token Base token
    error NoBasePrice(address token);

    /// @dev Token is not present in the pair
    /// @param token Input token
    /// @param pair Pair token
    error TokenNotInPair(address token, address pair);

    /// @dev Array length is not correct
    error ArrayLength();

}

File 5 of 9 : BeefyOracleHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20MetadataUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

import { IBeefyOracle } from "../../interfaces/oracle/IBeefyOracle.sol";
import { BeefyOracleErrors } from "./BeefyOracleErrors.sol";

/// @title Beefy Oracle Helper
/// @author Beefy, @kexley
/// @notice Helper functions for Beefy oracles
library BeefyOracleHelper {

    /// @dev Calculate the price of the output token in 18 decimals given the base token price 
    /// and the amount out received from swapping 1 unit of the base token
    /// @param _oracle Central Beefy oracle which stores the base token price
    /// @param _token Address of token to calculate the price of
    /// @param _baseToken Address of the base token used in the price chain
    /// @param _amountOut Amount received from swapping 1 unit of base token into the target token
    /// @return price Price of the target token in 18 decimals
    function priceFromBaseToken(
        address _oracle,
        address _token,
        address _baseToken,
        uint256 _amountOut
    ) internal returns (uint256 price) {
        (uint256 basePrice,) = IBeefyOracle(_oracle).getFreshPrice(_baseToken);
        uint8 decimals = IERC20MetadataUpgradeable(_token).decimals();
        _amountOut = scaleAmount(_amountOut, decimals);
        price =  basePrice * 1 ether / _amountOut;
    }

    /// @dev Scale an input amount to 18 decimals
    /// @param _amount Amount to be scaled up or down
    /// @param _decimals Decimals that the amount is already in
    /// @return scaledAmount New scaled amount in 18 decimals
    function scaleAmount(
        uint256 _amount,
        uint8 _decimals
    ) internal pure returns (uint256 scaledAmount) {
        scaledAmount = _decimals == 18 ? _amount : _amount * 10 ** 18 / 10 ** _decimals;
    }
}

File 6 of 9 : IUniswapV3Pool.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

    function token1() external view returns (address);

    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint32 feeProtocol,
            bool unlocked
        );

    function tickSpacing() external view returns (int24);

    function positions(
        bytes32 key
    )
        external
        view
        returns (
            uint128 _liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);

    function collect(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);

    function burn(int24 tickLower, int24 tickUpper, uint128 amount) external returns (uint256 amount0, uint256 amount1);

    function observe(
        uint32[] calldata secondsAgos
    ) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
}

File 7 of 9 : IBeefyOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IBeefyOracle {
    function getPrice(address token) external view returns (uint256 price);
    function getPrice(address[] calldata tokens) external view returns (uint256[] memory prices);
    function getFreshPrice(address token) external returns (uint256 price, bool success);
    function getFreshPrice(address[] calldata tokens) external returns (uint256[] memory prices, bool[] memory successes);
}

File 8 of 9 : TickMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
        require(absTick <= uint256(uint24(MAX_TICK)), 'T');

        uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
        // second inequality must be < because the price can never reach the price at the max tick
        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
        int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);

        tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
    }
}

File 9 of 9 : UniswapV3OracleLibrary.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../interfaces/common/IUniswapV3Pool.sol";
import "./TickMath.sol";

/// @title Oracle library
/// @notice Provides functions to integrate with V3 pool oracle
library UniswapV3OracleLibrary {
    /// @notice Calculates time-weighted means of tick and liquidity for a given Uniswap V3 pool
    /// @param pool Address of the pool that we want to observe
    /// @param secondsAgo Number of seconds in the past from which to calculate the time-weighted means
    /// @return arithmeticMeanTick The arithmetic mean tick from (block.timestamp - secondsAgo) to block.timestamp
    /// @return harmonicMeanLiquidity The harmonic mean liquidity from (block.timestamp - secondsAgo) to block.timestamp
    function consult(address pool, uint32 secondsAgo)
        internal
        view
        returns (int24 arithmeticMeanTick, uint128 harmonicMeanLiquidity)
    {
        require(secondsAgo != 0, 'BP');

        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = secondsAgo;
        secondsAgos[1] = 0;

        (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) =
            IUniswapV3Pool(pool).observe(secondsAgos);

        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
        uint160 secondsPerLiquidityCumulativesDelta =
            secondsPerLiquidityCumulativeX128s[1] - secondsPerLiquidityCumulativeX128s[0];

        arithmeticMeanTick = int24(tickCumulativesDelta / int32(secondsAgo));
        // Always round to negative infinity
        if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int32(secondsAgo) != 0)) arithmeticMeanTick--;

        // We are multiplying here instead of shifting to ensure that harmonicMeanLiquidity doesn't overflow uint128
        uint192 secondsAgoX160 = uint192(secondsAgo) * type(uint160).max;
        harmonicMeanLiquidity = uint128(secondsAgoX160 / (uint192(secondsPerLiquidityCumulativesDelta) << 32));
    }

    /// @notice Given a tick and a token amount, calculates the amount of token received in exchange
    /// @param tick Tick value used to calculate the quote
    /// @param baseAmount Amount of token to be converted
    /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
    function getQuoteAtTick(
        int24 tick,
        uint256 baseAmount
    ) internal pure returns (uint256 quoteAmount) {
        uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);

        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
        if (sqrtRatioX96 * baseAmount <= type(uint128).max) {
            uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
            quoteAmount = ratioX192 * baseAmount / (1 << 192);
        } else {
            uint256 ratioX128 = uint256(sqrtRatioX96) * sqrtRatioX96 / (1 << 64);
            quoteAmount = ratioX128 * baseAmount / (1 << 128);
        }
    }

    /// @notice Returns the "synthetic" tick which represents the price of the first entry in `tokens` in terms of the last
    /// @dev Useful for calculating relative prices along routes.
    /// @dev There must be one tick for each pairwise set of tokens.
    /// @param tokens The token contract addresses
    /// @param ticks The ticks, representing the price of each token pair in `tokens`
    /// @return syntheticTick The synthetic tick, representing the relative price of the outermost tokens in `tokens`
    function getChainedPrice(address[] memory tokens, int24[] memory ticks)
        internal
        pure
        returns (int256 syntheticTick)
    {
        require(tokens.length - 1 == ticks.length, 'DL');
        for (uint256 i = 1; i <= ticks.length; i++) {
            // check the tokens for address sort order, then accumulate the
            // ticks into the running synthetic tick, ensuring that intermediate tokens "cancel out"
            tokens[i - 1] < tokens[i] ? syntheticTick += ticks[i - 1] : syntheticTick -= ticks[i - 1];
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"ArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"NoBasePrice","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"name":"TokenNotInPair","type":"error"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"validateData","outputs":[],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100365760003560e01c80636b4dd1581461003b578063a6ffa36c14610067575b600080fd5b61004e610049366004610f8b565b61007c565b6040805192835290151560208301520160405180910390f35b61007a610075366004610f8b565b610278565b005b60008080808061008e868801886110f8565b9250925092506000825167ffffffffffffffff8111156100b0576100b0610ffd565b6040519080825280602002602001820160405280156100d9578160200160208202803683370190505b50905060005b8351811015610152576101248482815181106100fd576100fd6111d6565b6020026020010151848381518110610117576101176111d6565b60200260200101516105e8565b50828281518110610137576101376111d6565b60029290920b602092830291909101909101526001016100df565b50600061015f858361082e565b9050627fffff81131561017d57600080965096505050505050610271565b600061020f8287600081518110610196576101966111d6565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101ff91906111ec565b61020a90600a61130b565b61095e565b905061025d338760018951610224919061131a565b81518110610234576102346111d6565b60200260200101518860008151811061024f5761024f6111d6565b602002602001015184610a1a565b9750871561026a57600196505b5050505050505b9250929050565b60008080610288848601866110f8565b9250925092508151600161029c919061132d565b83511415806102b8575080516102b390600161132d565b835114155b156102d6576040516305c3d17360e11b815260040160405180910390fd5b6000336001600160a01b03166341976e09856000815181106102fa576102fa6111d6565b60200260200101516040518263ffffffff1660e01b815260040161032d91906001600160a01b0391909116815260200190565b602060405180830381865afa15801561034a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061036e9190611340565b9050806000036103c5578360008151811061038b5761038b6111d6565b602002602001015160405163089bfea760e01b81526004016103bc91906001600160a01b0391909116815260200190565b60405180910390fd5b825160005b818110156105de5760008682815181106103e6576103e66111d6565b60200260200101519050600087836001610400919061132d565b81518110610410576104106111d6565b60200260200101519050600087848151811061042e5761042e6111d6565b602002602001015190506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049c9190611359565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105029190611359565b9050816001600160a01b0316856001600160a01b0316141580156105385750806001600160a01b0316856001600160a01b031614155b1561056957604051638a9bb81760e01b81526001600160a01b038087166004830152841660248201526044016103bc565b816001600160a01b0316846001600160a01b03161415801561059d5750806001600160a01b0316846001600160a01b031614155b156105ce57604051638a9bb81760e01b81526001600160a01b038086166004830152841660248201526044016103bc565b85600101955050505050506103ca565b5050505050505050565b6000808263ffffffff166000036106265760405162461bcd60e51b8152602060048201526002602482015261042560f41b60448201526064016103bc565b604080516002808252606082018352600092602083019080368337019050509050838160008151811061065b5761065b6111d6565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061068a5761068a6111d6565b602002602001019063ffffffff16908163ffffffff1681525050600080866001600160a01b031663883bdbfd846040518263ffffffff1660e01b81526004016106d39190611376565b600060405180830381865afa1580156106f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107189190810190611428565b91509150600082600081518110610731576107316111d6565b60200260200101518360018151811061074c5761074c6111d6565b602002602001015161075e91906114f4565b9050600082600081518110610775576107756111d6565b602002602001015183600181518110610790576107906111d6565b60200260200101516107a29190611521565b90506107b2600389900b83611557565b965060008260060b1280156107d657506107d0600389900b83611595565b60060b15155b156107e957866107e5816115b7565b9750505b60006108026001600160a01b0363ffffffff8b166115da565b905061081f640100000000600160c01b03602084901b168261160c565b96505050505050509250929050565b6000815160018451610840919061131a565b146108725760405162461bcd60e51b8152602060048201526002602482015261111360f21b60448201526064016103bc565b60015b825181116109575783818151811061088f5761088f6111d6565b60200260200101516001600160a01b0316846001836108ae919061131a565b815181106108be576108be6111d6565b60200260200101516001600160a01b03161061090e57826108e060018361131a565b815181106108f0576108f06111d6565b602002602001015160020b826109069190611632565b915081610944565b8261091a60018361131a565b8151811061092a5761092a6111d6565b602002602001015160020b826109409190611652565b9150815b508061094f8161167a565b915050610875565b5092915050565b60008061096a84610b27565b90506fffffffffffffffffffffffffffffffff610990846001600160a01b038416611693565b116109cd5760006109aa6001600160a01b03831680611693565b9050600160c01b6109bb8583611693565b6109c591906116aa565b925050610957565b6000680100000000000000006109ec6001600160a01b03841680611693565b6109f691906116aa565b9050600160801b610a078583611693565b610a1191906116aa565b95945050505050565b60405163baeb325b60e01b81526001600160a01b038381166004830152600091829187169063baeb325b9060240160408051808303816000875af1158015610a66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8a91906116be565b5090506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610acd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af191906111ec565b9050610afd8482610f49565b935083610b1283670de0b6b3a7640000611693565b610b1c91906116aa565b979650505050505050565b60008060008360020b12610b3e578260020b610b4b565b8260020b610b4b906116f3565b9050610b5a620d89e71961170f565b62ffffff16811115610b925760405162461bcd60e51b81526020600482015260016024820152601560fa1b60448201526064016103bc565b600081600116600003610ba957600160801b610bbb565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615610bfa576080610bf5826ffff97272373d413259a46990580e213a611693565b901c90505b6004821615610c24576080610c1f826ffff2e50f5f656932ef12357cf3c7fdcc611693565b901c90505b6008821615610c4e576080610c49826fffe5caca7e10e4e61c3624eaa0941cd0611693565b901c90505b6010821615610c78576080610c73826fffcb9843d60f6159c9db58835c926644611693565b901c90505b6020821615610ca2576080610c9d826fff973b41fa98c081472e6896dfb254c0611693565b901c90505b6040821615610ccc576080610cc7826fff2ea16466c96a3843ec78b326b52861611693565b901c90505b6080821615610cf6576080610cf1826ffe5dee046a99a2a811c461f1969c3053611693565b901c90505b610100821615610d21576080610d1c826ffcbe86c7900a88aedcffc83b479aa3a4611693565b901c90505b610200821615610d4c576080610d47826ff987a7253ac413176f2b074cf7815e54611693565b901c90505b610400821615610d77576080610d72826ff3392b0822b70005940c7a398e4b70f3611693565b901c90505b610800821615610da2576080610d9d826fe7159475a2c29b7443b29c7fa6e889d9611693565b901c90505b611000821615610dcd576080610dc8826fd097f3bdfd2022b8845ad8f792aa5825611693565b901c90505b612000821615610df8576080610df3826fa9f746462d870fdf8a65dc1f90e061e5611693565b901c90505b614000821615610e23576080610e1e826f70d869a156d2a1b890bb3df62baf32f7611693565b901c90505b618000821615610e4e576080610e49826f31be135f97d08fd981231505542fcfa6611693565b901c90505b62010000821615610e7a576080610e75826f09aa508b5b7a84e1c677de54f3e99bc9611693565b901c90505b62020000821615610ea5576080610ea0826e5d6af8dedb81196699c329225ee604611693565b901c90505b62040000821615610ecf576080610eca826d2216e584f5fa1ea926041bedfe98611693565b901c90505b62080000821615610ef7576080610ef2826b048a170391f7dc42444e8fa2611693565b901c90505b60008460020b1315610f1257610f0f816000196116aa565b90505b610f2164010000000082611731565b15610f2d576001610f30565b60005b610f419060ff16602083901c61132d565b949350505050565b60008160ff16601214610f8257610f6182600a61130b565b610f7384670de0b6b3a7640000611693565b610f7d91906116aa565b610f84565b825b9392505050565b60008060208385031215610f9e57600080fd5b823567ffffffffffffffff80821115610fb657600080fd5b818501915085601f830112610fca57600080fd5b813581811115610fd957600080fd5b866020828501011115610feb57600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561103c5761103c610ffd565b604052919050565b600067ffffffffffffffff82111561105e5761105e610ffd565b5060051b60200190565b6001600160a01b038116811461107d57600080fd5b50565b600082601f83011261109157600080fd5b813560206110a66110a183611044565b611013565b8083825260208201915060208460051b8701019350868411156110c857600080fd5b602086015b848110156110ed5780356110e081611068565b83529183019183016110cd565b509695505050505050565b60008060006060848603121561110d57600080fd5b833567ffffffffffffffff8082111561112557600080fd5b61113187838801611080565b945060209150818601358181111561114857600080fd5b61115488828901611080565b94505060408601358181111561116957600080fd5b86019050601f8101871361117c57600080fd5b803561118a6110a182611044565b81815260059190911b820183019083810190898311156111a957600080fd5b928401925b828410156111c7578335825292840192908401906111ae565b80955050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156111fe57600080fd5b815160ff81168114610f8457600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b808511156112605781600019048211156112465761124661120f565b8085161561125357918102915b93841c939080029061122a565b509250929050565b60008261127757506001611305565b8161128457506000611305565b816001811461129a57600281146112a4576112c0565b6001915050611305565b60ff8411156112b5576112b561120f565b50506001821b611305565b5060208310610133831016604e8410600b84101617156112e3575081810a611305565b6112ed8383611225565b80600019048211156113015761130161120f565b0290505b92915050565b6000610f8460ff841683611268565b818103818111156113055761130561120f565b808201808211156113055761130561120f565b60006020828403121561135257600080fd5b5051919050565b60006020828403121561136b57600080fd5b8151610f8481611068565b6020808252825182820181905260009190848201906040850190845b818110156113b457835163ffffffff1683529284019291840191600101611392565b50909695505050505050565b600082601f8301126113d157600080fd5b815160206113e16110a183611044565b8083825260208201915060208460051b87010193508684111561140357600080fd5b602086015b848110156110ed57805161141b81611068565b8352918301918301611408565b6000806040838503121561143b57600080fd5b825167ffffffffffffffff8082111561145357600080fd5b818501915085601f83011261146757600080fd5b815160206114776110a183611044565b82815260059290921b8401810191818101908984111561149657600080fd5b948201945b838610156114c45785518060060b81146114b55760008081fd5b8252948201949082019061149b565b918801519196509093505050808211156114dd57600080fd5b506114ea858286016113c0565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff821317156113055761130561120f565b6001600160a01b038281168282160390808211156109575761095761120f565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061156e5761156e611541565b667fffffffffffff1982146000198214161561158c5761158c61120f565b90059392505050565b60008260060b806115a8576115a8611541565b808360060b0791505092915050565b60008160020b627fffff1981036115d0576115d061120f565b6000190192915050565b6001600160c01b038281168282168181028316929181158285048214176116035761160361120f565b50505092915050565b60006001600160c01b038381168061162657611626611541565b92169190910492915050565b81810360008312801583831316838312821617156109575761095761120f565b80820182811260008312801582168215821617156116725761167261120f565b505092915050565b60006001820161168c5761168c61120f565b5060010190565b80820281158282048414176113055761130561120f565b6000826116b9576116b9611541565b500490565b600080604083850312156116d157600080fd5b82519150602083015180151581146116e857600080fd5b809150509250929050565b6000600160ff1b82016117085761170861120f565b5060000390565b60008160020b627fffff1981036117285761172861120f565b60000392915050565b60008261174057611740611541565b50069056fea26469706673582212205a7fadcc472118fa3e5695d011922003375fe13aa9c4980e8fa6782336c9b66664736f6c63430008170033

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.