Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
PriceCalculatorBSC.sol
Created
5 years ago
Diff never expires
Clear
Export
Share
Explain
8 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
144 lines
Copy
48 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
185 lines
Copy
// 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";
Copy
Copied
Copy
Copied
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";
Copy
Copied
Copy
Copied
import "../../library/HomoraMath.sol";
contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable {
contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable {
using SafeMath for uint;
using SafeMath for uint;
Copy
Copied
Copy
Copied
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;
Copy
Copied
Copy
Copied
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);
Copy
Copied
Copy
Copied
AggregatorV3Interface private constant bnbPriceFeed = AggregatorV3Interface(0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE);
/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */
mapping(address => address) private pairTokens;
mapping(address => address) private pairTokens;
Copy
Copied
Copy
Copied
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;
}
}
Copy
Copied
Copy
Copied
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) {
Copy
Copied
Copy
Copied
(, 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) {
Copy
Copied
Copy
Copied
(,
u
int
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) {
if (asset == address(0) || asset == WBNB) {
Copy
Copied
Copy
Copied
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) {
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);
}
}
}
}
}
}
Saved diffs
Original text
Open file
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; /* ___ _ _ | _ )_ _ _ _ _ _ _ _ | | | | | _ \ || | ' \| ' \ || | |_| |_| |___/\_,_|_||_|_||_\_, | (_) (_) |__/ * * MIT License * =========== * * Copyright (c) 2020 BunnyFinance * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 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 */ 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 "../../interfaces/IPancakePair.sol"; import "../../interfaces/IPancakeFactory.sol"; import "../../interfaces/AggregatorV3Interface.sol"; import "../../interfaces/IPriceCalculator.sol"; contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable { using SafeMath for uint; address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; address public constant CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82; address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51; address public constant VAI = 0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7; address public constant BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56; IPancakeFactory private constant factory = IPancakeFactory(0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73); AggregatorV3Interface private constant bnbPriceFeed = AggregatorV3Interface(0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE); /* ========== STATE VARIABLES ========== */ mapping(address => address) private pairTokens; /* ========== INITIALIZER ========== */ function initialize() external initializer { __Ownable_init(); setPairToken(VAI, BUSD); } /* ========== Restricted Operation ========== */ function setPairToken(address asset, address pairToken) public onlyOwner { pairTokens[asset] = pairToken; } /* ========== Value Calculation ========== */ function priceOfBNB() view public returns (uint) { (, int price, , ,) = bnbPriceFeed.latestRoundData(); return uint(price).mul(1e10); } function priceOfCake() view public returns (uint) { (, uint cakePriceInUSD) = valueOfAsset(CAKE, 1e18); return cakePriceInUSD; } function priceOfBunny() view public returns (uint) { (, uint bunnyPriceInUSD) = valueOfAsset(BUNNY, 1e18); return bunnyPriceInUSD; } function pricesInUSD(address[] memory assets) public view override returns (uint[] memory) { uint[] memory prices = new uint[](assets.length); for (uint i = 0; i < assets.length; i++) { (, uint valueInUSD) = valueOfAsset(assets[i], 1e18); prices[i] = valueInUSD; } return prices; } function valueOfAsset(address asset, uint amount) public view override returns (uint valueInBNB, uint valueInUSD) { if (asset == address(0) || asset == WBNB) { valueInBNB = amount; valueInUSD = amount.mul(priceOfBNB()).div(1e18); } else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) { if (IPancakePair(asset).totalSupply() == 0) return (0, 0); (uint reserve0, uint reserve1, ) = IPancakePair(asset).getReserves(); if (IPancakePair(asset).token0() == WBNB) { valueInBNB = amount.mul(reserve0).mul(2).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } else if (IPancakePair(asset).token1() == WBNB) { valueInBNB = amount.mul(reserve1).mul(2).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } else { (uint token0PriceInBNB,) = valueOfAsset(IPancakePair(asset).token0(), 1e18); valueInBNB = amount.mul(reserve0).mul(2).mul(token0PriceInBNB).div(1e18).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } } else { address pairToken = pairTokens[asset] == address(0) ? WBNB : pairTokens[asset]; address pair = factory.getPair(asset, pairToken); if (IBEP20(asset).balanceOf(pair) == 0) return (0, 0); (uint reserve0, uint reserve1, ) = IPancakePair(pair).getReserves(); if (IPancakePair(pair).token0() == pairToken) { valueInBNB = reserve0.mul(amount).div(reserve1); } else if (IPancakePair(pair).token1() == pairToken) { valueInBNB = reserve1.mul(amount).div(reserve0); } else { return (0, 0); } if (pairToken != WBNB) { (uint pairValueInBNB,) = valueOfAsset(pairToken, 1e18); valueInBNB = valueInBNB.mul(pairValueInBNB).div(1e18); } valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } } }
Changed text
Open file
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; /* ___ _ _ | _ )_ _ _ _ _ _ _ _ | | | | | _ \ || | ' \| ' \ || | |_| |_| |___/\_,_|_||_|_||_\_, | (_) (_) |__/ * * MIT License * =========== * * Copyright (c) 2020 BunnyFinance * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 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 */ import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "../../interfaces/IPancakePair.sol"; import "../../interfaces/IPancakeFactory.sol"; import "../../interfaces/AggregatorV3Interface.sol"; import "../../interfaces/IPriceCalculator.sol"; import "../../library/HomoraMath.sol"; contract PriceCalculatorBSC is IPriceCalculator, OwnableUpgradeable { using SafeMath for uint; using HomoraMath for uint; address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; address public constant CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82; address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51; address public constant VAI = 0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7; 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); /* ========== STATE VARIABLES ========== */ mapping(address => address) private pairTokens; mapping(address => address) private tokenFeeds; /* ========== INITIALIZER ========== */ function initialize() external initializer { __Ownable_init(); setPairToken(VAI, BUSD); } /* ========== Restricted Operation ========== */ function setPairToken(address asset, address pairToken) public onlyOwner { pairTokens[asset] = pairToken; } function setTokenFeed(address asset, address feed) public onlyOwner { tokenFeeds[asset] = feed; } /* ========== Value Calculation ========== */ function priceOfBNB() view public returns (uint) { (, int price, , ,) = AggregatorV3Interface(tokenFeeds[WBNB]).latestRoundData(); return uint(price).mul(1e10); } function priceOfCake() view public returns (uint) { (, int price, , ,) = AggregatorV3Interface(tokenFeeds[CAKE]).latestRoundData(); return uint(price).mul(1e10); } function priceOfBunny() view public returns (uint) { (, uint bunnyPriceInUSD) = valueOfAsset(BUNNY, 1e18); return bunnyPriceInUSD; } function pricesInUSD(address[] memory assets) public view override returns (uint[] memory) { uint[] memory prices = new uint[](assets.length); for (uint i = 0; i < assets.length; i++) { (, uint valueInUSD) = valueOfAsset(assets[i], 1e18); prices[i] = valueInUSD; } return prices; } 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) { valueInBNB = amount; valueInUSD = amount.mul(priceOfBNB()).div(1e18); } else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) { if (IPancakePair(asset).totalSupply() == 0) return (0, 0); (uint reserve0, uint reserve1, ) = IPancakePair(asset).getReserves(); if (IPancakePair(asset).token0() == WBNB) { valueInBNB = amount.mul(reserve0).mul(2).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } else if (IPancakePair(asset).token1() == WBNB) { valueInBNB = amount.mul(reserve1).mul(2).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } else { (uint token0PriceInBNB,) = valueOfAsset(IPancakePair(asset).token0(), 1e18); valueInBNB = amount.mul(reserve0).mul(2).mul(token0PriceInBNB).div(1e18).div(IPancakePair(asset).totalSupply()); valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } } else { address pairToken = pairTokens[asset] == address(0) ? WBNB : pairTokens[asset]; address pair = factory.getPair(asset, pairToken); if (IBEP20(asset).balanceOf(pair) == 0) return (0, 0); (uint reserve0, uint reserve1, ) = IPancakePair(pair).getReserves(); if (IPancakePair(pair).token0() == pairToken) { valueInBNB = reserve0.mul(amount).div(reserve1); } else if (IPancakePair(pair).token1() == pairToken) { valueInBNB = reserve1.mul(amount).div(reserve0); } else { return (0, 0); } if (pairToken != WBNB) { (uint pairValueInBNB,) = valueOfAsset(pairToken, 1e18); valueInBNB = valueInBNB.mul(pairValueInBNB).div(1e18); } valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18); } } }
Find difference