S Price: $0.48927 (+8.47%)

Contract Diff Checker

Contract Name:
OffchainOracle

Contract Source Code:

File 1 of 1 : OffchainOracle

// SPDX-License-Identifier: No

pragma solidity 0.7.6;

library SafeMath {
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

library Sqrt {
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IERC20Metadata is IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}
// For Uniswap v1
interface IUniswapV1 {
    function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 );
}
// For Uniswap v2, Quickswap v2, Sushiswap v2, pancakeswap v2
interface IUniswapV2Pair {
    function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
    function token0() external view returns (address);
    function token1() external view returns (address);
}
// For Uniswap v3, Sushiswap v3, Pancakeswap v3
interface IUniswapV3Pool {
    function slot0() external view returns (uint160 sqrtPriceX96, int24, uint16, uint16, uint16, uint8, bool);
    function ticks(int24 tick) external view returns (uint128, int128, uint256, uint256, int56, uint160, uint32, bool);
    function tickSpacing() external view returns (int24);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function liquidity() external view returns (uint128);
}
// For Quickswap v3
interface IAlgebraPool {
    function globalState() external view returns (uint160 price, int24 tick, uint16 fee, uint16 timepointIndex, uint8 communityFeeToken0, uint8 communityFeeToken1, bool unlocked);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function liquidity() external view returns (uint128);
}
// For Meshswap
interface IMeshswapPool {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function reserve0() external view returns (uint112);
    function reserve1() external view returns (uint112);
}
// For Balancer v2
interface IStablePool {
    function getTokenRate(address) external view returns (uint256);
}
// For Balancer v2
interface IWeightedPool {
    function getPoolId() external view returns (bytes32);
    function getNormalizedWeights() external view returns (uint256[] memory);
}
// For Balancer v2
interface IVault {
    function getPoolTokens(bytes32 poolId) external view returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock);
}
// For Kyber swap
interface IKyberDmmPool {
    function getTradeInfo() external view returns (uint112 reserve0, uint112 reserve1, uint112 _vReserve0, uint112 _vReserve1, uint256 feeInPrecision);
    function token0() external view returns (address);
    function token1() external view returns (address);
}
// For Curve v2
interface ICurveV2Pool {
    function price_oracle() external view returns (uint256); 
    function coins(uint256 arg0) external view returns (address);
}
// For Curve Stable
interface ICurveStablePool {
    function price_oracle(uint256 arg0) external view returns (uint256); 
    function N_COINS() external view returns (uint256); 
    function coins(uint256 arg0) external view returns (address); 
}
// // For Dodoex V2 DSP
// interface IDodoDSP {
//     function _BASE_TOKEN_() external view returns (address);
//     function _QUOTE_TOKEN_() external view returns (address);
//     function querySellBase(address trader, uint256 payBaseAmount) external view returns (uint256 receiveQuoteAmount, uint256 mtFee, uint8 newRState, uint256 newBaseTarget);
//     function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee, uint8 newRState, uint256 newQuoteTarget);
// }
// For Dodoex V2 DVM & DSP
interface IDodoDVM {
    function _BASE_TOKEN_() external view returns (address);
    function _QUOTE_TOKEN_() external view returns (address);
    function querySellBase(address trader, uint256 payBaseAmount) external view returns (uint256 receiveQuoteAmount, uint256 mtFee);
    function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee);
}
contract OffchainOracle {
    using SafeMath for uint256;
    using SafeMath for uint112;
    using Sqrt for uint256;

    function getRate(address tokenFrom, address tokenTo, address poolAddress, uint8 ver) external view returns (uint256 rate, uint8 decimalsFrom, uint8 decimalsTo) {
        if(ver == 2 || ver == 5 || ver == 7) {
            address token0;
            address token1;
            uint256 reserve0;
            uint256 reserve1;
            // version = 2 : Uniswap V2 like
            if(ver == 2) {
                token0 = IUniswapV2Pair(poolAddress).token0();
                token1 = IUniswapV2Pair(poolAddress).token1();
                (reserve0, reserve1,) = IUniswapV2Pair(poolAddress).getReserves(); 
            } 
            // version = 5 : Meshswap
            else if(ver == 5) {
                token0 = IMeshswapPool(poolAddress).token0();
                token1 = IMeshswapPool(poolAddress).token1();
                reserve0 = IMeshswapPool(poolAddress).reserve0();
                reserve1 = IMeshswapPool(poolAddress).reserve1();
            }
            // version = 7 : Kyber swap
            else if(ver == 7) {
                token0 = IKyberDmmPool(poolAddress).token0();
                token1 = IKyberDmmPool(poolAddress).token1();
                (,, reserve0, reserve1,) = IKyberDmmPool(poolAddress).getTradeInfo();
            }
            if(token0 == tokenFrom) {
                decimalsFrom = IERC20Metadata(token0).decimals();
                decimalsTo = IERC20Metadata(token1).decimals();
                rate = reserve1.mul(1e18).div(reserve0);
            } else {
                decimalsFrom = IERC20Metadata(token1).decimals();
                decimalsTo = IERC20Metadata(token0).decimals();
                rate = reserve0.mul(1e18).div(reserve1);
            }
        }
        // version = 1 : Uniswap V1
        else if(ver == 1) {
            decimalsFrom = IERC20Metadata(tokenFrom).decimals();
            decimalsTo = 18;
            rate = IUniswapV1(poolAddress).getTokenToEthInputPrice(10**decimalsFrom);
        }
        // version = 3 : Uniswap V3
        else if(ver == 3) {
            address token0 = IUniswapV3Pool(poolAddress).token0();
            address token1 = IUniswapV3Pool(poolAddress).token1();
            (uint256 sqrtPriceX96,,,,,,) = IUniswapV3Pool(poolAddress).slot0();
            if(token0 == tokenFrom) {
                decimalsFrom = IERC20Metadata(token0).decimals();
                decimalsTo = IERC20Metadata(token1).decimals();
                rate = (((1e18 * sqrtPriceX96) >> 96) * sqrtPriceX96) >> 96;
            } else {
                decimalsFrom = IERC20Metadata(token1).decimals();
                decimalsTo = IERC20Metadata(token0).decimals();
                rate = (1e18 << 192) / sqrtPriceX96 / sqrtPriceX96;
            }
        } 
        // version = 4 : QuickSwap V3
        else if(ver == 4) {
            address token0 = IAlgebraPool(poolAddress).token0();
            address token1 = IAlgebraPool(poolAddress).token1();
            (uint256 sqrtPriceX96,,,,,,) = IAlgebraPool(poolAddress).globalState();
            if(token0 == tokenFrom) {
                decimalsFrom = IERC20Metadata(token0).decimals();
                decimalsTo = IERC20Metadata(token1).decimals();
                rate = (((1e18 * sqrtPriceX96) >> 96) * sqrtPriceX96) >> 96;
            } else {
                decimalsFrom = IERC20Metadata(token1).decimals();
                decimalsTo = IERC20Metadata(token0).decimals();
                rate = (1e18 << 192) / sqrtPriceX96 / sqrtPriceX96;
            }
        }
        // version = 6 : balancer v2
        else if(ver == 6) {
            address balancerVaultAddress = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
            bytes32 poolId = IWeightedPool(poolAddress).getPoolId();
            (uint256[] memory weights) = IWeightedPool(poolAddress).getNormalizedWeights();
            (address[] memory tokens, uint256[] memory balances,) = IVault(balancerVaultAddress).getPoolTokens(poolId);
            uint256 balanceOfTokenFrom = 0;
            uint256 balanceOfTokenTo = 0;
            for(uint8 i = 0; i < tokens.length; i++ ){
                if(tokens[i] == tokenFrom) {
                    balanceOfTokenFrom = balances[i].mul(1e18).div(weights[i]);
                }
                if(tokens[i] == tokenTo) {
                    balanceOfTokenTo = balances[i].mul(1e18).div(weights[i]);
                }
            }
            decimalsFrom = IERC20Metadata(tokenFrom).decimals();
            decimalsTo = IERC20Metadata(tokenTo).decimals();
            rate = balanceOfTokenTo.mul(1e18).div(balanceOfTokenFrom);
        } 
        // version = 8 : Curve v2
        // return price_oracle
        else if(ver == 8) {
            rate = ICurveV2Pool(poolAddress).price_oracle();
            address token0 = ICurveV2Pool(poolAddress).coins(0);
            if(tokenFrom == token0) {
                uint256 num1e36 = 1e36;
                rate = num1e36.div(rate);
            }
            decimalsFrom = 18;
            decimalsTo = 18;
        }
        // version = 9 : Dodoex v2 DVM & DSP with sell = 1 
        // (ver=12 : sell=10^(-4)) 
        // (ver=13 : sell=10^(-2)) 
        // (ver=14 : sell=10^(2)) 
        // (ver=15 : sell=10^(4)) 
        // (ver=16 : sell=10^(6)) 
        else if(ver == 9 || ver == 12 || ver == 13 || ver == 14 || ver == 15 || ver == 16) {
            address token0 = IDodoDVM(poolAddress)._BASE_TOKEN_();
            address token1 = IDodoDVM(poolAddress)._QUOTE_TOKEN_();
            
            uint8 num = 4;
            if(ver == 9) {
                num = 4;
            } else if(ver == 12) {
                num = 0;
            } else if(ver == 13) {
                num = 2;
            } else if(ver == 14) {
                num = 6;
            } else if(ver == 15) {
                num = 8;
            } else if(ver == 16) {
                num = 10;
            }

            if(tokenFrom == token0) {
                decimalsFrom = IERC20Metadata(token0).decimals();
                decimalsTo = IERC20Metadata(token1).decimals();
                (uint256 receiveQuoteAmount, ) = IDodoDVM(poolAddress).querySellBase(0xD692C31E5ec0d87D032ABC243c1eb2C9Ae204FeA, 10**(decimalsFrom+num-4));
                rate = receiveQuoteAmount.mul(1e18).div(10**decimalsTo);
            } else {
                decimalsFrom = IERC20Metadata(token1).decimals();
                decimalsTo = IERC20Metadata(token0).decimals();
                (uint256 receiveBaseAmount, ) = IDodoDVM(poolAddress).querySellQuote(0xD692C31E5ec0d87D032ABC243c1eb2C9Ae204FeA, 10**(decimalsFrom+num-4));
                rate = receiveBaseAmount.mul(1e18).div(10**decimalsTo);
            }

            decimalsFrom = 18;
            decimalsTo = 18;
        }
        // version = 10: Balancer stable pool
        else if(ver == 10) {
            uint256 rateFrom = IStablePool(poolAddress).getTokenRate(tokenFrom);
            uint256 rateTo = IStablePool(poolAddress).getTokenRate(tokenTo);
            rate = rateFrom.mul(1e18).div(rateTo);
            decimalsFrom = 18;
            decimalsTo = 18;
        }
        // version = 11 :, Curve Stable
        // return price_oracle(i)
        else if(ver == 11) {
            uint256 N_COINS = ICurveStablePool(poolAddress).N_COINS();
            uint256 tokenFromInd = 0;
            for(uint256 i = 1; i < N_COINS; i++) {
                address tmpToken = ICurveStablePool(poolAddress).coins(i);
                if(tmpToken == tokenFrom) {
                    tokenFromInd = i - 1;
                    break;
                }
            }
            rate = ICurveStablePool(poolAddress).price_oracle(tokenFromInd);
            decimalsFrom = 18;
            decimalsTo = 18;
        }
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):