PriceCalculatorBSC.sol

Created Diff never expires
6 removals
144 lines
47 additions
185 lines
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
pragma experimental ABIEncoderV2;


/*
/*
___ _ _
___ _ _
| _ )_ _ _ _ _ _ _ _ | | | |
| _ )_ _ _ _ _ _ _ _ | | | |
| _ \ || | ' \| ' \ || | |_| |_|
| _ \ || | ' \| ' \ || | |_| |_|
|___/\_,_|_||_|_||_\_, | (_) (_)
|___/\_,_|_||_|_||_\_, | (_) (_)
|__/
|__/


*
*
* MIT License
* MIT License
* ===========
* ===========
*
*
* Copyright (c) 2020 BunnyFinance
* Copyright (c) 2020 BunnyFinance
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in all
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
*/


import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";


import "../../interfaces/IPancakePair.sol";
import "../../interfaces/IPancakePair.sol";
import "../../interfaces/IPancakeFactory.sol";
import "../../interfaces/IPancakeFactory.sol";
import "../../interfaces/AggregatorV3Interface.sol";
import "../../interfaces/AggregatorV3Interface.sol";
import "../../interfaces/IPriceCalculator.sol";
import "../../interfaces/IPriceCalculator.sol";
import "../../library/HomoraMath.sol";




contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable {
contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable {
using SafeMath for uint;
using SafeMath for uint;
using HomoraMath for uint;


address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82;
address public constant CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82;
address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51;
address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51;
address public constant VAI = 0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7;
address public constant VAI = 0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7;
address public constant BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;
address public constant BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;


address public constant BUNNY_BNB_V1 = 0x7Bb89460599Dbf32ee3Aa50798BBcEae2A5F7f6a;
address public constant BUNNY_BNB_V2 = 0x5aFEf8567414F29f0f927A0F2787b188624c10E2;

IPancakeFactory private constant factory = IPancakeFactory(0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73);
IPancakeFactory private constant factory = IPancakeFactory(0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73);
AggregatorV3Interface private constant bnbPriceFeed = AggregatorV3Interface(0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE);


/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */


mapping(address => address) private pairTokens;
mapping(address => address) private pairTokens;
mapping(address => address) private tokenFeeds;


/* ========== INITIALIZER ========== */
/* ========== INITIALIZER ========== */


function initialize() external initializer {
function initialize() external initializer {
__Ownable_init();
__Ownable_init();
setPairToken(VAI, BUSD);
setPairToken(VAI, BUSD);
}
}


/* ========== Restricted Operation ========== */
/* ========== Restricted Operation ========== */


function setPairToken(address asset, address pairToken) public onlyOwner {
function setPairToken(address asset, address pairToken) public onlyOwner {
pairTokens[asset] = pairToken;
pairTokens[asset] = pairToken;
}
}


function setTokenFeed(address asset, address feed) public onlyOwner {
tokenFeeds[asset] = feed;
}

/* ========== Value Calculation ========== */
/* ========== Value Calculation ========== */


function priceOfBNB() view public returns (uint) {
function priceOfBNB() view public returns (uint) {
(, int price, , ,) = bnbPriceFeed.latestRoundData();
(, int price, , ,) = AggregatorV3Interface(tokenFeeds[WBNB]).latestRoundData();
return uint(price).mul(1e10);
return uint(price).mul(1e10);
}
}


function priceOfCake() view public returns (uint) {
function priceOfCake() view public returns (uint) {
(, uint cakePriceInUSD) = valueOfAsset(CAKE, 1e18);
(, int price, , ,) = AggregatorV3Interface(tokenFeeds[CAKE]).latestRoundData();
return cakePriceInUSD;
return uint(price).mul(1e10);
}
}


function priceOfBunny() view public returns (uint) {
function priceOfBunny() view public returns (uint) {
(, uint bunnyPriceInUSD) = valueOfAsset(BUNNY, 1e18);
(, uint bunnyPriceInUSD) = valueOfAsset(BUNNY, 1e18);
return bunnyPriceInUSD;
return bunnyPriceInUSD;
}
}


function pricesInUSD(address[] memory assets) public view override returns (uint[] memory) {
function pricesInUSD(address[] memory assets) public view override returns (uint[] memory) {
uint[] memory prices = new uint[](assets.length);
uint[] memory prices = new uint[](assets.length);
for (uint i = 0; i < assets.length; i++) {
for (uint i = 0; i < assets.length; i++) {
(, uint valueInUSD) = valueOfAsset(assets[i], 1e18);
(, uint valueInUSD) = valueOfAsset(assets[i], 1e18);
prices[i] = valueInUSD;
prices[i] = valueInUSD;
}
}
return prices;
return prices;
}
}


function valueOfAsset(address asset, uint amount) public view override returns (uint valueInBNB, uint valueInUSD) {
function valueOfAsset(address asset, uint amount) public view override returns (uint valueInBNB, uint valueInUSD) {
if (asset == address(0) || asset == WBNB) {
return _oracleValueOf(WBNB, amount);
} else if (asset == BUNNY || asset == BUNNY_BNB_V1 || asset == BUNNY_BNB_V2) {
return _unsafeValueOfAsset(asset, amount);
} else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) {
return _getPairPrice(asset, amount);
} else {
return _oracleValueOf(asset, amount);
}
}

function _oracleValueOf(address asset, uint amount) private view returns (uint valueInBNB, uint valueInUSD) {
(, int price, , ,) = AggregatorV3Interface(tokenFeeds[asset]).latestRoundData();
valueInUSD = uint(price).mul(1e10).mul(amount).div(1e18);
valueInBNB = valueInUSD.mul(1e18).div(priceOfBNB());
}

function _getPairPrice(address pair, uint amount) private view returns (uint valueInBNB, uint valueInUSD) {
address token0 = IPancakePair(pair).token0();
address token1 = IPancakePair(pair).token1();
uint totalSupply = IPancakePair(pair).totalSupply();
(uint r0, uint r1, ) = IPancakePair(pair).getReserves();

uint sqrtK = HomoraMath.sqrt(r0.mul(r1)).fdiv(totalSupply);
(uint px0,) = _oracleValueOf(token0, 1e18);
(uint px1,) = _oracleValueOf(token1, 1e18);
uint fairPriceInBNB = sqrtK.mul(2).mul(HomoraMath.sqrt(px0)).div(2**56).mul(HomoraMath.sqrt(px1)).div(2**56);

valueInBNB = fairPriceInBNB.mul(amount).div(1e18);
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
}

function _unsafeValueOfAsset(address asset, uint amount) private view returns (uint valueInBNB, uint valueInUSD) {
if (asset == address(0) || asset == WBNB) {
if (asset == address(0) || asset == WBNB) {
valueInBNB = amount;
valueInBNB = amount;
valueInUSD = amount.mul(priceOfBNB()).div(1e18);
valueInUSD = amount.mul(priceOfBNB()).div(1e18);
}
}
else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) {
else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) {
if (IPancakePair(asset).totalSupply() == 0) return (0, 0);
if (IPancakePair(asset).totalSupply() == 0) return (0, 0);


(uint reserve0, uint reserve1, ) = IPancakePair(asset).getReserves();
(uint reserve0, uint reserve1, ) = IPancakePair(asset).getReserves();
if (IPancakePair(asset).token0() == WBNB) {
if (IPancakePair(asset).token0() == WBNB) {
valueInBNB = amount.mul(reserve0).mul(2).div(IPancakePair(asset).totalSupply());
valueInBNB = amount.mul(reserve0).mul(2).div(IPancakePair(asset).totalSupply());
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
} else if (IPancakePair(asset).token1() == WBNB) {
} else if (IPancakePair(asset).token1() == WBNB) {
valueInBNB = amount.mul(reserve1).mul(2).div(IPancakePair(asset).totalSupply());
valueInBNB = amount.mul(reserve1).mul(2).div(IPancakePair(asset).totalSupply());
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
} else {
} else {
(uint token0PriceInBNB,) = valueOfAsset(IPancakePair(asset).token0(), 1e18);
(uint token0PriceInBNB,) = valueOfAsset(IPancakePair(asset).token0(), 1e18);
valueInBNB = amount.mul(reserve0).mul(2).mul(token0PriceInBNB).div(1e18).div(IPancakePair(asset).totalSupply());
valueInBNB = amount.mul(reserve0).mul(2).mul(token0PriceInBNB).div(1e18).div(IPancakePair(asset).totalSupply());
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
}
}
}
}
else {
else {
address pairToken = pairTokens[asset] == address(0) ? WBNB : pairTokens[asset];
address pairToken = pairTokens[asset] == address(0) ? WBNB : pairTokens[asset];
address pair = factory.getPair(asset, pairToken);
address pair = factory.getPair(asset, pairToken);
if (IBEP20(asset).balanceOf(pair) == 0) return (0, 0);
if (IBEP20(asset).balanceOf(pair) == 0) return (0, 0);


(uint reserve0, uint reserve1, ) = IPancakePair(pair).getReserves();
(uint reserve0, uint reserve1, ) = IPancakePair(pair).getReserves();
if (IPancakePair(pair).token0() == pairToken) {
if (IPancakePair(pair).token0() == pairToken) {
valueInBNB = reserve0.mul(amount).div(reserve1);
valueInBNB = reserve0.mul(amount).div(reserve1);
} else if (IPancakePair(pair).token1() == pairToken) {
} else if (IPancakePair(pair).token1() == pairToken) {
valueInBNB = reserve1.mul(amount).div(reserve0);
valueInBNB = reserve1.mul(amount).div(reserve0);
} else {
} else {
return (0, 0);
return (0, 0);
}
}


if (pairToken != WBNB) {
if (pairToken != WBNB) {
(uint pairValueInBNB,) = valueOfAsset(pairToken, 1e18);
(uint pairValueInBNB,) = valueOfAsset(pairToken, 1e18);
valueInBNB = valueInBNB.mul(pairValueInBNB).div(1e18);
valueInBNB = valueInBNB.mul(pairValueInBNB).div(1e18);
}
}
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
}
}
}
}
}
}