Comparing sensitive data, confidential files or internal emails?

Most legal and privacy policies prohibit uploading sensitive data online. Diffchecker Desktop ensures your confidential information never leaves your computer. Work offline and compare documents securely.

BunnyMinterV2.sol

Created Diff never expires
81 removals
313 lines
18 additions
251 lines
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma solidity ^0.6.12;


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


*
*
* 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/BEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/BEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol";
import "@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol";


import "../interfaces/IBunnyMinterV2.sol";
import "../interfaces/IBunnyMinterV2.sol";
import "../interfaces/IStakingRewards.sol";
import "../interfaces/IStakingRewards.sol";
import "../dashboard/calculator/PriceCalculatorBSC.sol";
import "../interfaces/IPriceCalculator.sol";

import "../zap/ZapBSC.sol";
import "../zap/ZapBSC.sol";
import "../library/SafeToken.sol";


contract BunnyMinterV2 is IBunnyMinterV2, OwnableUpgradeable {
contract BunnyMinterV2 is IBunnyMinterV2, OwnableUpgradeable {
using SafeMath for uint;
using SafeMath for uint;
using SafeBEP20 for IBEP20;
using SafeBEP20 for IBEP20;


/* ========== CONSTANTS ============= */
/* ========== CONSTANTS ============= */


address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51;
address public constant BUNNY = 0xC9849E6fdB743d08fAeE3E34dd2D1bc69EA11a51;
address public constant BUNNY_BNB = 0x7Bb89460599Dbf32ee3Aa50798BBcEae2A5F7f6a;
address public constant BUNNY_POOL = 0xCADc8CB26c8C7cB46500E61171b5F27e9bd7889D;
address public constant BUNNY_POOL = 0xCADc8CB26c8C7cB46500E61171b5F27e9bd7889D;


address public constant DEPLOYER = 0xe87f02606911223C2Cf200398FFAF353f60801F7;
address public constant TREASURY = 0x0989091F27708Bc92ea4cA60073e03592B94C0eE;
address private constant TIMELOCK = 0x85c9162A51E03078bdCd08D4232Bab13ed414cC3;
address private constant TIMELOCK = 0x85c9162A51E03078bdCd08D4232Bab13ed414cC3;
address private constant DEAD = 0x000000000000000000000000000000000000dEaD;
address private constant DEAD = 0x000000000000000000000000000000000000dEaD;


uint public constant FEE_MAX = 10000;
uint public constant FEE_MAX = 10000;


ZapBSC public constant zapBSC = ZapBSC(0xCBEC8e7AB969F6Eb873Df63d04b4eAFC353574b1);
IPriceCalculator public constant priceCalculator = IPriceCalculator(0xF5BF8A9249e3cc4cB684E3f23db9669323d4FB7d);
ZapBSC public constant zapBSCV2 = ZapBSC(0xdC2bBB0D33E0e7Dea9F5b98F46EDBaC823586a0C);
PriceCalculatorBSC public constant priceCalculator = PriceCalculatorBSC(0x542c06a5dc3f27e0fbDc9FB7BC6748f26d54dDb0); // should be V1 address

IPancakeRouter02 private constant routerV1 = IPancakeRouter02(0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F);
IPancakeRouter02 private constant routerV2 = IPancakeRouter02(0x10ED43C718714eb63d5aA57B78B54704E256024E);


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


address public bunnyChef;
address public bunnyChef;
mapping(address => bool) private _minters;
mapping(address => bool) private _minters;
address public _deprecated_helper; // deprecated
address public _deprecated_helper; // deprecated


uint public PERFORMANCE_FEE;
uint public PERFORMANCE_FEE;
uint public override WITHDRAWAL_FEE_FREE_PERIOD;
uint public override WITHDRAWAL_FEE_FREE_PERIOD;
uint public override WITHDRAWAL_FEE;
uint public override WITHDRAWAL_FEE;


uint public override bunnyPerProfitBNB;
uint public override bunnyPerProfitBNB;
uint public bunnyPerBunnyBNBFlip; // will be deprecated
uint public bunnyPerBunnyBNBFlip; // will be deprecated


/* ========== MODIFIERS ========== */
/* ========== MODIFIERS ========== */


modifier onlyMinter {
modifier onlyMinter {
require(isMinter(msg.sender) == true, "BunnyMinterV2: caller is not the minter");
require(isMinter(msg.sender) == true, "BunnyMinterV2: caller is not the minter");
_;
_;
}
}


modifier onlyBunnyChef {
modifier onlyBunnyChef {
require(msg.sender == bunnyChef, "BunnyMinterV2: caller not the bunny chef");
require(msg.sender == bunnyChef, "BunnyMinterV2: caller not the bunny chef");
_;
_;
}
}


receive() external payable {}
receive() external payable {}


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


function initialize() external initializer {
function initialize() external initializer {
WITHDRAWAL_FEE_FREE_PERIOD = 3 days;
WITHDRAWAL_FEE_FREE_PERIOD = 3 days;
WITHDRAWAL_FEE = 50;
WITHDRAWAL_FEE = 50;
PERFORMANCE_FEE = 3000;
PERFORMANCE_FEE = 3000;


bunnyPerProfitBNB = 5e18;
bunnyPerProfitBNB = 5e18;
bunnyPerBunnyBNBFlip = 6e18;
bunnyPerBunnyBNBFlip = 6e18;


IBEP20(BUNNY).approve(BUNNY_POOL, uint(- 1));
IBEP20(BUNNY).approve(BUNNY_POOL, uint(- 1));
}
}


/* ========== RESTRICTED FUNCTIONS ========== */
/* ========== RESTRICTED FUNCTIONS ========== */


function transferBunnyOwner(address _owner) external onlyOwner {
function transferBunnyOwner(address _owner) external onlyOwner {
Ownable(BUNNY).transferOwnership(_owner);
Ownable(BUNNY).transferOwnership(_owner);
}
}


function setWithdrawalFee(uint _fee) external onlyOwner {
function setWithdrawalFee(uint _fee) external onlyOwner {
require(_fee < 500, "wrong fee");
require(_fee < 500, "wrong fee");
// less 5%
// less 5%
WITHDRAWAL_FEE = _fee;
WITHDRAWAL_FEE = _fee;
}
}


function setPerformanceFee(uint _fee) external onlyOwner {
function setPerformanceFee(uint _fee) external onlyOwner {
require(_fee < 5000, "wrong fee");
require(_fee < 5000, "wrong fee");
PERFORMANCE_FEE = _fee;
PERFORMANCE_FEE = _fee;
}
}


function setWithdrawalFeeFreePeriod(uint _period) external onlyOwner {
function setWithdrawalFeeFreePeriod(uint _period) external onlyOwner {
WITHDRAWAL_FEE_FREE_PERIOD = _period;
WITHDRAWAL_FEE_FREE_PERIOD = _period;
}
}


function setMinter(address minter, bool canMint) external override onlyOwner {
function setMinter(address minter, bool canMint) external override onlyOwner {
if (canMint) {
if (canMint) {
_minters[minter] = canMint;
_minters[minter] = canMint;
} else {
} else {
delete _minters[minter];
delete _minters[minter];
}
}
}
}


function setBunnyPerProfitBNB(uint _ratio) external onlyOwner {
function setBunnyPerProfitBNB(uint _ratio) external onlyOwner {
bunnyPerProfitBNB = _ratio;
bunnyPerProfitBNB = _ratio;
}
}


function setBunnyPerBunnyBNBFlip(uint _bunnyPerBunnyBNBFlip) external onlyOwner {
function setBunnyPerBunnyBNBFlip(uint _bunnyPerBunnyBNBFlip) external onlyOwner {
bunnyPerBunnyBNBFlip = _bunnyPerBunnyBNBFlip;
bunnyPerBunnyBNBFlip = _bunnyPerBunnyBNBFlip;
}
}


function setBunnyChef(address _bunnyChef) external onlyOwner {
function setBunnyChef(address _bunnyChef) external onlyOwner {
require(bunnyChef == address(0), "BunnyMinterV2: setBunnyChef only once");
require(bunnyChef == address(0), "BunnyMinterV2: setBunnyChef only once");
bunnyChef = _bunnyChef;
bunnyChef = _bunnyChef;
}
}


/* ========== VIEWS ========== */
/* ========== VIEWS ========== */


function isMinter(address account) public view override returns (bool) {
function isMinter(address account) public view override returns (bool) {
if (IBEP20(BUNNY).getOwner() != address(this)) {
if (IBEP20(BUNNY).getOwner() != address(this)) {
return false;
return false;
}
}
return _minters[account];
return _minters[account];
}
}


function amountBunnyToMint(uint bnbProfit) public view override returns (uint) {
function amountBunnyToMint(uint bnbProfit) public view override returns (uint) {
return bnbProfit.mul(bunnyPerProfitBNB).div(1e18);
return bnbProfit.mul(bunnyPerProfitBNB).div(1e18);
}
}


function amountBunnyToMintForBunnyBNB(uint amount, uint duration) public view override returns (uint) {
function amountBunnyToMintForBunnyBNB(uint amount, uint duration) public view override returns (uint) {
return amount.mul(bunnyPerBunnyBNBFlip).mul(duration).div(365 days).div(1e18);
return amount.mul(bunnyPerBunnyBNBFlip).mul(duration).div(365 days).div(1e18);
}
}


function withdrawalFee(uint amount, uint depositedAt) external view override returns (uint) {
function withdrawalFee(uint amount, uint depositedAt) external view override returns (uint) {
if (depositedAt.add(WITHDRAWAL_FEE_FREE_PERIOD) > block.timestamp) {
if (depositedAt.add(WITHDRAWAL_FEE_FREE_PERIOD) > block.timestamp) {
return amount.mul(WITHDRAWAL_FEE).div(FEE_MAX);
return amount.mul(WITHDRAWAL_FEE).div(FEE_MAX);
}
}
return 0;
return 0;
}
}


function performanceFee(uint profit) public view override returns (uint) {
function performanceFee(uint profit) public view override returns (uint) {
return profit.mul(PERFORMANCE_FEE).div(FEE_MAX);
return profit.mul(PERFORMANCE_FEE).div(FEE_MAX);
}
}


/* ========== V1 FUNCTIONS ========== */
/* ========== V1 FUNCTIONS ========== */


function mintFor(address asset, uint _withdrawalFee, uint _performanceFee, address to, uint) external payable override onlyMinter {
function mintFor(address asset, uint _withdrawalFee, uint _performanceFee, address to, uint) public payable override onlyMinter {
uint feeSum = _performanceFee.add(_withdrawalFee);
uint feeSum = _performanceFee.add(_withdrawalFee);
_transferAsset(asset, feeSum);
_transferAsset(asset, feeSum);


if (asset == BUNNY) {
if (asset == BUNNY) {
IBEP20(BUNNY).safeTransfer(DEAD, feeSum);
IBEP20(BUNNY).safeTransfer(DEAD, feeSum);
return;
return;
}
}


uint bunnyBNBAmount = _zapAssetsToBunnyBNB(asset, feeSum, false);
if (asset == address(0)) { // means BNB
if (bunnyBNBAmount == 0) return;
SafeToken.safeTransferETH(TREASURY, feeSum);

} else {
IBEP20(BUNNY_BNB).safeTransfer(BUNNY_POOL, bunnyBNBAmount);
IBEP20(asset).safeTransfer(TREASURY, feeSum);
IStakingRewards(BUNNY_POOL).notifyRewardAmount(bunnyBNBAmount);
}


(uint valueInBNB,) = priceCalculator.valueOfAsset(BUNNY_BNB, bunnyBNBAmount);
(uint contribution, ) = priceCalculator.valueOfAsset(asset, _performanceFee);
uint contribution = valueInBNB.mul(_performanceFee).div(feeSum);
uint mintBunny = amountBunnyToMint(contribution);
uint mintBunny = amountBunnyToMint(contribution);
if (mintBunny == 0) return;
if (mintBunny == 0) return;
_mint(mintBunny, to);
_mint(mintBunny, to);
}
}


/* ========== PancakeSwap V2 FUNCTIONS ========== */
/* ========== PancakeSwap V2 FUNCTIONS ========== */


function mintForV2(address asset, uint _withdrawalFee, uint _performanceFee, address to, uint) external payable override onlyMinter {
function mintForV2(address asset, uint _withdrawalFee, uint _performanceFee, address to, uint timestamp) external payable override onlyMinter {
uint feeSum = _performanceFee.add(_withdrawalFee);
mintFor(asset, _withdrawalFee, _performanceFee, to, timestamp);
_transferAsset(asset, feeSum);

if (asset == BUNNY) {
IBEP20(BUNNY).safeTransfer(DEAD, feeSum);
return;
}

uint bunnyBNBAmount = _zapAssetsToBunnyBNB(asset, feeSum, true);
if (bunnyBNBAmount == 0) return;

IBEP20(BUNNY_BNB).safeTransfer(BUNNY_POOL, bunnyBNBAmount);
IStakingRewards(BUNNY_POOL).notifyRewardAmount(bunnyBNBAmount);

(uint valueInBNB,) = priceCalculator.valueOfAsset(BUNNY_BNB, bunnyBNBAmount);
uint contribution = valueInBNB.mul(_performanceFee).div(feeSum);
uint mintBunny = amountBunnyToMint(contribution);
if (mintBunny == 0) return;
_mint(mintBunny, to);
}
}


/* ========== BunnyChef FUNCTIONS ========== */
/* ========== BunnyChef FUNCTIONS ========== */


function mint(uint amount) external override onlyBunnyChef {
function mint(uint amount) external override onlyBunnyChef {
if (amount == 0) return;
if (amount == 0) return;
_mint(amount, address(this));
_mint(amount, address(this));
}
}


function safeBunnyTransfer(address _to, uint _amount) external override onlyBunnyChef {
function safeBunnyTransfer(address _to, uint _amount) external override onlyBunnyChef {
if (_amount == 0) return;
if (_amount == 0) return;


uint bal = IBEP20(BUNNY).balanceOf(address(this));
uint bal = IBEP20(BUNNY).balanceOf(address(this));
if (_amount <= bal) {
if (_amount <= bal) {
IBEP20(BUNNY).safeTransfer(_to, _amount);
IBEP20(BUNNY).safeTransfer(_to, _amount);
} else {
} else {
IBEP20(BUNNY).safeTransfer(_to, bal);
IBEP20(BUNNY).safeTransfer(_to, bal);
}
}
}
}


// @dev should be called when determining mint in governance. Bunny is transferred to the timelock contract.
// @dev should be called when determining mint in governance. Bunny is transferred to the timelock contract.
function mintGov(uint amount) external override onlyOwner {
function mintGov(uint amount) external override onlyOwner {
if (amount == 0) return;
if (amount == 0) return;
_mint(amount, TIMELOCK);
_mint(amount, TIMELOCK);
}
}


/* ========== PRIVATE FUNCTIONS ========== */
/* ========== PRIVATE FUNCTIONS ========== */


function _transferAsset(address asset, uint amount) private {
function _transferAsset(address asset, uint amount) private {
if (asset == address(0)) {
if (asset == address(0)) {
// case) transferred BNB
// case) transferred BNB
require(msg.value >= amount);
require(msg.value >= amount);
} else {
} else {
IBEP20(asset).safeTransferFrom(msg.sender, address(this), amount);
IBEP20(asset).safeTransferFrom(msg.sender, address(this), amount);
}
}
}
}


function _zapAssetsToBunnyBNB(address asset, uint amount, bool fromV2) private returns (uint bunnyBNBAmount) {
uint _initBunnyBNBAmount = IBEP20(BUNNY_BNB).balanceOf(address(this));

if (asset == address(0)) {
zapBSC.zapIn{ value : amount }(BUNNY_BNB);
}
else if (keccak256(abi.encodePacked(IPancakePair(asset).symbol())) == keccak256("Cake-LP")) {
IPancakeRouter02 router = fromV2 ? routerV2 : routerV1;

if (IBEP20(asset).allowance(address(this), address(router)) == 0) {
IBEP20(asset).safeApprove(address(router), uint(- 1));
}

IPancakePair pair = IPancakePair(asset);
address token0 = pair.token0();
address token1 = pair.token1();

(uint amountToken0, uint amountToken1) = router.removeLiquidity(token0, token1, amount, 0, 0, address(this), block.timestamp);

if (IBEP20(token0).allowance(address(this), address(zapBSC)) == 0) {
IBEP20(token0).safeApprove(address(zapBSC), uint(- 1));
}
if (IBEP20(token1).allowance(address(this), address(zapBSC)) == 0) {
IBEP20(token1).safeApprove(address(zapBSC), uint(- 1));
}

zapBSC.zapInToken(token0, amountToken0, BUNNY_BNB);
zapBSC.zapInToken(token1, amountToken1, BUNNY_BNB);
}
else {
if (IBEP20(asset).allowance(address(this), address(zapBSC)) == 0) {
IBEP20(asset).safeApprove(address(zapBSC), uint(- 1));
}

zapBSC.zapInToken(asset, amount, BUNNY_BNB);
}

bunnyBNBAmount = IBEP20(BUNNY_BNB).balanceOf(address(this)).sub(_initBunnyBNBAmount);
}

function _mint(uint amount, address to) private {
function _mint(uint amount, address to) private {
BEP20 tokenBUNNY = BEP20(BUNNY);
BEP20 tokenBUNNY = BEP20(BUNNY);


tokenBUNNY.mint(amount);
tokenBUNNY.mint(amount);
if (to != address(this)) {
if (to != address(this)) {
tokenBUNNY.transfer(to, amount);
tokenBUNNY.transfer(to, amount);
}
}


uint bunnyForDev = amount.mul(15).div(100);
uint bunnyForDev = amount.mul(15).div(100);
tokenBUNNY.mint(bunnyForDev);
tokenBUNNY.mint(bunnyForDev);
IStakingRewards(BUNNY_POOL).stakeTo(bunnyForDev, DEPLOYER);
tokenBUNNY.transfer(TREASURY, bunnyForDev);
}
}
}
}