Contract 0xd79dc49ed716832658ec28fe93dd733e0dfb8d58 1

 
Txn Hash
Block
From
To
Value [Txn Fee]
0x32d0e7480f206044f6bad995bdc954467e9fc1d72fc78f9ee7a198739429aeed96413432021-07-31 21:53:3444 secs ago0x6617e137f255745cec7b8a0969183f6d60e515ee IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00042506
0xc5684c518718794cf94936a107a2df862b197eeaa9927e268285b7ce3f2099b496412702021-07-31 21:49:554 mins ago0x86f6cc253f0c0d129fe9140ae18db4891494a21a IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050012
0xacec03ccf98ae918912c1d5c2429582a9cd1be7d766b7c3ae40651ff7ce5c05d96412142021-07-31 21:47:077 mins ago0x478cda6b8f61ef82b8233962c284a615c7da6271 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000528025
0xdd4f4aaf395577344f59af16b98ab7dc9677a5ba2aca4291a8733f497c0c950c96410672021-07-31 21:39:4614 mins ago0xc2163626675ee9162cd68aadbcc28d797f3966af IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050012
0xa261e2ec66e2ca01e86e1f0034eee573a0ba0613d8e76826255f17ab8e603b3696410182021-07-31 21:37:1916 mins ago0xed5385770fbb69872f31af5ec00471268779fb9e IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001622475
0xdafe8047671538eee89093ef6d4e2e16f644164360e7d96aff80986e6c9ca81e96410162021-07-31 21:37:1317 mins ago0x014467cc3f40ef555a27651e860bd92f92d69125 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00042512
0x6540bece5e4bed30da07f38e88dec0547a612a1d24d8a1b847f79b6797e3281096409912021-07-31 21:35:5818 mins ago0x484c5ecd7e493fb5004edfdccf9364afc98d3f9c IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001411275
0x496dbc85b16ef2e5643e8ae80c6d96ad15a56cc19bfa63741e0a306de13dd8b396409302021-07-31 21:32:5521 mins ago0xc598a776ec83ca10289dcbfdd561c07caa414813 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000478835
0xdf9eeb50d490604075ffec820db6dac16c67b5c07f0c96bcf4d9d4321c4e86a796408862021-07-31 21:30:4023 mins ago0xf3cb47cf59a71b36a371dce1f6b1b5c9f1fb0d19 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00162873
0x06e5a212ff94d5fc30c8cfe5dbb45dadf45e7d09f7e4f1823b28e651bd66149096408702021-07-31 21:29:5224 mins ago0xee59fa6e0fb81d1101ccef377670fbcdf03bafd3 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000553835
0x491c1124ab5fb31e068f1fcb2a77e05453f613451b1dbaa4a5d5fe59ae579cbf96408132021-07-31 21:27:0127 mins ago0x9ca0c85ad7a98d56b331779abadbced09cfb4375 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000478895
0xc4bd3af792ca117623f99cb228d534c0db46d31de0322b6893211bc166c0ed7896407372021-07-31 21:23:1331 mins ago0xca8a7efc165a9f31fc46ea7f3a85902bfb478cbd IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001336275
0x587507ab2ac6847c4300f377a63e4e91a314f80c31f6e2a651a6c63089302fc796406682021-07-31 21:19:4634 mins ago0x96067e35bb4ff14232f25a932213b35c8bfaf8f9 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000467566
0x84e0f0d06ae4a17b0385feeb30d92c36a94447a4f480c55d11b46814acdd1b8096406572021-07-31 21:19:1335 mins ago0x15a71cedb3c7b9292b6f09f1bbfd397bff09a26c IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.000528025
0xcaae0ae1e995eae0f84a9fde724007531034df838f386c5d2f334d5f42ef74b796406432021-07-31 21:18:3135 mins ago0x1da7839ddd39443de7b8c4502b998ad583550e51 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00049994
0x0884aabb35c03cdc7c144d3acccc6c358a71b3403bdd6f97cb88123a70edb3d196405862021-07-31 21:15:4038 mins ago0xfb1fdb06e32b01ad5045a188343a870fd6da4ff9 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001411275
0xf4ab4331dadb150ac158fb94b9d6591c3bf36e856c08f34662e8226d9529ce9496405152021-07-31 21:12:0742 mins ago0xbcb84a9049e7d409392e742b86f37573ac6a5550 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050006
0x7510ad14139eae1908a82066b9fb3c8e817402df4acdc0c6d535d082c6d6cfb996405102021-07-31 21:11:5242 mins ago0x1da7839ddd39443de7b8c4502b998ad583550e51 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001357275
0xe4b47db115ada78e329445fbff2ff696c65a76ddaf2f6b6faa77d4df1c23fffa96404052021-07-31 21:06:3747 mins ago0xbcb84a9049e7d409392e742b86f37573ac6a5550 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001357275
0x75fd2c26d133d87f65b2beed6cfabb6703c1bacb2e8d8c5b92c5ee1cfc87b91c96403532021-07-31 21:04:0150 mins ago0xb7dffece1f671f4429078cacfc4737db151684bf IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050006
0xec3279c6baeec76125eeec403ef12877bd4e811dbbbf054120de6e94de9c54d896403442021-07-31 21:03:3450 mins ago0x2f896dd9b2abebfc52fb19074148c249d735b478 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00042506
0x4d02441e540193b9f0d46e3841f7afdd2ab17add2f0b61da03e2a1dd1735cbac96402922021-07-31 21:00:5853 mins ago0xd09743cf6ff624a89193de785684fb89e812c240 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001336275
0xaaa80f7619b4d517801406a073bc94bea3b60963ee29869c735245eab87f0ca296402502021-07-31 20:58:5255 mins ago0xc9e1083fc4197825a3a8f3278ebb5f6bf048ee04 IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050006
0x713afa16c9242680216c8be611108d87ce3ac42f603d41bc8368f4dcbfefa83196402022021-07-31 20:56:2257 mins ago0x65c3c80b2a6baa2f794c10a18308b04ade685c0d IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.00050012
0xf29cc1c205a365fd4655ef2a7b2bc79693c5384c076d17103f5822f8c52be19a96401592021-07-31 20:54:131 hr ago0x65c3c80b2a6baa2f794c10a18308b04ade685c0d IN  0xd79dc49ed716832658ec28fe93dd733e0dfb8d580 BNB0.001357275
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SpacePool

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 43 : SpaceMinter.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";

import "../libraries/BEP20.sol";
import "../libraries/SafeBEP20.sol";
import "../interfaces/ISpaceMinter.sol";
import "../interfaces/IStakingRewards.sol";
import "./PriceCalculator.sol";
import "./SpaceToken.sol";
import "./Zap.sol";

contract SpaceMinter is ISpaceMinter, Ownable {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;
    using Address for address;

    address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
    address public constant DEAD = 0x000000000000000000000000000000000000dEaD;

    SpaceToken public immutable SPACE;

    // @notice dev address for space allocation
    address public immutable DEPLOYER;
    address public immutable SPACE_BNB_PAIR;
    address public immutable SPACE_POOL;
    // @notice masterchef
    address public immutable SPACE_CHEF;

    Zap public zap;
    // @notice owner of the contract when set up
    address public governance;
    // @notice used to calculate value of assets to determine number of space minted.
    PriceCalculator public priceCalculator;

    // @notice lists of vaults/contracts allowed to mint space.
    mapping(address => bool) private _minters;

    uint256 public constant DENOMINATOR = 10000;
    uint256 public constant MAX_WITHDRAWAL_FEE = 500; // 5%
    uint256 public constant MAX_PERFORMANCE_FEE = 5000; // 50%

    uint256 public performanceFeeRate;
    uint256 public override withdrawalFeeFreePeriod;
    uint256 public override withdrawalFeeRate;

    // @notice Space amount to mint per BNB
    uint256 public override amountToMintPerProfit;

    modifier onlyMinter {
        require(isMinter(msg.sender) == true, "SpaceMinter: caller is not allowed dest mint");
        _;
    }

    modifier onlySpaceChef {
        require(msg.sender == SPACE_CHEF, "SpaceMinter: caller not the space chef");
        _;
    }

    // @notice fallback
    receive() external payable {}

    constructor(
        address _SPACE,
        address _SPACE_CHEF,
        address _SPACE_POOL,
        address _PAIR,
        address payable _zap,
        address _priceCalculator
    ) public {
        DEPLOYER = msg.sender;

        SPACE = SpaceToken(_SPACE);
        SPACE_CHEF = _SPACE_CHEF;
        SPACE_POOL = _SPACE_POOL;
        SPACE_BNB_PAIR = _PAIR;

        zap = Zap(_zap);
        priceCalculator = PriceCalculator(_priceCalculator);

        withdrawalFeeFreePeriod = 3 days;
        withdrawalFeeRate = 50;
        performanceFeeRate = 3000;

        amountToMintPerProfit = 64e18;

        IBEP20(_SPACE).safeApprove(_SPACE_POOL, 0);
        IBEP20(_SPACE).safeApprove(_SPACE_POOL, uint256(~0));
    }

    // @notice Minter is owned by governance. Useful to update tokenomics in case of governance proposal.
    function transferSpaceOwner(address _owner) external onlyOwner {
        require(_owner != address(this), "SpaceMinter: transferSpaceOwnership address already set");
        require(_owner != address(0), "SpaceMinter: wrong address");

        Ownable(SPACE).transferOwnership(_owner);
    }

    // @notice One-time call. Called after governance set up
    function setGovernance(address _governance) external onlyOwner {
        require(governance == address(0), "Governance already set");
        governance = _governance;
    }

    function updatePriceCalculator(address _priceCalculator) external onlyOwner {
        require(_priceCalculator != address(0), "SpaceMinter: updatePriceCalculator wrong address");
        require(_priceCalculator != address(priceCalculator), "SpaceMinter: updatePriceCalculator address already set");

        priceCalculator = PriceCalculator(_priceCalculator);
    }

    function updateZap(address payable _zap) external onlyOwner {
        require(_zap != address(0), "updateZap: updateZap wrong address");
        require(_zap != address(zap), "SpaceMinter: updateZap address already set");

        zap = Zap(_zap);
    }

    function setWithdrawalFee(uint256 _fee) external onlyOwner {
        require(_fee < MAX_WITHDRAWAL_FEE, "SpaceMinter: setWithdrawalFee fees too high");
        withdrawalFeeRate = _fee;
    }

    // @notice Performance Fee cut in profit. Default 30%.
    function setPerformanceFee(uint256 _fee) external onlyOwner {
        require(_fee < MAX_PERFORMANCE_FEE, "SpaceMinter: setPerformanceFee fees too high");
        performanceFeeRate = _fee;
    }

    // @notice Period during withdrawal fee are active. Default 3 days.
    function setWithdrawalFeeFreePeriod(uint256 _period) external onlyOwner {
        withdrawalFeeFreePeriod = _period;
    }

    // @notice give right to vaults the right to mint SPACE. Must be a contract.
    function updateAccessToMint(address minter, bool canMint) external override onlyOwner {
        require(minter.isContract(), "SpaceMinter: updateAccessToMint only contract are allowed to mint");

        if (canMint) {
            _minters[minter] = canMint;
        } else {
            delete _minters[minter];
        }
    }

    function updateSpacePerProfit(uint256 _newAmountPerProfit) external onlyOwner {
        amountToMintPerProfit = _newAmountPerProfit;
    }

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

    function amountSpaceToMint(uint256 bnbProfit) public view override returns (uint256) {
        return bnbProfit.mul(amountToMintPerProfit).div(1e18);
    }

    // @notice check if withdrawal fee is applicable for the amount wanted
    function withdrawalFee(uint256 amount, uint256 depositedAt) external view override returns (uint256) {
        if (depositedAt.add(withdrawalFeeFreePeriod) > block.timestamp) {
            return amount.mul(withdrawalFeeRate).div(DENOMINATOR);
        }
        return 0;
    }

    // @notice get performance fee amount cut from profit
    function performanceFee(uint256 profit) public view override returns (uint256) {
        return profit.mul(performanceFeeRate).div(DENOMINATOR);
    }

    function mintFor(
        address asset,
        uint256 withdrawalFeeAmount,
        uint256 performanceFeeAmount,
        address dest,
        uint256 depositedAt
    ) external payable override onlyMinter {
        // Total fee collected
        uint256 totalFee = performanceFeeAmount.add(withdrawalFeeAmount);
        // Get fee from caller
        _transferAsset(asset, totalFee);

        if (asset == address(SPACE)) {
            IBEP20(SPACE).safeTransfer(DEAD, totalFee);
            return;
        }

        // determine value of performance fee.
        (uint256 valueInBNB, ) = priceCalculator.valueOfAsset(asset, totalFee);
        uint256 performanceFeeInBnb = valueInBNB.mul(performanceFeeAmount).div(totalFee);
        uint256 spaceBnbAmount = _zapAssetsToSpaceBnb(asset);

        if (spaceBnbAmount == 0) return;

        IBEP20(SPACE_BNB_PAIR).safeTransfer(SPACE_POOL, spaceBnbAmount);
        IStakingRewards(SPACE_POOL).notifyRewardAmount(spaceBnbAmount);

        // Mint Space according to performance fee BNB value.
        uint256 amountToMint = amountSpaceToMint(performanceFeeInBnb);
        if (amountToMint == 0) return;
        _mint(amountToMint, dest);
    }

    function mint(address dest, uint256 amount) external override onlySpaceChef {
        if (amount == 0) return;
        _mint(amount, dest);
    }

    function safeSpaceTransfer(address _to, uint256 _amount) external override onlySpaceChef {
        if (_amount == 0) return;

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

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

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

    function _zapAssetsToSpaceBnb(address asset) private returns (uint256) {
        // Check allowance
        if (asset != address(0) && IBEP20(asset).allowance(address(this), address(zap)) == 0) {
            IBEP20(asset).safeApprove(address(zap), uint256(-1));
        }

        // Swap BNB for SPACE-BNB
        if (asset == address(0)) {
            zap.zapIn{value: address(this).balance}(SPACE_BNB_PAIR);
        } else if (keccak256(abi.encodePacked(IApePair(asset).symbol())) == keccak256("APE-LP")) {
            // Remove LP token
            zap.zapOut(asset, IBEP20(asset).balanceOf(address(this)));

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

            if (token0 == WBNB || token1 == WBNB) {
                address token = token0 == WBNB ? token1 : token0;
                if (IBEP20(token).allowance(address(this), address(zap)) == 0) {
                    IBEP20(token).safeApprove(address(zap), uint256(-1));
                }
                zap.zapIn{value: address(this).balance}(SPACE_BNB_PAIR);
                zap.zapInToken(token, IBEP20(token).balanceOf(address(this)), SPACE_BNB_PAIR);
            } else {
                if (IBEP20(token0).allowance(address(this), address(zap)) == 0) {
                    IBEP20(token0).safeApprove(address(zap), uint256(-1));
                }
                if (IBEP20(token1).allowance(address(this), address(zap)) == 0) {
                    IBEP20(token1).safeApprove(address(zap), uint256(-1));
                }

                zap.zapInToken(token0, IBEP20(token0).balanceOf(address(this)), SPACE_BNB_PAIR);
                zap.zapInToken(token1, IBEP20(token1).balanceOf(address(this)), SPACE_BNB_PAIR);
            }
        } else {
            zap.zapInToken(asset, IBEP20(asset).balanceOf(address(this)), SPACE_BNB_PAIR);
        }

        return IBEP20(SPACE_BNB_PAIR).balanceOf(address(this));
    }

    function _mint(uint256 amount, address dest) private {
        require(dest != address(0), "SpaceMinter: _mint to wrong address");
        SPACE.mint(dest, amount);

        // if (dest != address(this)) {
        // spaceToken.transfer(dest, amount);
        // }

        uint256 teamAllocation = amount.mul(15).div(100);
        SPACE.mint(teamAllocation);

        // Automatically stack team allocation into SPACE POOL for fees redistribution.
        IStakingRewards(SPACE_POOL).stakeTo(teamAllocation, DEPLOYER);
    }
}

File 2 of 43 : BEP20.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */

pragma solidity >=0.4.0;

import "../interfaces/IBEP20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/GSN/Context.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

/**
 * @dev Implementation of the {IBEP20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {BEP20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-BEP20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of BEP20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IBEP20-approve}.
 */
contract BEP20 is Context, IBEP20, Ownable {
    using SafeMath for uint256;

    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name, string memory symbol) public {
        _name = name;
        _symbol = symbol;
        _decimals = 18;
    }

    /**
     * @dev Returns the bep token owner.
     */
    function getOwner() external view override returns (address) {
        return owner();
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     */
    function decimals() public view override returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {BEP20-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {BEP20-balanceOf}.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {BEP20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {BEP20-allowance}.
     */
    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {BEP20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {BEP20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {BEP20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "BEP20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {BEP20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {BEP20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "BEP20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Creates `amount` tokens and assigns them to `msg.sender`, increasing
     * the total supply.
     *
     * Requirements
     *
     * - `msg.sender` must be the token owner
     */
    function mint(uint256 amount) public onlyOwner returns (bool) {
        _mint(_msgSender(), amount);
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal {
        require(sender != address(0), "BEP20: transfer from the zero address");
        require(recipient != address(0), "BEP20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "BEP20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "BEP20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount, "BEP20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal {
        require(owner != address(0), "BEP20: approve from the zero address");
        require(spender != address(0), "BEP20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "BEP20: burn amount exceeds allowance"));
    }
}

File 3 of 43 : IBEP20.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.4;

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

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

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

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

    /**
     * @dev Returns the bep token owner.
     */
    function getOwner() external view returns (address);

    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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);
}

File 4 of 43 : SafeBEP20.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;

import "../interfaces/IBEP20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";

/**
 * @title SafeBEP20
 * @dev Wrappers around BEP20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeBEP20 for IBEP20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeBEP20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(
        IBEP20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IBEP20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IBEP20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IBEP20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeBEP20: approve from non-zero to non-zero allowance");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IBEP20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IBEP20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeBEP20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IBEP20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeBEP20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeBEP20: BEP20 operation did not succeed");
        }
    }
}

File 5 of 43 : ISpaceMinter.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */

pragma solidity >=0.6.12;

interface ISpaceMinter {
    function isMinter(address) external view returns (bool);

    function amountSpaceToMint(uint256 bnbProfit) external view returns (uint256);

    function withdrawalFee(uint256 amount, uint256 depositedAt) external view returns (uint256);

    function performanceFee(uint256 profit) external view returns (uint256);

    function mintFor(
        address flip,
        uint256 withdrawalFeeAmount,
        uint256 performanceFeeAmount,
        address dest,
        uint256 depositedAt
    ) external payable;

    function amountToMintPerProfit() external view returns (uint256);

    function withdrawalFeeFreePeriod() external view returns (uint256);

    function withdrawalFeeRate() external view returns (uint256);

    function updateAccessToMint(address minter, bool canMint) external;

    function mint(address to, uint256 amount) external;

    function safeSpaceTransfer(address to, uint256 amount) external;

    function mintGov(uint256 amount) external;
}

File 6 of 43 : IStakingRewards.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IStakingRewards {
    function stakeTo(uint256 amount, address _to) external;

    function notifyRewardAmount(uint256 reward) external;
}

File 7 of 43 : PriceCalculator.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */

pragma solidity >=0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import "../libraries/HomoraMath.sol";
import "../interfaces/IPriceOracle.sol";
import "../interfaces/IBEP20.sol";
import "../interfaces/IApePair.sol";
import "../interfaces/IApeFactory.sol";
import "../interfaces/AggregatorV3Interface.sol";
import "../interfaces/IPriceCalculator.sol";

contract PriceCalculator is IPriceCalculator, Ownable {
    using SafeMath for uint256;
    using HomoraMath for uint256;

    address public immutable SPACE;
    address public immutable SPACE_BNB;

    IPriceOracle public oracle;

    address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
    address public constant BANANA = 0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95;
    address public constant BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;

    IApeFactory private constant factory = IApeFactory(0x0841BD0B734E4F5853f0dD8d7Ea041c241fb0Da6);
    AggregatorV3Interface private constant bnbPriceFeed = AggregatorV3Interface(0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE);

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

    constructor(
        address _SPACE_TOKEN,
        address _SPACE_BNB,
        IPriceOracle _oracle
    ) public {
        oracle = _oracle;
        SPACE = _SPACE_TOKEN;
        SPACE_BNB = _SPACE_BNB;
    }

    // Add Pair to asset to be able to use valueOfAsset
    function setPairToken(address asset, address pairToken) public onlyOwner {
        pairTokens[asset] = pairToken;
    }

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

    function setOracleFeeds(address asset, bool available) public onlyOwner {
        oracleFeeds[asset] = available;
    }

    // Price of BNB via Chainlink
    function priceOfBNB() public view returns (uint256) {
        (, int256 price, , , ) = bnbPriceFeed.latestRoundData();
        return uint256(price).mul(1e10);
    }

    // Price of Banana using PriceOracle
    function priceOfBanana() public view returns (uint256) {
        require(oracleFeeds[BANANA], "PriceFeed: Banana not available in Oracle");
        (uint256 priceInBnb, ) = oracle.getPrice(BANANA, WBNB);
        uint256 valueInUSD = priceInBnb.mul(priceOfBNB()).div(1e18);
        return valueInUSD;
    }

    function priceOfSpace() public view returns (uint256) {
        (, uint256 spacePriceInUSD) = valueOfAsset(SPACE, 1e18);
        return spacePriceInUSD;
    }

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

    function _oracleValueOf(address asset, uint256 amount) private view returns (uint256 valueInBNB, uint256 valueInUSD) {
        require(oracleFeeds[asset], "PriceFeed: asset not available in Oracle");

        if (tokenFeeds[asset] != address(0)) {
            (, int256 price, , , ) = AggregatorV3Interface(tokenFeeds[asset]).latestRoundData();
            valueInUSD = uint256(price).mul(1e10).mul(amount).div(1e18);
            valueInBNB = valueInUSD.mul(1e18).div(priceOfBNB());
        } else {
            (uint256 assetPriceInBnb, ) = oracle.getPrice(asset, WBNB);
            valueInBNB = assetPriceInBnb.mul(amount).div(1e18);
            valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
        }
    }

    function valueOfAsset(address asset, uint256 amount) public view override returns (uint256 valueInBNB, uint256 valueInUSD) {
        if (asset == address(0) || asset == WBNB) {
            return _oracleValueOf(WBNB, amount);
        } else if (asset == SPACE || asset == SPACE_BNB) {
            return _valueOfAsset(asset, amount);
        } else if (keccak256(abi.encodePacked(IApePair(asset).symbol())) == keccak256("APE-LP")) {
            return _getPairPrice(asset, amount);
        } else {
            return _oracleValueOf(asset, amount);
        }
    }

    function _getPairPrice(address pair, uint256 amount) private view returns (uint256 valueInBNB, uint256 valueInUSD) {
        address token0 = IApePair(pair).token0();
        address token1 = IApePair(pair).token1();
        uint256 totalSupply = IApePair(pair).totalSupply();
        (uint256 r0, uint256 r1, ) = IApePair(pair).getReserves();
        uint256 sqrtK = HomoraMath.sqrt(r0.mul(r1)).fdiv(totalSupply);
        (uint256 px0, ) = _oracleValueOf(token0, 1e18);
        (uint256 px1, ) = _oracleValueOf(token1, 1e18);
        uint256 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);
    }

    // Need to add Pair Token before using it
    function _valueOfAsset(address asset, uint256 amount) public view returns (uint256 valueInBNB, uint256 valueInUSD) {
        if (asset == address(0) || asset == WBNB) {
            valueInBNB = amount;
            valueInUSD = amount.mul(priceOfBNB()).div(1e18);
        } else if (keccak256(abi.encodePacked(IApePair(asset).symbol())) == keccak256("APE-LP")) {
            if (IApePair(asset).token0() == WBNB || IApePair(asset).token1() == WBNB) {
                valueInBNB = amount.mul(IBEP20(WBNB).balanceOf(address(asset))).mul(2).div(IApePair(asset).totalSupply());
                valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
            } else {
                uint256 balanceToken0 = IBEP20(IApePair(asset).token0()).balanceOf(asset);
                (uint256 token0PriceInBNB, ) = valueOfAsset(IApePair(asset).token0(), 1e18);

                valueInBNB = amount.mul(balanceToken0).mul(2).mul(token0PriceInBNB).div(1e18).div(IApePair(asset).totalSupply());
                valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
            }
        } else {
            address pairToken = pairTokens[asset] == address(0) ? WBNB : pairTokens[asset];
            address pair = factory.getPair(asset, pairToken);
            valueInBNB = IBEP20(pairToken).balanceOf(pair).mul(amount).div(IBEP20(asset).balanceOf(pair));
            if (pairToken != WBNB) {
                (uint256 pairValueInBNB, ) = valueOfAsset(pairToken, 1e18);
                valueInBNB = valueInBNB.mul(pairValueInBNB).div(1e18);
            }
            valueInUSD = valueInBNB.mul(priceOfBNB()).div(1e18);
        }
    }

    function updateOracle(address newOracle) external onlyOwner {
        require(newOracle != address(0), "PriceCalculator: updateOracle wrong address");
        require(newOracle != address(oracle), "PriceCalculator: updateOracle address already set");
        oracle = IPriceOracle(newOracle);
    }
}

File 8 of 43 : HomoraMath.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";

library HomoraMath {
    using SafeMath for uint256;

    function divCeil(uint256 lhs, uint256 rhs) internal pure returns (uint256) {
        return lhs.add(rhs).sub(1) / rhs;
    }

    function fmul(uint256 lhs, uint256 rhs) internal pure returns (uint256) {
        return lhs.mul(rhs) / (2**112);
    }

    function fdiv(uint256 lhs, uint256 rhs) internal pure returns (uint256) {
        return lhs.mul(2**112) / rhs;
    }

    // implementation from https://github.com/Uniswap/uniswap-lib/commit/99f3f28770640ba1bb1ff460ac7c5292fb8291a0
    // original implementation: https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687
    function sqrt(uint256 x) internal pure returns (uint256) {
        if (x == 0) return 0;
        uint256 xx = x;
        uint256 r = 1;

        if (xx >= 0x100000000000000000000000000000000) {
            xx >>= 128;
            r <<= 64;
        }

        if (xx >= 0x10000000000000000) {
            xx >>= 64;
            r <<= 32;
        }
        if (xx >= 0x100000000) {
            xx >>= 32;
            r <<= 16;
        }
        if (xx >= 0x10000) {
            xx >>= 16;
            r <<= 8;
        }
        if (xx >= 0x100) {
            xx >>= 8;
            r <<= 4;
        }
        if (xx >= 0x10) {
            xx >>= 4;
            r <<= 2;
        }
        if (xx >= 0x8) {
            r <<= 1;
        }

        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return (r < r1 ? r : r1);
    }
}

File 9 of 43 : IPriceOracle.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IPriceOracle {
    /// @dev Return the wad price of token0/token1, multiplied by 1e18
    /// NOTE: (if you have 1 token0 how much you can sell it for token1)
    function getPrice(address token0, address token1) external view returns (uint256 price, uint256 lastUpdate);
}

File 10 of 43 : IApePair.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.2;

interface IApePair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);

    function symbol() external pure returns (string memory);

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves()
        external
        view
        returns (
            uint112 reserve0,
            uint112 reserve1,
            uint32 blockTimestampLast
        );

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;
}

File 11 of 43 : IApeFactory.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IApeFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);

    function feeTo() external view returns (address);

    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);

    function allPairs(uint256) external view returns (address pair);

    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;

    function setFeeToSetter(address) external;
}

File 12 of 43 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.0;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);

    function description() external view returns (string memory);

    function version() external view returns (uint256);

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    function getRoundData(uint80 _roundId)
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}

File 13 of 43 : IPriceCalculator.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IPriceCalculator {
    function pricesInUSD(address[] memory assets) external view returns (uint256[] memory);

    function valueOfAsset(address asset, uint256 amount) external view returns (uint256 valueInBNB, uint256 valueInUSD);
}

File 14 of 43 : SpaceToken.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "../libraries/BEP20.sol";

// SpaceToken with Governance.
contract SpaceToken is BEP20("Space Token", "SPACE") {
    // @dev Creates `_amount` token to `_to`. Must only be called by the owner (SpaceMinter).
    function mint(address _to, uint256 _amount) public onlyOwner {
        _mint(_to, _amount);
        _moveDelegates(address(0), _delegates[_to], _amount);
    }

    // Copied and modified from YAM code:
    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol
    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol
    // Which is copied and modified from COMPOUND:
    // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol

    // @dev A record of each accounts delegate
    mapping(address => address) internal _delegates;

    // @dev A checkpoint for marking number of votes from a given block
    struct Checkpoint {
        uint32 fromBlock;
        uint256 votes;
    }

    // @dev A record of votes checkpoints for each account, by index
    mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;

    // @dev The number of checkpoints for each account
    mapping(address => uint32) public numCheckpoints;

    // @dev The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    // @dev The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    // @dev A record of states for signing / validating signatures
    mapping(address => uint256) public nonces;

    // @dev An event thats emitted when an account changes its delegate
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    // @dev An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

    /**
     * @dev Delegate votes from `msg.sender` to `delegatee`
     * @param delegator The address to get delegatee for
     */
    function delegates(address delegator) external view returns (address) {
        return _delegates[delegator];
    }

    /**
     * @dev Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) external {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @dev Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(
        address delegatee,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), getChainId(), address(this)));

        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));

        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));

        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "SPACE::delegateBySig: invalid signature");
        require(nonce == nonces[signatory]++, "SPACE::delegateBySig: invalid nonce");
        require(now <= expiry, "SPACE::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @dev Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint256) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    /**
     * @dev Determine the prior number of votes for an account as of a block number
     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
     * @param account The address of the account to check
     * @param blockNumber The block number to get the vote balance at
     * @return The number of votes the account had as of the given block
     */
    function getPriorVotes(address account, uint256 blockNumber) external view returns (uint256) {
        require(blockNumber < block.number, "SPACE::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlock == blockNumber) {
                return cp.votes;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = _delegates[delegator];
        uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SPACEs (not scaled);
        _delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _moveDelegates(
        address srcRep,
        address dstRep,
        uint256 amount
    ) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                // decrease old representative
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint256 srcRepNew = srcRepOld.sub(amount);
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                // increase new representative
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint256 dstRepNew = dstRepOld.add(amount);
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(
        address delegatee,
        uint32 nCheckpoints,
        uint256 oldVotes,
        uint256 newVotes
    ) internal {
        uint32 blockNumber = safe32(block.number, "SPACE::_writeCheckpoint: block number exceeds 32 bits");

        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
        } else {
            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
            numCheckpoints[delegatee] = nCheckpoints + 1;
        }

        emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
    }

    function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function getChainId() internal pure returns (uint256) {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        return chainId;
    }
}

File 15 of 43 : Zap.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";

import "../libraries/SafeBEP20.sol";
import "../interfaces/IApePair.sol";
import "../interfaces/IApeRouter02.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Zap is Ownable {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    address private immutable SPACE;
    address private constant BANANA = 0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95;
    address private constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
    address private constant BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;
    address private constant USDT = 0x55d398326f99059fF775485246999027B3197955;
    address private constant DAI = 0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3;
    address private constant USDC = 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d;
    address private constant BTCB = 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c;
    address private constant ETH = 0x2170Ed0880ac9A755fd29B2688956BD959F933F8;

    IApeRouter02 private constant ROUTER = IApeRouter02(0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607);

    mapping(address => bool) private notFlip;
    mapping(address => address) private routePairAddresses;
    address[] public tokens;

    constructor(address _spaceToken) public {
        require(owner() != address(0), "Zap: owner must be set");
        SPACE = _spaceToken;

        setNotFlip(BANANA);
        setNotFlip(_spaceToken);
        setNotFlip(WBNB);
        setNotFlip(BUSD);
        setNotFlip(USDT);
        setNotFlip(DAI);
        setNotFlip(USDC);
        setNotFlip(BTCB);
        setNotFlip(ETH);
    }

    receive() external payable {}

    function isFlip(address _address) public view returns (bool) {
        return !notFlip[_address];
    }

    function routePair(address _address) external view returns (address) {
        return routePairAddresses[_address];
    }

    function zapInToken(
        address _from,
        uint256 amount,
        address _to
    ) external {
        if (amount > IBEP20(_from).balanceOf(msg.sender)) amount = IBEP20(_from).balanceOf(msg.sender);
        IBEP20(_from).safeTransferFrom(msg.sender, address(this), amount);
        _approveTokenIfNeeded(_from);

        if (isFlip(_to)) {
            IApePair pair = IApePair(_to);
            address token0 = pair.token0();
            address token1 = pair.token1();
            if (_from == token0 || _from == token1) {
                // swap half amount for other
                address other = _from == token0 ? token1 : token0;
                _approveTokenIfNeeded(other);
                uint256 sellAmount = amount.div(2);
                uint256 otherAmount = _swap(_from, sellAmount, other, address(this));
                ROUTER.addLiquidity(_from, other, amount.sub(sellAmount), otherAmount, 0, 0, msg.sender, block.timestamp);
            } else {
                uint256 bnbAmount = _swapTokenForBNB(_from, amount, address(this));
                _swapBNBToFlip(_to, bnbAmount, msg.sender);
            }
        } else {
            _swap(_from, amount, _to, msg.sender);
        }
    }

    function zapIn(address _to) external payable {
        _swapBNBToFlip(_to, msg.value, msg.sender);
    }

    function zapOut(address _from, uint256 amount) external {
        if (amount > IBEP20(_from).balanceOf(msg.sender)) amount = IBEP20(_from).balanceOf(msg.sender);
        IBEP20(_from).safeTransferFrom(msg.sender, address(this), amount);
        _approveTokenIfNeeded(_from);

        if (!isFlip(_from)) {
            _swapTokenForBNB(_from, amount, msg.sender);
        } else {
            IApePair pair = IApePair(_from);
            address token0 = pair.token0();
            address token1 = pair.token1();
            if (token0 == WBNB || token1 == WBNB) {
                ROUTER.removeLiquidityETH(token0 != WBNB ? token0 : token1, amount, 0, 0, msg.sender, block.timestamp);
            } else {
                ROUTER.removeLiquidity(token0, token1, amount, 0, 0, msg.sender, block.timestamp);
            }
        }
    }

    function _approveTokenIfNeeded(address token) private {
        if (IBEP20(token).allowance(address(this), address(ROUTER)) == 0) {
            IBEP20(token).safeApprove(address(ROUTER), uint256(~0));
        }
    }

    function _swapBNBToFlip(
        address flip,
        uint256 amount,
        address receiver
    ) private {
        if (!isFlip(flip)) {
            _swapBNBForToken(flip, amount, receiver);
        } else {
            // flip
            IApePair pair = IApePair(flip);
            address token0 = pair.token0();
            address token1 = pair.token1();
            if (token0 == WBNB || token1 == WBNB) {
                address token = token0 == WBNB ? token1 : token0;
                uint256 swapValue = amount.div(2);
                uint256 tokenAmount = _swapBNBForToken(token, swapValue, address(this));

                _approveTokenIfNeeded(token);
                ROUTER.addLiquidityETH{value: amount.sub(swapValue)}(token, tokenAmount, 0, 0, receiver, block.timestamp);
            } else {
                uint256 swapValue = amount.div(2);
                uint256 token0Amount = _swapBNBForToken(token0, swapValue, address(this));
                uint256 token1Amount = _swapBNBForToken(token1, amount.sub(swapValue), address(this));

                _approveTokenIfNeeded(token0);
                _approveTokenIfNeeded(token1);
                ROUTER.addLiquidity(token0, token1, token0Amount, token1Amount, 0, 0, receiver, block.timestamp);
            }
        }
    }

    function _swapBNBForToken(
        address token,
        uint256 value,
        address receiver
    ) private returns (uint256) {
        address[] memory path;

        if (routePairAddresses[token] != address(0)) {
            path = new address[](3);
            path[0] = WBNB;
            path[1] = routePairAddresses[token];
            path[2] = token;
        } else {
            path = new address[](2);
            path[0] = WBNB;
            path[1] = token;
        }

        uint256[] memory amounts = ROUTER.swapExactETHForTokens{value: value}(0, path, receiver, block.timestamp);
        return amounts[amounts.length - 1];
    }

    function _swapTokenForBNB(
        address token,
        uint256 amount,
        address receiver
    ) private returns (uint256) {
        address[] memory path;
        if (routePairAddresses[token] != address(0)) {
            path = new address[](3);
            path[0] = token;
            path[1] = routePairAddresses[token];
            path[2] = WBNB;
        } else {
            path = new address[](2);
            path[0] = token;
            path[1] = WBNB;
        }

        uint256[] memory amounts = ROUTER.swapExactTokensForETH(amount, 0, path, receiver, block.timestamp);
        return amounts[amounts.length - 1];
    }

    function _swap(
        address _from,
        uint256 amount,
        address _to,
        address receiver
    ) private returns (uint256) {
        address intermediate = routePairAddresses[_from];
        if (intermediate == address(0)) {
            intermediate = routePairAddresses[_to];
        }

        address[] memory path;
        if (intermediate != address(0) && (_from == WBNB || _to == WBNB)) {
            path = new address[](3);
            path[0] = _from;
            path[1] = intermediate;
            path[2] = _to;
        } else if (intermediate != address(0) && (_from == intermediate || _to == intermediate)) {
            path = new address[](2);
            path[0] = _from;
            path[1] = _to;
        } else if (intermediate != address(0) && routePairAddresses[_from] == routePairAddresses[_to]) {
            path = new address[](3);
            path[0] = _from;
            path[1] = intermediate;
            path[2] = _to;
        } else if (
            routePairAddresses[_from] != address(0) &&
            routePairAddresses[_to] != address(0) &&
            routePairAddresses[_from] != routePairAddresses[_to]
        ) {
            // routePairAddresses[xToken] = xRoute
            path = new address[](5);
            path[0] = _from;
            path[1] = routePairAddresses[_from];
            path[2] = WBNB;
            path[3] = routePairAddresses[_to];
            path[4] = _to;
        } else if (intermediate != address(0) && routePairAddresses[_from] != address(0)) {
            path = new address[](4);
            path[0] = _from;
            path[1] = intermediate;
            path[2] = WBNB;
            path[3] = _to;
        } else if (intermediate != address(0) && routePairAddresses[_to] != address(0)) {
            path = new address[](4);
            path[0] = _from;
            path[1] = WBNB;
            path[2] = intermediate;
            path[3] = _to;
        } else if (_from == WBNB || _to == WBNB) {
            path = new address[](2);
            path[0] = _from;
            path[1] = _to;
        } else {
            path = new address[](3);
            path[0] = _from;
            path[1] = WBNB;
            path[2] = _to;
        }

        uint256[] memory amounts = ROUTER.swapExactTokensForTokens(amount, 0, path, receiver, block.timestamp);
        return amounts[amounts.length - 1];
    }

    function setRoutePairAddress(address asset, address route) external onlyOwner {
        routePairAddresses[asset] = route;
    }

    function setNotFlip(address token) public onlyOwner {
        bool needPush = notFlip[token] == false;
        notFlip[token] = true;
        if (needPush) {
            tokens.push(token);
        }
    }

    function removeToken(uint256 i) external onlyOwner {
        address token = tokens[i];
        notFlip[token] = false;
        tokens[i] = tokens[tokens.length - 1];
        tokens.pop();
    }

    function sweep() external onlyOwner {
        for (uint256 i = 0; i < tokens.length; i++) {
            address token = tokens[i];
            if (token == address(0)) continue;
            uint256 amount = IBEP20(token).balanceOf(address(this));
            if (amount > 0) {
                _swapTokenForBNB(token, amount, owner());
            }
        }
    }

    // Emergency only
    function withdraw(address token) external onlyOwner {
        if (token == address(0)) {
            payable(owner()).transfer(address(this).balance);
            return;
        }

        IBEP20(token).transfer(owner(), IBEP20(token).balanceOf(address(this)));
    }
}

File 16 of 43 : IApeRouter02.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */

pragma solidity >=0.6.2;

import "./IApeRouter01.sol";

interface IApeRouter02 is IApeRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

File 17 of 43 : IApeRouter01.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.2;

interface IApeRouter01 {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external pure returns (uint256 amountB);

    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountOut);

    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountIn);

    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);

    function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);
}

File 18 of 43 : BaseOracle.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/IPriceOracle.sol";

contract BaseOracle is Ownable, IPriceOracle {
    event PriceUpdate(address indexed token0, address indexed token1, uint256 price);

    struct PriceData {
        uint192 price;
        uint64 lastUpdate;
    }

    /// @notice Public price data mapping storage.
    mapping(address => mapping(address => PriceData)) public store;

    /// @dev Set the prices of the token token pairs. Must be called by the owner.
    function setPrices(
        address[] calldata token0s,
        address[] calldata token1s,
        uint256[] calldata prices
    ) external onlyOwner {
        uint256 len = token0s.length;
        require(token1s.length == len, "bad token1s length");
        require(prices.length == len, "bad prices length");
        for (uint256 idx = 0; idx < len; idx++) {
            address token0 = token0s[idx];
            address token1 = token1s[idx];
            uint256 price = prices[idx];
            store[token0][token1] = PriceData({price: uint192(price), lastUpdate: uint64(now)});
            emit PriceUpdate(token0, token1, price);
        }
    }

    /// @dev Return the wad price of token0/token1, multiplied by 1e18
    /// NOTE: (if you have 1 token0 how much you can sell it for token1)
    function getPrice(address token0, address token1) external view override returns (uint256 price, uint256 lastUpdate) {
        PriceData memory data = store[token0][token1];
        price = uint256(data.price);
        lastUpdate = uint256(data.lastUpdate);
        require(price != 0 && lastUpdate != 0, "bad price data");
        return (price, lastUpdate);
    }
}

File 19 of 43 : VaultController.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "../libraries/SafeBEP20.sol";
import "../libraries/BEP20.sol";

import "../interfaces/IApeRouter02.sol";
import "../interfaces/IApePair.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/ISpaceMinter.sol";
import "../interfaces/ISpaceChef.sol";
import "../libraries/Pausable.sol";
import "../libraries/Whitelist.sol";

abstract contract VaultController is IVaultController, Pausable, Whitelist {
    using SafeBEP20 for IBEP20;

    BEP20 public SPACE;

    address public keeper;

    IBEP20 internal _stakingToken;
    ISpaceMinter internal _minter;
    ISpaceChef internal _spaceChef;

    event Recovered(address token, uint256 amount);

    modifier onlyKeeper {
        require(msg.sender == keeper || msg.sender == owner(), "VaultController: caller is not the owner or keeper");
        _;
    }

    constructor(IBEP20 token, address _SPACE) public {
        keeper = msg.sender;
        SPACE = BEP20(_SPACE);
        _stakingToken = token;
    }

    function minter() external view override returns (address) {
        return canMint() ? address(_minter) : address(0);
    }

    function canMint() internal view returns (bool) {
        return address(_minter) != address(0) && _minter.isMinter(address(this));
    }

    function spaceChef() external view override returns (address) {
        return address(_spaceChef);
    }

    function stakingToken() external view override returns (address) {
        return address(_stakingToken);
    }

    // Only owner
    function setKeeper(address _keeper) external onlyKeeper {
        require(_keeper != address(0), "VaultController: invalid keeper address");
        keeper = _keeper;
    }

    function setMinter(address newMinter) public virtual onlyOwner {
        // can zero
        _minter = ISpaceMinter(newMinter);
        if (newMinter != address(0)) {
            require(newMinter == SPACE.getOwner(), "VaultController: not space minter");
            _stakingToken.safeApprove(newMinter, 0);
            _stakingToken.safeApprove(newMinter, uint256(~0));
        }
    }

    function setSpaceChef(ISpaceChef newSpaceChef) public virtual onlyOwner {
        require(address(_spaceChef) == address(0), "VaultController: setSpaceChef only once");
        _spaceChef = newSpaceChef;
    }

    // Emergency only
    function recoverToken(address _token, uint256 amount) external virtual onlyOwner {
        require(_token != address(_stakingToken), "VaultController: cannot recover underlying token");
        IBEP20(_token).safeTransfer(owner(), amount);

        emit Recovered(_token, amount);
    }
}

File 20 of 43 : IStrategy.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "../libraries/PoolConstant.sol";
import "./IVaultController.sol";

interface IStrategy is IVaultController {
    function deposit(uint256 _amount) external;

    function depositAll() external;

    function withdraw(uint256 _amount) external; // SPACE STAKING POOL ONLY

    function withdrawAll() external;

    function getReward() external; // SPACE STAKING POOL ONLY

    function harvest() external;

    function totalSupply() external view returns (uint256);

    function balance() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function sharesOf(address account) external view returns (uint256);

    function principalOf(address account) external view returns (uint256);

    function earned(address account) external view returns (uint256);

    function withdrawableBalanceOf(address account) external view returns (uint256); // SPACE STAKING POOL ONLY

    function priceShare() external view returns (uint256);

    /* ========== Strategy Information ========== */

    function pid() external view returns (uint256);

    function poolType() external view returns (PoolConstant.PoolTypes);

    function depositedAt(address account) external view returns (uint256);

    function rewardsToken() external view returns (address);

    event Deposited(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount, uint256 withdrawalFee);
    event ProfitPaid(address indexed user, uint256 profit, uint256 performanceFee);
    event SpacePaid(address indexed user, uint256 profit, uint256 performanceFee);
    event Harvested(uint256 profit);
}

File 21 of 43 : PoolConstant.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

library PoolConstant {
    enum PoolTypes {
        SpaceStake, // no perf fee
        BananaStake,
        FlipToFlip,
        FlipToBanana,
        Space, // no perf fee
        SpaceBNB
    }

    struct PoolInfoBSC {
        address pool;
        uint256 balance;
        uint256 principal;
        uint256 available;
        uint256 tvl;
        uint256 utilized;
        uint256 liquidity;
        uint256 pBASE;
        uint256 pSPACE;
        uint256 depositedAt;
        uint256 feeDuration;
        uint256 feePercentage;
    }
}

File 22 of 43 : IVaultController.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IVaultController {
    function minter() external view returns (address);

    function spaceChef() external view returns (address);

    function stakingToken() external view returns (address);
}

File 23 of 43 : ISpaceChef.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

interface ISpaceChef {
    struct UserInfo {
        uint256 balance;
        uint256 pending;
        uint256 rewardPaid;
    }

    struct VaultInfo {
        address token;
        uint256 allocPoint;
        uint256 lastRewardBlock;
        uint256 accSpacePerShare;
    }

    function spacePerBlock() external view returns (uint256);

    function totalAllocPoint() external view returns (uint256);

    function vaultInfoOf(address vault) external view returns (VaultInfo memory);

    function vaultUserInfoOf(address vault, address user) external view returns (UserInfo memory);

    function pendingSpace(address vault, address user) external view returns (uint256);

    function notifyDeposited(address user, uint256 amount) external;

    function notifyWithdrawn(address user, uint256 amount) external;

    function safeSpaceTransfer(address user) external returns (uint256);
}

File 24 of 43 : Pausable.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/access/Ownable.sol";

abstract contract Pausable is Ownable {
    uint256 public lastPauseTime;
    bool public paused;

    event PauseChanged(bool isPaused);

    modifier notPaused {
        require(!paused, "This action cannot be performed while the contract is paused");
        _;
    }

    constructor() internal {
        require(owner() != address(0), "Owner must be set");
    }

    function setPaused(bool _paused) external onlyOwner {
        if (_paused == paused) {
            return;
        }

        paused = _paused;
        if (paused) {
            lastPauseTime = now;
        }

        emit PauseChanged(paused);
    }
}

File 25 of 43 : Whitelist.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";

contract Whitelist is Ownable {
    mapping(address => bool) private _whitelist;
    bool private _disable = true;

    event Whitelisted(address indexed _address, bool whitelist);
    event EnableWhitelist();
    event DisableWhitelist();

    modifier onlyWhitelisted {
        require(_disable || _whitelist[msg.sender], "Whitelist: caller is not on the whitelist");
        _;
    }

    constructor() public {}

    function isWhitelist(address _address) public view returns (bool) {
        return _whitelist[_address];
    }

    function setWhitelist(address _address, bool _on) external onlyOwner {
        _whitelist[_address] = _on;

        emit Whitelisted(_address, _on);
    }

    function disableWhitelist(bool disable) external onlyOwner {
        _disable = disable;
        if (disable) {
            emit DisableWhitelist();
        } else {
            emit EnableWhitelist();
        }
    }
}

File 26 of 43 : Dashboard.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import "../interfaces/IStrategy.sol";
import "../interfaces/ISpaceMinter.sol";
import "../interfaces/ISpaceChef.sol";

import "./SpacePool.sol";
import "./PriceCalculator.sol";

contract Dashboard is Ownable {
    using SafeMath for uint256;

    PriceCalculator public constant priceCalculator = PriceCalculator(0x5D6086f8aae9DaEBAC5674E8F3b867D5743171D3);

    address public constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
    address public constant SPACE = 0xe486a69E432Fdc29622bF00315f6b34C99b45e80;
    address public constant BANANA = 0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95;
    address public constant VaultBanana = 0xB8FDa49A709E9D00274053D9Ed34CCa1B4BB21f8;

    ISpaceChef private constant spaceChef = ISpaceChef(0x03Eb6A9E2C0e45c0657cf77B6497e8767c92c710);
    SpacePool private constant spacePool = SpacePool(0xd79dc49Ed716832658ec28FE93dd733e0DFB8d58);

    mapping(address => PoolConstant.PoolTypes) public poolTypes;
    mapping(address => uint256) public apeswapPoolIds;
    mapping(address => bool) public perfExemptions;

    function setPoolType(address pool, PoolConstant.PoolTypes poolType) public onlyOwner {
        poolTypes[pool] = poolType;
    }

    function setApeswapPoolId(address pool, uint256 pid) public onlyOwner {
        apeswapPoolIds[pool] = pid;
    }

    function setPerfExemption(address pool, bool exemption) public onlyOwner {
        perfExemptions[pool] = exemption;
    }

    // ---- View Functions
    function poolTypeOf(address pool) public view returns (PoolConstant.PoolTypes) {
        return poolTypes[pool];
    }

    function calculateProfit(address pool, address account) public view returns (uint256 profit, uint256 profitInBNB) {
        PoolConstant.PoolTypes poolType = poolTypes[pool];
        profit = 0;
        profitInBNB = 0;

        if (poolType == PoolConstant.PoolTypes.SpaceStake) {
            // profit as bnb
            address rewardsToken = address(spacePool.SPACE());
            uint256 amount = spacePool.earned(account);
            (profit, ) = priceCalculator.valueOfAsset(rewardsToken, amount);
            profitInBNB = profit;
        } else if (poolType == PoolConstant.PoolTypes.Space) {
            // profit as space
            profit = spaceChef.pendingSpace(pool, account);
            (profitInBNB, ) = priceCalculator.valueOfAsset(SPACE, profit);
        } else if (poolType == PoolConstant.PoolTypes.BananaStake || poolType == PoolConstant.PoolTypes.FlipToFlip) {
            // profit as underlying
            IStrategy strategy = IStrategy(pool);
            profit = strategy.earned(account);
            (profitInBNB, ) = priceCalculator.valueOfAsset(strategy.stakingToken(), profit);
        } else if (poolType == PoolConstant.PoolTypes.FlipToBanana || poolType == PoolConstant.PoolTypes.SpaceBNB) {
            // profit as banana
            IStrategy strategy = IStrategy(pool);
            profit = strategy.earned(account).mul(IStrategy(strategy.rewardsToken()).priceShare()).div(1e18);
            (profitInBNB, ) = priceCalculator.valueOfAsset(BANANA, profit);
        }
    }

    function utilizationOfPool(address pool) public view returns (uint256 liquidity, uint256 utilized) {
        return (0, 0);
    }

    function profitOfPool(address pool, address account) public view returns (uint256 profit, uint256 space) {
        (uint256 profitCalculated, uint256 profitInBNB) = calculateProfit(pool, account);
        profit = profitCalculated;
        space = 0;

        if (!perfExemptions[pool]) {
            IStrategy strategy = IStrategy(pool);
            if (strategy.minter() != address(0)) {
                profit = profit.mul(70).div(100);
                space = ISpaceMinter(strategy.minter()).amountSpaceToMint(profitInBNB.mul(30).div(100));
            }

            if (strategy.spaceChef() != address(0)) {
                space = space.add(spaceChef.pendingSpace(pool, account));
            }
        }
    }

    function tvlOfPool(address pool) public view returns (uint256 tvl) {
        if (poolTypes[pool] == PoolConstant.PoolTypes.SpaceStake) {
            (, tvl) = priceCalculator.valueOfAsset(address(spacePool.SPACE()), spacePool.balance());
        } else {
            IStrategy strategy = IStrategy(pool);
            (, tvl) = priceCalculator.valueOfAsset(strategy.stakingToken(), strategy.balance());

            if (strategy.rewardsToken() == VaultBanana) {
                IStrategy rewardsToken = IStrategy(strategy.rewardsToken());
                uint256 rewardsInBanana = rewardsToken.balanceOf(pool).mul(rewardsToken.priceShare()).div(1e18);
                (, uint256 rewardsInUSD) = priceCalculator.valueOfAsset(address(BANANA), rewardsInBanana);
                tvl = tvl.add(rewardsInUSD);
            }
        }
    }

    function infoOfPool(address pool, address account) public view returns (PoolConstant.PoolInfoBSC memory) {
        PoolConstant.PoolInfoBSC memory poolInfo;

        IStrategy strategy = IStrategy(pool);
        (uint256 pBASE, uint256 pSPACE) = profitOfPool(pool, account);
        (uint256 liquidity, uint256 utilized) = utilizationOfPool(pool);

        poolInfo.pool = pool;
        poolInfo.balance = strategy.balanceOf(account);
        poolInfo.principal = strategy.principalOf(account);
        poolInfo.available = strategy.withdrawableBalanceOf(account);
        poolInfo.tvl = tvlOfPool(pool);
        poolInfo.utilized = utilized;
        poolInfo.liquidity = liquidity;
        poolInfo.pBASE = pBASE;
        poolInfo.pSPACE = pSPACE;

        PoolConstant.PoolTypes poolType = poolTypeOf(pool);
        if (poolType != PoolConstant.PoolTypes.SpaceStake && strategy.minter() != address(0)) {
            ISpaceMinter minter = ISpaceMinter(strategy.minter());
            poolInfo.depositedAt = strategy.depositedAt(account);
            poolInfo.feeDuration = minter.withdrawalFeeFreePeriod();
            poolInfo.feePercentage = minter.withdrawalFeeRate();
        }
        return poolInfo;
    }

    function poolsOf(address account, address[] memory pools) public view returns (PoolConstant.PoolInfoBSC[] memory) {
        PoolConstant.PoolInfoBSC[] memory results = new PoolConstant.PoolInfoBSC[](pools.length);
        for (uint256 i = 0; i < pools.length; i++) {
            results[i] = infoOfPool(pools[i], account);
        }
        return results;
    }

    function stakingTokenValueInUSD(address pool, address account) internal view returns (uint256 tokenInUSD) {
        PoolConstant.PoolTypes poolType = poolTypes[pool];

        address stakingToken;
        if (poolType == PoolConstant.PoolTypes.SpaceStake) {
            stakingToken = SPACE;
        } else {
            stakingToken = IStrategy(pool).stakingToken();
        }

        if (stakingToken == address(0)) return 0;
        (, tokenInUSD) = priceCalculator.valueOfAsset(stakingToken, IStrategy(pool).principalOf(account));
    }

    function portfolioOfPoolInUSD(address pool, address account) internal view returns (uint256) {
        uint256 tokenInUSD = stakingTokenValueInUSD(pool, account);
        (, uint256 profitInBNB) = calculateProfit(pool, account);
        uint256 profitInSPACE = 0;

        if (!perfExemptions[pool]) {
            IStrategy strategy = IStrategy(pool);
            if (strategy.minter() != address(0)) {
                profitInBNB = profitInBNB.mul(70).div(100);
                profitInSPACE = ISpaceMinter(strategy.minter()).amountSpaceToMint(profitInBNB.mul(30).div(100));
            }

            if (
                (poolTypes[pool] == PoolConstant.PoolTypes.Space ||
                    poolTypes[pool] == PoolConstant.PoolTypes.SpaceBNB ||
                    poolTypes[pool] == PoolConstant.PoolTypes.FlipToFlip) && strategy.spaceChef() != address(0)
            ) {
                profitInSPACE = profitInSPACE.add(spaceChef.pendingSpace(pool, account));
            }
        }

        (, uint256 profitBNBInUSD) = priceCalculator.valueOfAsset(WBNB, profitInBNB);
        (, uint256 profitSPACEInUSD) = priceCalculator.valueOfAsset(SPACE, profitInSPACE);
        return tokenInUSD.add(profitBNBInUSD).add(profitSPACEInUSD);
    }

    function portfolioOf(address account, address[] memory pools) public view returns (uint256 deposits) {
        deposits = 0;
        for (uint256 i = 0; i < pools.length; i++) {
            deposits = deposits.add(portfolioOfPoolInUSD(pools[i], account));
        }
    }
}

File 27 of 43 : SpacePool.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

import "../libraries/SafeBEP20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import "../libraries/RewardsDistributionRecipient.sol";
import "../libraries/Pausable.sol";
import "../interfaces/IStrategyHelper.sol";
import "../interfaces/IApeRouter02.sol";
import "../interfaces/ISpacePool.sol";

// @notice Fees Redistribution pool
contract SpacePool is ISpacePool, RewardsDistributionRecipient, ReentrancyGuard, Pausable {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    IApeRouter02 private constant ROUTER = IApeRouter02(0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607);
    // @notice SPACE TOKEN
    IBEP20 public immutable SPACE;
    // @notice SPACE_BNB Treasury -> WBNB Rewards
    IBEP20 public immutable REWARDS_TOKEN;

    // @notice Rewards distributed over 90 days
    uint256 public periodFinish = 0;
    uint256 public rewardRate = 0;
    uint256 public rewardsDuration = 90 days;

    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;
    uint256 private totalDeposited;

    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;

    mapping(address => uint256) private _balances;

    // @notice delegate staking
    mapping(address => bool) private _stakePermission;

    // @notice contract with utils functions
    IStrategyHelper public helper;

    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);
    event RewardsDurationUpdated(uint256 newDuration);
    event Recovered(address token, uint256 amount);

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();
        if (account != address(0)) {
            rewards[account] = earned(account);
            userRewardPerTokenPaid[account] = rewardPerTokenStored;
        }
        _;
    }

    modifier canStakeTo() {
        require(_stakePermission[msg.sender], "auth");
        _;
    }

    constructor(
        address _helper,
        address _STAKING_TOKEN,
        address _REWARDS_TOKEN
    ) public {
        rewardsDistribution = msg.sender;
        _stakePermission[msg.sender] = true;

        REWARDS_TOKEN = IBEP20(_REWARDS_TOKEN);
        SPACE = IBEP20(_STAKING_TOKEN);

        helper = IStrategyHelper(_helper);

        IBEP20(_REWARDS_TOKEN).safeApprove(address(ROUTER), 0);
        IBEP20(_REWARDS_TOKEN).safeApprove(address(ROUTER), uint256(~0));

        IBEP20(_STAKING_TOKEN).safeApprove(address(ROUTER), 0);
        IBEP20(_STAKING_TOKEN).safeApprove(address(ROUTER), uint256(~0));
    }

    function deposit(uint256 amount) public override {
        _deposit(amount, msg.sender);
    }

    function depositAll() external override {
        deposit(SPACE.balanceOf(msg.sender));
    }

    function _deposit(uint256 amount, address to) private nonReentrant notPaused updateReward(to) {
        require(amount > 0, "amount");
        totalDeposited = totalDeposited.add(amount);
        _balances[to] = _balances[to].add(amount);
        SPACE.safeTransferFrom(msg.sender, address(this), amount);
        emit Staked(to, amount);
    }

    function withdraw(uint256 amount) public override nonReentrant updateReward(msg.sender) {
        require(amount > 0, "amount");
        totalDeposited = totalDeposited.sub(amount);
        _balances[msg.sender] = _balances[msg.sender].sub(amount);
        SPACE.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount);
    }

    function withdrawAll() external override {
        uint256 _withdraw = _balances[msg.sender];
        if (_withdraw > 0) {
            withdraw(_withdraw);
        }
        getReward();
    }

    function getReward() public override nonReentrant updateReward(msg.sender) {
        uint256 reward = rewards[msg.sender];
        if (reward > 0) {
            rewards[msg.sender] = 0;
            reward = _flipToWBNB(reward);
            IBEP20(ROUTER.WETH()).safeTransfer(msg.sender, reward);
            emit RewardPaid(msg.sender, reward);
        }
    }

    function _flipToWBNB(uint256 amount) private returns (uint256 reward) {
        address wbnb = ROUTER.WETH();
        (uint256 rewardSpace, ) = ROUTER.removeLiquidity(address(SPACE), wbnb, amount, 0, 0, address(this), block.timestamp);
        address[] memory path = new address[](2);
        path[0] = address(SPACE);
        path[1] = wbnb;
        require(rewardSpace > 0, "SpacePool: _flipToWBNB no reward");
        ROUTER.swapExactTokensForTokens(rewardSpace, 0, path, address(this), block.timestamp);
        reward = IBEP20(wbnb).balanceOf(address(this));
    }

    function setHelper(IStrategyHelper _helper) external onlyOwner {
        require(address(_helper) != address(0), "SpacePool: setHelper zero address");
        helper = _helper;
    }

    function setStakePermission(address _address, bool permission) external onlyOwner {
        _stakePermission[_address] = permission;
    }

    function stakeTo(uint256 amount, address _to) external canStakeTo {
        _deposit(amount, _to);
    }

    function notifyRewardAmount(uint256 reward) external override onlyRewardsDistribution updateReward(address(0)) {
        if (block.timestamp >= periodFinish) {
            rewardRate = reward.div(rewardsDuration);
        } else {
            uint256 remaining = periodFinish.sub(block.timestamp);
            uint256 leftover = remaining.mul(rewardRate);
            rewardRate = reward.add(leftover).div(rewardsDuration);
        }

        uint256 _balance = REWARDS_TOKEN.balanceOf(address(this));
        require(rewardRate <= _balance.div(rewardsDuration), "reward");

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp.add(rewardsDuration);
        emit RewardAdded(reward);
    }

    function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
        require(periodFinish == 0 || block.timestamp > periodFinish, "period");
        rewardsDuration = _rewardsDuration;
        emit RewardsDurationUpdated(rewardsDuration);
    }

    function info(address account) external view override returns (UserInfo memory) {
        UserInfo memory userInfo;

        userInfo.balance = _balances[account];
        userInfo.principal = _balances[account];
        userInfo.available = _balances[account];

        Profit memory profit;
        (uint256 usd, uint256 space, uint256 bnb) = profitOf(account);
        profit.usd = usd;
        profit.space = space;
        profit.bnb = bnb;
        userInfo.profit = profit;

        userInfo.poolTVL = tvl();

        APY memory poolAPY;
        (usd, space, bnb) = apy();
        poolAPY.usd = usd;
        poolAPY.space = space;
        poolAPY.bnb = bnb;
        userInfo.poolAPY = poolAPY;

        return userInfo;
    }

    function profitOf(address account)
        public
        view
        override
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        )
    {
        _usd = 0;
        _space = 0;
        _bnb = helper.tvlInBNB(address(REWARDS_TOKEN), earned(account));
    }

    function apy()
        public
        view
        override
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        )
    {
        uint256 tokenDecimals = 1e18;
        uint256 __totalSupply = totalDeposited;
        if (__totalSupply == 0) {
            __totalSupply = tokenDecimals;
        }

        uint256 rewardPerTokenPerSecond = rewardRate.mul(tokenDecimals).div(__totalSupply);

        uint256 spacePrice = helper.tokenPriceInBNB(address(SPACE));
        uint256 lpPrice = helper.tvlInBNB(address(REWARDS_TOKEN), 1e18);

        _usd = 0;
        _space = 0;
        _bnb = 0;
        if (lpPrice > 0 && spacePrice > 0) {
            _bnb = rewardPerTokenPerSecond.mul(365 days).mul(lpPrice).div(spacePrice);
        }
    }

    function rewardPerToken() public view returns (uint256) {
        if (totalDeposited == 0) {
            return rewardPerTokenStored;
        }
        return rewardPerTokenStored.add(lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(totalDeposited));
    }

    function lastTimeRewardApplicable() public view returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }

    function tvl() public view override returns (uint256) {
        uint256 price = helper.tokenPriceInBNB(address(SPACE));
        return price > 0 ? totalDeposited.mul(price).div(1e18) : 0;
    }

    function earned(address account) public view returns (uint256) {
        return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
    }

    function getRewardForDuration() external view returns (uint256) {
        return rewardRate.mul(rewardsDuration);
    }

    function totalSupply() external view returns (uint256) {
        return totalDeposited;
    }

    function balance() external view override returns (uint256) {
        return totalDeposited;
    }

    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function principalOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    // @notice Emergency only
    function recoverBEP20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
        require(tokenAddress != address(SPACE) && tokenAddress != address(REWARDS_TOKEN), "tokenAddress");
        IBEP20(tokenAddress).safeTransfer(owner(), tokenAmount);
        emit Recovered(tokenAddress, tokenAmount);
    }
}

File 28 of 43 : RewardsDistributionRecipient.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.2;

import "@openzeppelin/contracts/access/Ownable.sol";

abstract contract RewardsDistributionRecipient is Ownable {
    address public rewardsDistribution;

    modifier onlyRewardsDistribution() {
        require(msg.sender == rewardsDistribution, "onlyRewardsDistribution");
        _;
    }

    function notifyRewardAmount(uint256 reward) external virtual;

    function setRewardsDistribution(address _rewardsDistribution) external onlyOwner {
        rewardsDistribution = _rewardsDistribution;
    }
}

File 29 of 43 : IStrategyHelper.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

import "./ISpaceMinter.sol";

interface IStrategyHelper {
    function tokenPriceInBNB(address _token) external view returns (uint256);

    function bananaPriceInBNB() external view returns (uint256);

    function bnbPriceInUSD() external view returns (uint256);

    function profitOf(
        ISpaceMinter minter,
        address _flip,
        uint256 amount
    )
        external
        view
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        );

    function tvl(address _flip, uint256 amount) external view returns (uint256); // in USD

    function tvlInBNB(address _flip, uint256 amount) external view returns (uint256); // in BNB

    function apy(ISpaceMinter minter, uint256 pid)
        external
        view
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        );

    function compoundingAPY(uint256 pid, uint256 compoundUnit) external view returns (uint256);
}

File 30 of 43 : ISpacePool.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

struct Profit {
    uint256 usd;
    uint256 space;
    uint256 bnb;
}

struct APY {
    uint256 usd;
    uint256 space;
    uint256 bnb;
}

struct UserInfo {
    uint256 balance;
    uint256 principal;
    uint256 available;
    Profit profit;
    uint256 poolTVL;
    APY poolAPY;
}

interface ISpacePool {
    function deposit(uint256 _amount) external;

    function depositAll() external;

    function withdraw(uint256 _amount) external;

    function withdrawAll() external;

    function getReward() external;

    function balance() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function principalOf(address account) external view returns (uint256);

    function profitOf(address account)
        external
        view
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        );

    //    function earned(address account) external view returns (uint);
    function tvl() external view returns (uint256); // in USD

    function apy()
        external
        view
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        );

    /* ========== Strategy Information ========== */
    //    function pid() external view returns (uint);
    //    function poolType() external view returns (PoolTypes);
    //    function isMinter() external view returns (bool, address);
    //    function getDepositedAt(address account) external view returns (uint);
    //    function getRewardsToken() external view returns (address);

    function info(address account) external view returns (UserInfo memory);
}

File 31 of 43 : VaultBanana.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/Math.sol";

import "../libraries/SafeBEP20.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/IMasterApe.sol";
import "./VaultController.sol";
import {PoolConstant} from "../libraries/PoolConstant.sol";

contract VaultBanana is VaultController, IStrategy {
    using SafeBEP20 for IBEP20;
    using SafeMath for uint256;

    IBEP20 private constant BANANA = IBEP20(0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95);
    IMasterApe private constant BANANA_MASTER_CHEF = IMasterApe(0x5c8D727b265DBAfaba67E050f2f739cAeEB4A6F9);

    uint256 public constant override pid = 0;
    PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.BananaStake;

    uint256 private constant DUST = 1000;

    uint256 public totalShares;
    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _principal;
    mapping(address => uint256) private _depositedAt;

    constructor(address minter, address spaceToken) public VaultController(BANANA, spaceToken) {
        BANANA.safeApprove(address(BANANA_MASTER_CHEF), 0);
        BANANA.safeApprove(address(BANANA_MASTER_CHEF), uint256(~0));
        setMinter(minter);
    }

    function totalSupply() external view override returns (uint256) {
        return totalShares;
    }

    function balance() public view override returns (uint256) {
        (uint256 amount, ) = BANANA_MASTER_CHEF.userInfo(pid, address(this));
        return BANANA.balanceOf(address(this)).add(amount);
    }

    function balanceOf(address account) public view override returns (uint256) {
        if (totalShares == 0) return 0;
        return balance().mul(sharesOf(account)).div(totalShares);
    }

    function withdrawableBalanceOf(address account) public view override returns (uint256) {
        return balanceOf(account);
    }

    function sharesOf(address account) public view override returns (uint256) {
        return _shares[account];
    }

    function principalOf(address account) public view override returns (uint256) {
        return _principal[account];
    }

    function earned(address account) public view override returns (uint256) {
        if (balanceOf(account) >= principalOf(account) + DUST) {
            return balanceOf(account).sub(principalOf(account));
        } else {
            return 0;
        }
    }

    function priceShare() external view override returns (uint256) {
        if (totalShares == 0) return 1e18;
        return balance().mul(1e18).div(totalShares);
    }

    function depositedAt(address account) external view override returns (uint256) {
        return _depositedAt[account];
    }

    function rewardsToken() external view override returns (address) {
        return address(_stakingToken);
    }

    function deposit(uint256 _amount) public override {
        _deposit(_amount, msg.sender);

        if (isWhitelist(msg.sender) == false) {
            _principal[msg.sender] = _principal[msg.sender].add(_amount);
            _depositedAt[msg.sender] = block.timestamp;
        }
    }

    function depositAll() external override {
        deposit(BANANA.balanceOf(msg.sender));
    }

    function withdrawAll() external override {
        uint256 amount = balanceOf(msg.sender);
        uint256 principal = principalOf(msg.sender);
        uint256 depositTimestamp = _depositedAt[msg.sender];

        totalShares = totalShares.sub(_shares[msg.sender]);
        delete _shares[msg.sender];
        delete _principal[msg.sender];
        delete _depositedAt[msg.sender];

        _withdrawTokenWithCorrection(amount);

        uint256 profit = amount > principal ? amount.sub(principal) : 0;
        uint256 withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0;
        uint256 performanceFee = canMint() ? _minter.performanceFee(profit) : 0;

        if (withdrawalFee.add(performanceFee) > DUST) {
            _minter.mintFor(address(BANANA), withdrawalFee, performanceFee, msg.sender, depositTimestamp);
            if (performanceFee > 0) {
                emit ProfitPaid(msg.sender, profit, performanceFee);
            }
            amount = amount.sub(withdrawalFee).sub(performanceFee);
        }

        BANANA.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, withdrawalFee);

        _harvest();
    }

    function harvest() external override {
        BANANA_MASTER_CHEF.leaveStaking(0);
        _harvest();
    }

    function withdraw(uint256 shares) external override onlyWhitelisted {
        uint256 amount = balance().mul(shares).div(totalShares);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);

        _withdrawTokenWithCorrection(amount);
        BANANA.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, 0);

        _harvest();
    }

    // @dev underlying only + withdrawal fee + no perf fee
    function withdrawUnderlying(uint256 _amount) external {
        uint256 amount = Math.min(_amount, _principal[msg.sender]);
        uint256 shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);
        _principal[msg.sender] = _principal[msg.sender].sub(amount);

        _withdrawTokenWithCorrection(amount);
        uint256 depositTimestamp = _depositedAt[msg.sender];
        uint256 withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0;
        if (withdrawalFee > DUST) {
            _minter.mintFor(address(BANANA), withdrawalFee, 0, msg.sender, depositTimestamp);
            amount = amount.sub(withdrawalFee);
        }

        BANANA.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, withdrawalFee);

        _harvest();
    }

    function getReward() external override {
        uint256 amount = earned(msg.sender);
        uint256 shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);
        _cleanupIfDustShares();

        _withdrawTokenWithCorrection(amount);
        uint256 depositTimestamp = _depositedAt[msg.sender];
        uint256 performanceFee = canMint() ? _minter.performanceFee(amount) : 0;
        if (performanceFee > DUST) {
            _minter.mintFor(address(BANANA), 0, performanceFee, msg.sender, depositTimestamp);
            amount = amount.sub(performanceFee);
        }

        BANANA.safeTransfer(msg.sender, amount);
        emit ProfitPaid(msg.sender, amount, performanceFee);

        _harvest();
    }

    // Private functions
    function _harvest() private {
        uint256 bananaAmount = BANANA.balanceOf(address(this));
        if (bananaAmount > 0) {
            emit Harvested(bananaAmount);
            BANANA_MASTER_CHEF.enterStaking(bananaAmount);
        }
    }

    function _deposit(uint256 _amount, address _to) private notPaused {
        uint256 _pool = balance();
        BANANA.safeTransferFrom(msg.sender, address(this), _amount);
        uint256 shares = 0;
        if (totalShares == 0) {
            shares = _amount;
        } else {
            shares = (_amount.mul(totalShares)).div(_pool);
        }

        totalShares = totalShares.add(shares);
        _shares[_to] = _shares[_to].add(shares);

        BANANA_MASTER_CHEF.enterStaking(_amount);
        emit Deposited(msg.sender, _amount);

        _harvest();
    }

    function _withdrawTokenWithCorrection(uint256 amount) private {
        uint256 bananaBalance = BANANA.balanceOf(address(this));
        if (bananaBalance < amount) {
            BANANA_MASTER_CHEF.leaveStaking(amount.sub(bananaBalance));
        }
    }

    function _cleanupIfDustShares() private {
        uint256 shares = _shares[msg.sender];
        if (shares > 0 && shares < DUST) {
            totalShares = totalShares.sub(shares);
            delete _shares[msg.sender];
        }
    }
}

File 32 of 43 : IMasterApe.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;

interface IMasterApe {
    function cakePerBlock() external view returns (uint256);

    function totalAllocPoint() external view returns (uint256);

    function poolInfo(uint256 _pid)
        external
        view
        returns (
            address lpToken,
            uint256 allocPoint,
            uint256 lastRewardBlock,
            uint256 accCakePerShare
        );

    function userInfo(uint256 _pid, address _account) external view returns (uint256 amount, uint256 rewardDebt);

    function poolLength() external view returns (uint256);

    function deposit(uint256 _pid, uint256 _amount) external;

    function withdraw(uint256 _pid, uint256 _amount) external;

    function emergencyWithdraw(uint256 _pid) external;

    function enterStaking(uint256 _amount) external;

    function leaveStaking(uint256 _amount) external;
}

File 33 of 43 : VaultFlipToBanana.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import "../libraries/RewardsDistributionRecipient.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/IMasterApe.sol";
import "../interfaces/ISpaceMinter.sol";
import "./VaultController.sol";

import {PoolConstant} from "../libraries/PoolConstant.sol";

contract VaultFlipToBanana is VaultController, IStrategy, RewardsDistributionRecipient, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    address private constant BANANA = 0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95;
    IMasterApe private constant APE_MASTER_CHEF = IMasterApe(0x5c8D727b265DBAfaba67E050f2f739cAeEB4A6F9);
    PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToBanana;

    IStrategy private _rewardsToken;

    uint256 public periodFinish;
    uint256 public rewardRate;
    uint256 public rewardsDuration;
    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;

    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;

    uint256 private _totalSupply;
    mapping(address => uint256) private _balances;

    uint256 public override pid;
    mapping(address => uint256) private _depositedAt;

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();
        if (account != address(0)) {
            rewards[account] = earned(account);
            userRewardPerTokenPaid[account] = rewardPerTokenStored;
        }
        _;
    }

    event RewardAdded(uint256 reward);
    event RewardsDurationUpdated(uint256 newDuration);

    constructor(
        uint256 _pid,
        IBEP20 token,
        address _minter,
        address _vaultBanana,
        address _spaceToken
    ) public VaultController(token, _spaceToken) {
        _stakingToken.safeApprove(address(APE_MASTER_CHEF), uint256(~0));
        pid = _pid;

        rewardsDuration = 24 hours;

        rewardsDistribution = msg.sender;
        setMinter(_minter);
        setRewardsToken(_vaultBanana);
    }

    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }

    function balance() external view override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function sharesOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function principalOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function depositedAt(address account) external view override returns (uint256) {
        return _depositedAt[account];
    }

    function withdrawableBalanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    function rewardsToken() external view override returns (address) {
        return address(_rewardsToken);
    }

    function priceShare() external view override returns (uint256) {
        return 1e18;
    }

    function lastTimeRewardApplicable() public view returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }

    function rewardPerToken() public view returns (uint256) {
        if (_totalSupply == 0) {
            return rewardPerTokenStored;
        }
        return rewardPerTokenStored.add(lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply));
    }

    function earned(address account) public view override returns (uint256) {
        return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
    }

    function getRewardForDuration() external view returns (uint256) {
        return rewardRate.mul(rewardsDuration);
    }

    function _deposit(uint256 amount, address _to) private nonReentrant notPaused updateReward(_to) {
        require(amount > 0, "VaultFlipToBanana: amount must be greater than zero");
        _totalSupply = _totalSupply.add(amount);
        _balances[_to] = _balances[_to].add(amount);
        _depositedAt[_to] = block.timestamp;
        _stakingToken.safeTransferFrom(msg.sender, address(this), amount);
        APE_MASTER_CHEF.deposit(pid, amount);
        emit Deposited(_to, amount);

        _harvest();
    }

    function deposit(uint256 amount) public override {
        _deposit(amount, msg.sender);
    }

    function depositAll() external override {
        deposit(_stakingToken.balanceOf(msg.sender));
    }

    function withdraw(uint256 amount) public override nonReentrant updateReward(msg.sender) {
        require(amount > 0, "VaultFlipToBanana: amount must be greater than zero");
        _totalSupply = _totalSupply.sub(amount);
        _balances[msg.sender] = _balances[msg.sender].sub(amount);
        APE_MASTER_CHEF.withdraw(pid, amount);
        uint256 withdrawalFee;
        if (canMint()) {
            uint256 depositTimestamp = _depositedAt[msg.sender];
            withdrawalFee = _minter.withdrawalFee(amount, depositTimestamp);
            if (withdrawalFee > 0) {
                uint256 performanceFee = withdrawalFee.div(100);
                _minter.mintFor(address(_stakingToken), withdrawalFee.sub(performanceFee), performanceFee, msg.sender, depositTimestamp);
                amount = amount.sub(withdrawalFee);
            }
        }

        _stakingToken.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, withdrawalFee);

        _harvest();
    }

    function withdrawAll() external override {
        uint256 _withdraw = withdrawableBalanceOf(msg.sender);
        if (_withdraw > 0) {
            withdraw(_withdraw);
        }
        getReward();
    }

    function getReward() public override nonReentrant updateReward(msg.sender) {
        uint256 reward = rewards[msg.sender];
        if (reward > 0) {
            rewards[msg.sender] = 0;
            uint256 before = IBEP20(BANANA).balanceOf(address(this));
            _rewardsToken.withdraw(reward);
            uint256 bananaBalance = IBEP20(BANANA).balanceOf(address(this)).sub(before);
            uint256 performanceFee;

            if (canMint()) {
                performanceFee = _minter.performanceFee(bananaBalance);
                _minter.mintFor(BANANA, 0, performanceFee, msg.sender, _depositedAt[msg.sender]);
            }

            IBEP20(BANANA).safeTransfer(msg.sender, bananaBalance.sub(performanceFee));
            emit ProfitPaid(msg.sender, bananaBalance, performanceFee);
        }
    }

    function harvest() public override {
        APE_MASTER_CHEF.withdraw(pid, 0);
        _harvest();
    }

    function _harvest() private {
        uint256 bananaAmount = IBEP20(BANANA).balanceOf(address(this));
        uint256 _before = _rewardsToken.sharesOf(address(this));
        _rewardsToken.deposit(bananaAmount);
        uint256 amount = _rewardsToken.sharesOf(address(this)).sub(_before);
        if (amount > 0) {
            _notifyRewardAmount(amount);
            emit Harvested(amount);
        }
    }

    function setMinter(address newMinter) public override onlyOwner {
        VaultController.setMinter(newMinter);
        if (newMinter != address(0)) {
            IBEP20(BANANA).safeApprove(newMinter, 0);
            IBEP20(BANANA).safeApprove(newMinter, uint256(~0));
        }
    }

    function setRewardsToken(address newRewardsToken) public onlyOwner {
        require(address(_rewardsToken) == address(0), "VaultFlipToBanana: rewards token already set");

        _rewardsToken = IStrategy(newRewardsToken);
        IBEP20(BANANA).safeApprove(newRewardsToken, 0);
        IBEP20(BANANA).safeApprove(newRewardsToken, uint256(~0));
    }

    function notifyRewardAmount(uint256 reward) public override onlyRewardsDistribution {
        _notifyRewardAmount(reward);
    }

    function _notifyRewardAmount(uint256 reward) private updateReward(address(0)) {
        if (block.timestamp >= periodFinish) {
            rewardRate = reward.div(rewardsDuration);
        } else {
            uint256 remaining = periodFinish.sub(block.timestamp);
            uint256 leftover = remaining.mul(rewardRate);
            rewardRate = reward.add(leftover).div(rewardsDuration);
        }

        uint256 _balance = _rewardsToken.sharesOf(address(this));
        require(rewardRate <= _balance.div(rewardsDuration), "VaultFlipToBanana: reward rate must be in the right range");

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp.add(rewardsDuration);
        emit RewardAdded(reward);
    }

    function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
        require(
            periodFinish == 0 || block.timestamp > periodFinish,
            "VaultFlipToBanana: reward duration can only be updated after the period ends"
        );
        rewardsDuration = _rewardsDuration;
        emit RewardsDurationUpdated(rewardsDuration);
    }

    function recoverToken(address tokenAddress, uint256 tokenAmount) external override onlyOwner {
        require(
            tokenAddress != address(_stakingToken) && tokenAddress != _rewardsToken.stakingToken(),
            "VaultFlipToBanana: cannot recover underlying token"
        );
        IBEP20(tokenAddress).safeTransfer(owner(), tokenAmount);
        emit Recovered(tokenAddress, tokenAmount);
    }
}

File 34 of 43 : StrategyHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;

import "../interfaces/IBEP20.sol";
import "../libraries/BEP20.sol";

import "@openzeppelin/contracts/math/SafeMath.sol";

import "../interfaces/IApeFactory.sol";
import "../interfaces/IApePair.sol";
import "../interfaces/IMasterApe.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/IStrategyHelper.sol";

contract StrategyHelper is IStrategyHelper {
    using SafeMath for uint256;
    address private constant BANANA_BNB_LP = 0xF65C1C0478eFDe3c19b49EcBE7ACc57BB6B1D713;
    address private constant BNB_BUSD_POOL = 0x51e6D27FA57373d8d4C256231241053a70Cb1d93;

    IBEP20 private constant WBNB = IBEP20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
    IBEP20 private constant BANANA = IBEP20(0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95);
    IBEP20 private constant BUSD = IBEP20(0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56);

    IMasterApe private constant APE_MASTER_CHEF = IMasterApe(0x5c8D727b265DBAfaba67E050f2f739cAeEB4A6F9);
    IApeFactory private constant factory = IApeFactory(0x0841BD0B734E4F5853f0dD8d7Ea041c241fb0Da6);

    function tokenPriceInBNB(address _token) public view override returns (uint256) {
        address pair = factory.getPair(_token, address(WBNB));
        uint256 decimal = uint256(BEP20(_token).decimals());
        return WBNB.balanceOf(pair).mul(10**decimal).div(IBEP20(_token).balanceOf(pair));
    }

    function bananaPriceInBNB() public view override returns (uint256) {
        return WBNB.balanceOf(BANANA_BNB_LP).mul(1e18).div(BANANA.balanceOf(BANANA_BNB_LP));
    }

    function bnbPriceInUSD() public view override returns (uint256) {
        return BUSD.balanceOf(BNB_BUSD_POOL).mul(1e18).div(WBNB.balanceOf(BNB_BUSD_POOL));
    }

    function bananaPerYearOfPool(uint256 pid) public view returns (uint256) {
        (, uint256 allocPoint, , ) = APE_MASTER_CHEF.poolInfo(pid);
        return APE_MASTER_CHEF.cakePerBlock().mul(blockPerYear()).mul(allocPoint).div(APE_MASTER_CHEF.totalAllocPoint());
    }

    function blockPerYear() public pure returns (uint256) {
        return 10512000;
    }

    function profitOf(
        ISpaceMinter minter,
        address flip,
        uint256 amount
    )
        external
        view
        override
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        )
    {
        _usd = tvl(flip, amount);
        if (address(minter) == address(0)) {
            _space = 0;
        } else {
            uint256 performanceFee = minter.performanceFee(_usd);
            _usd = _usd.sub(performanceFee);
            uint256 bnbAmount = performanceFee.mul(1e18).div(bnbPriceInUSD());
            _space = minter.amountSpaceToMint(bnbAmount);
        }
        _bnb = 0;
    }

    function _apy(uint256 pid) private view returns (uint256) {
        (address token, , , ) = APE_MASTER_CHEF.poolInfo(pid);
        uint256 poolSize = tvl(token, IBEP20(token).balanceOf(address(APE_MASTER_CHEF))).mul(1e18).div(bnbPriceInUSD());
        return bananaPriceInBNB().mul(bananaPerYearOfPool(pid)).div(poolSize);
    }

    function apy(ISpaceMinter, uint256 pid)
        public
        view
        override
        returns (
            uint256 _usd,
            uint256 _space,
            uint256 _bnb
        )
    {
        _usd = compoundingAPY(pid, 1 days);
        _space = 0;
        _bnb = 0;
    }

    function tvl(address _flip, uint256 amount) public view override returns (uint256) {
        return tvlInBNB(_flip, amount).mul(bnbPriceInUSD()).div(1e18);
    }

    function tvlInBNB(address _flip, uint256 amount) public view override returns (uint256) {
        if (_flip == address(BANANA)) {
            return bananaPriceInBNB().mul(amount).div(1e18);
        }
        address _token0 = IApePair(_flip).token0();
        address _token1 = IApePair(_flip).token1();
        if (_token0 == address(WBNB) || _token1 == address(WBNB)) {
            uint256 bnb = WBNB.balanceOf(address(_flip)).mul(amount).div(IBEP20(_flip).totalSupply());
            return bnb.mul(2);
        }

        uint256 balanceToken0 = IBEP20(_token0).balanceOf(_flip);
        uint256 price = tokenPriceInBNB(_token0);
        return balanceToken0.mul(price).mul(2).div(1e18);
    }

    function compoundingAPY(uint256 pid, uint256 compoundUnit) public view override returns (uint256) {
        uint256 __apy = _apy(pid);
        uint256 compoundTimes = 365 days / compoundUnit;
        uint256 unitAPY = 1e18 + (__apy.div(compoundTimes));
        uint256 result = 1e18;

        for (uint256 i = 0; i < compoundTimes; i++) {
            result = (result.mul(unitAPY)).div(1e18);
        }

        return result.sub(1e18);
    }
}

File 35 of 43 : SpaceChef.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import "../libraries/SafeBEP20.sol";

import "../interfaces/IBEP20.sol";
import "../interfaces/ISpaceMinter.sol";
import "../interfaces/ISpaceChef.sol";
import "../interfaces/IStrategy.sol";
import "./SpaceToken.sol";

contract SpaceChef is ISpaceChef, Ownable {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    SpaceToken public immutable SPACE;
    // @notice Can't be modified
    ISpaceMinter public MINTER;

    address[] private _vaultList;

    mapping(address => VaultInfo) vaults;
    mapping(address => mapping(address => UserInfo)) vaultUsers;

    uint256 public startBlock;
    uint256 public override spacePerBlock;
    uint256 public override totalAllocPoint;

    event NotifyDeposited(address indexed user, address indexed vault, uint256 amount);
    event NotifyWithdrawn(address indexed user, address indexed vault, uint256 amount);
    event SpaceRewardPaid(address indexed user, address indexed vault, uint256 amount);
    event LogVaultAddition(address indexed vault, uint256 allocPoint, address indexed token);
    event LogVaultUpdated(address indexed vault, uint256 allocPoint);

    modifier onlyVaults {
        require(vaults[msg.sender].token != address(0), "SpaceChef: caller is not on the vault");
        _;
    }

    modifier updateRewards(address vault) {
        VaultInfo storage vaultInfo = vaults[vault];
        if (block.number > vaultInfo.lastRewardBlock) {
            uint256 tokenSupply = tokenSupplyOf(vault);
            if (tokenSupply > 0) {
                uint256 multiplier = timeMultiplier(vaultInfo.lastRewardBlock, block.number);
                uint256 rewards = multiplier.mul(spacePerBlock).mul(vaultInfo.allocPoint).div(totalAllocPoint);
                vaultInfo.accSpacePerShare = vaultInfo.accSpacePerShare.add(rewards.mul(1e12).div(tokenSupply));
            }
            vaultInfo.lastRewardBlock = block.number;
        }
        _;
    }

    constructor(
        uint256 _startBlock,
        uint256 _spacePerBlock,
        address _SPACE
    ) public {
        SPACE = SpaceToken(_SPACE);

        startBlock = _startBlock;
        spacePerBlock = _spacePerBlock;
    }

    function timeMultiplier(uint256 from, uint256 to) public pure returns (uint256) {
        return to.sub(from);
    }

    function tokenSupplyOf(address vault) public view returns (uint256) {
        return IStrategy(vault).totalSupply();
    }

    function vaultInfoOf(address vault) external view override returns (VaultInfo memory) {
        return vaults[vault];
    }

    function vaultUserInfoOf(address vault, address user) external view override returns (UserInfo memory) {
        return vaultUsers[vault][user];
    }

    function pendingSpace(address vault, address user) public view override returns (uint256) {
        UserInfo storage userInfo = vaultUsers[vault][user];
        VaultInfo storage vaultInfo = vaults[vault];

        uint256 accSpacePerShare = vaultInfo.accSpacePerShare;
        uint256 tokenSupply = tokenSupplyOf(vault);
        if (block.number > vaultInfo.lastRewardBlock && tokenSupply > 0) {
            uint256 multiplier = timeMultiplier(vaultInfo.lastRewardBlock, block.number);
            uint256 spaceRewards = multiplier.mul(spacePerBlock).mul(vaultInfo.allocPoint).div(totalAllocPoint);
            accSpacePerShare = accSpacePerShare.add(spaceRewards.mul(1e12).div(tokenSupply));
        }
        return userInfo.pending.add(userInfo.balance.mul(accSpacePerShare).div(1e12).sub(userInfo.rewardPaid));
    }

    // Only Owner
    function addVault(
        address vault,
        address token,
        uint256 allocPoint,
        bool update
    ) public onlyOwner {
        require(address(token) != address(0), "SpaceChef: wrong token address");
        require(vaults[vault].token == address(0), "SpaceChef: vault is already set");
        if (update) {
            massUpdateVaultsRewards();
        }

        uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
        totalAllocPoint = totalAllocPoint.add(allocPoint);
        vaults[vault] = VaultInfo(token, allocPoint, lastRewardBlock, 0);
        _vaultList.push(vault);

        emit LogVaultAddition(vault, allocPoint, token);
    }

    function updateVault(
        address vault,
        uint256 allocPoint,
        bool update
    ) public onlyOwner {
        require(vaults[vault].token != address(0), "SpaceChef: vault must be set");
        if (update) {
            massUpdateVaultsRewards();
        }

        uint256 lastAllocPoint = vaults[vault].allocPoint;
        if (lastAllocPoint != allocPoint) {
            totalAllocPoint = totalAllocPoint.sub(lastAllocPoint).add(allocPoint);
        }
        vaults[vault].allocPoint = allocPoint;
        emit LogVaultUpdated(vault, allocPoint);
    }

    function updateEmissionPerBlock(uint256 _spacePerBlock, bool update) external onlyOwner {
        massUpdateVaultsRewards();
        spacePerBlock = _spacePerBlock;
    }

    function initializeMinter(address minter) external onlyOwner {
        require(address(MINTER) == address(0), "SpaceChef: MINTER already set");
        MINTER = ISpaceMinter(minter);
    }

    function notifyDeposited(address user, uint256 amount) external override onlyVaults updateRewards(msg.sender) {
        UserInfo storage userInfo = vaultUsers[msg.sender][user];
        VaultInfo storage vaultInfo = vaults[msg.sender];

        uint256 pending = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12).sub(userInfo.rewardPaid);
        userInfo.pending = userInfo.pending.add(pending);
        userInfo.balance = userInfo.balance.add(amount);
        userInfo.rewardPaid = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12);
        emit NotifyDeposited(user, msg.sender, amount);
    }

    function notifyWithdrawn(address user, uint256 amount) external override onlyVaults updateRewards(msg.sender) {
        UserInfo storage userInfo = vaultUsers[msg.sender][user];
        VaultInfo storage vaultInfo = vaults[msg.sender];

        uint256 pending = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12).sub(userInfo.rewardPaid);
        userInfo.pending = userInfo.pending.add(pending);
        userInfo.balance = userInfo.balance.sub(amount);
        userInfo.rewardPaid = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12);
        emit NotifyWithdrawn(user, msg.sender, amount);
    }

    function safeSpaceTransfer(address user) external override onlyVaults updateRewards(msg.sender) returns (uint256) {
        UserInfo storage userInfo = vaultUsers[msg.sender][user];
        VaultInfo storage vaultInfo = vaults[msg.sender];

        uint256 pending = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12).sub(userInfo.rewardPaid);
        uint256 amount = userInfo.pending.add(pending);
        userInfo.pending = 0;
        userInfo.rewardPaid = userInfo.balance.mul(vaultInfo.accSpacePerShare).div(1e12);

        MINTER.mint(user, amount);
        // MINTER.safeSpaceTransfer(user, amount);
        emit SpaceRewardPaid(user, msg.sender, amount);
        return amount;
    }

    function massUpdateVaultsRewards() public {
        for (uint256 idx = 0; idx < _vaultList.length; idx++) {
            if (_vaultList[idx] != address(0) && vaults[_vaultList[idx]].token != address(0)) {
                updateRewardsOf(_vaultList[idx]);
            }
        }
    }

    function updateRewardsOf(address vault) public updateRewards(vault) {}

    // Emergency only
    function recoverToken(address _token, uint256 amount) external virtual onlyOwner {
        require(_token != address(SPACE), "SpaceChef: cannot recover SPACE token");
        IBEP20(_token).safeTransfer(owner(), amount);
    }
}

File 36 of 43 : VaultFlipToFlip.sol
// SPDX-License-Identifier: MIT
// Version @2021-05
// Source: Pancake Bunny
/*
 █████╗ ██████╗ ███████╗██████╗  ██████╗  ██████╗██╗  ██╗███████╗████████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
███████║██████╔╝█████╗  ██████╔╝██║   ██║██║     █████╔╝ █████╗     ██║   
██╔══██║██╔═══╝ ██╔══╝  ██╔══██╗██║   ██║██║     ██╔═██╗ ██╔══╝     ██║   
██║  ██║██║     ███████╗██║  ██║╚██████╔╝╚██████╗██║  ██╗███████╗   ██║   
╚═╝  ╚═╝╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝   ╚═╝  
 */
pragma solidity >=0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

import {PoolConstant} from "../libraries/PoolConstant.sol";
import "../interfaces/IApeRouter02.sol";
import "../interfaces/IApePair.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/IMasterApe.sol";
import "../interfaces/ISpaceMinter.sol";
import "./Zap.sol";

import "./VaultController.sol";

contract VaultFlipToFlip is VaultController, IStrategy {
    using SafeBEP20 for IBEP20;
    using SafeMath for uint256;

    IApeRouter02 private constant ROUTER = IApeRouter02(0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607);
    IBEP20 private constant BANANA = IBEP20(0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95);
    IBEP20 private constant WBNB = IBEP20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
    IMasterApe private constant APE_MASTER_CHEF = IMasterApe(0x5c8D727b265DBAfaba67E050f2f739cAeEB4A6F9);

    PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToFlip;

    Zap public zap;
    uint256 private constant DUST = 1000;

    uint256 public override pid;

    address private _token0;
    address private _token1;

    uint256 public totalShares;
    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _principal;
    mapping(address => uint256) private _depositedAt;

    uint256 public bananaHarvested;

    modifier updateBananaHarvested {
        uint256 before = BANANA.balanceOf(address(this));
        _;
        uint256 _after = BANANA.balanceOf(address(this));
        bananaHarvested = bananaHarvested.add(_after).sub(before);
    }

    constructor(
        uint256 _pid,
        IBEP20 _token,
        address payable _zap,
        address _spaceToken
    ) public VaultController(_token, _spaceToken) {
        require(_pid != 0, "VaultFlipToFlip: pid must not be zero");
        setFlipToken(address(_token));
        pid = _pid;
        zap = Zap(_zap);

        BANANA.approve(address(ROUTER), uint256(~0));
        BANANA.approve(_zap, uint256(~0));
    }

    function totalSupply() external view override returns (uint256) {
        return totalShares;
    }

    function balance() public view override returns (uint256 amount) {
        (amount, ) = APE_MASTER_CHEF.userInfo(pid, address(this));
    }

    function balanceOf(address account) public view override returns (uint256) {
        if (totalShares == 0) return 0;
        return balance().mul(sharesOf(account)).div(totalShares);
    }

    function withdrawableBalanceOf(address account) public view override returns (uint256) {
        return balanceOf(account);
    }

    function sharesOf(address account) public view override returns (uint256) {
        return _shares[account];
    }

    function principalOf(address account) public view override returns (uint256) {
        return _principal[account];
    }

    function earned(address account) public view override returns (uint256) {
        if (balanceOf(account) >= principalOf(account) + DUST) {
            return balanceOf(account).sub(principalOf(account));
        } else {
            return 0;
        }
    }

    function depositedAt(address account) external view override returns (uint256) {
        return _depositedAt[account];
    }

    function rewardsToken() external view override returns (address) {
        return address(_stakingToken);
    }

    function priceShare() external view override returns (uint256) {
        if (totalShares == 0) return 1e18;
        return balance().mul(1e18).div(totalShares);
    }

    function deposit(uint256 _amount) public override {
        _depositTo(_amount, msg.sender);
    }

    function depositAll() external override {
        deposit(_stakingToken.balanceOf(msg.sender));
    }

    function withdrawAll() external override {
        uint256 amount = balanceOf(msg.sender);
        uint256 principal = principalOf(msg.sender);
        uint256 depositTimestamp = _depositedAt[msg.sender];

        totalShares = totalShares.sub(_shares[msg.sender]);
        delete _shares[msg.sender];
        delete _principal[msg.sender];
        delete _depositedAt[msg.sender];

        amount = _withdrawTokenWithCorrection(amount);
        uint256 profit = amount > principal ? amount.sub(principal) : 0;

        uint256 withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0;
        uint256 performanceFee = canMint() ? _minter.performanceFee(profit) : 0;
        if (withdrawalFee.add(performanceFee) > DUST) {
            _minter.mintFor(address(_stakingToken), withdrawalFee, performanceFee, msg.sender, depositTimestamp);

            if (performanceFee > 0) {
                emit ProfitPaid(msg.sender, profit, performanceFee);
            }
            amount = amount.sub(withdrawalFee).sub(performanceFee);
        }

        _stakingToken.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, withdrawalFee);
    }

    function harvest() external override onlyKeeper {
        _harvest();

        uint256 before = _stakingToken.balanceOf(address(this));
        zap.zapInToken(address(BANANA), bananaHarvested, address(_stakingToken));
        uint256 harvested = _stakingToken.balanceOf(address(this)).sub(before);

        APE_MASTER_CHEF.deposit(pid, harvested);
        emit Harvested(harvested);

        bananaHarvested = 0;
    }

    function _harvest() private updateBananaHarvested {
        APE_MASTER_CHEF.withdraw(pid, 0);
    }

    function withdraw(uint256 shares) external override onlyWhitelisted {
        uint256 amount = balance().mul(shares).div(totalShares);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);

        amount = _withdrawTokenWithCorrection(amount);
        _stakingToken.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, 0);
    }

    // @dev underlying only + withdrawal fee + no perf fee
    function withdrawUnderlying(uint256 _amount) external {
        uint256 amount = Math.min(_amount, _principal[msg.sender]);
        uint256 shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);
        _principal[msg.sender] = _principal[msg.sender].sub(amount);

        amount = _withdrawTokenWithCorrection(amount);
        uint256 depositTimestamp = _depositedAt[msg.sender];
        uint256 withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0;
        if (withdrawalFee > DUST) {
            _minter.mintFor(address(_stakingToken), withdrawalFee, 0, msg.sender, depositTimestamp);
            amount = amount.sub(withdrawalFee);
        }

        _stakingToken.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount, withdrawalFee);
    }

    // @dev profits only (underlying + space) + no withdraw fee + perf fee
    function getReward() external override {
        uint256 amount = earned(msg.sender);
        uint256 shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
        totalShares = totalShares.sub(shares);
        _shares[msg.sender] = _shares[msg.sender].sub(shares);
        _cleanupIfDustShares();

        amount = _withdrawTokenWithCorrection(amount);
        uint256 depositTimestamp = _depositedAt[msg.sender];
        uint256 performanceFee = canMint() ? _minter.performanceFee(amount) : 0;
        if (performanceFee > DUST) {
            _minter.mintFor(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp);
            amount = amount.sub(performanceFee);
        }

        _stakingToken.safeTransfer(msg.sender, amount);
        emit ProfitPaid(msg.sender, amount, performanceFee);
    }

    // Private functions
    function setFlipToken(address _token) private {
        _token0 = IApePair(_token).token0();
        _token1 = IApePair(_token).token1();

        _stakingToken.safeApprove(address(APE_MASTER_CHEF), uint256(~0));

        IBEP20(_token0).safeApprove(address(ROUTER), 0);
        IBEP20(_token0).safeApprove(address(ROUTER), uint256(~0));
        IBEP20(_token1).safeApprove(address(ROUTER), 0);
        IBEP20(_token1).safeApprove(address(ROUTER), uint256(~0));
    }

    function _depositTo(uint256 _amount, address _to) private notPaused updateBananaHarvested {
        uint256 _pool = balance();
        uint256 _before = _stakingToken.balanceOf(address(this));
        _stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
        uint256 _after = _stakingToken.balanceOf(address(this));
        _amount = _after.sub(_before); // Additional check for deflationary tokens
        uint256 shares = 0;
        if (totalShares == 0) {
            shares = _amount;
        } else {
            shares = (_amount.mul(totalShares)).div(_pool);
        }

        totalShares = totalShares.add(shares);
        _shares[_to] = _shares[_to].add(shares);
        _principal[_to] = _principal[_to].add(_amount);
        _depositedAt[_to] = block.timestamp;

        APE_MASTER_CHEF.deposit(pid, _amount);
        emit Deposited(_to, _amount);
    }

    function _withdrawTokenWithCorrection(uint256 amount) private updateBananaHarvested returns (uint256) {
        uint256 before = _stakingToken.balanceOf(address(this));
        APE_MASTER_CHEF.withdraw(pid, amount);
        return _stakingToken.balanceOf(address(this)).sub(before);
    }

    function _cleanupIfDustShares() private {
        uint256 shares = _shares[msg.sender];
        if (shares > 0 && shares < DUST) {
            totalShares = totalShares.sub(shares);
            delete _shares[msg.sender];
        }
    }

    // Emergency only
    // @dev stakingToken must not remain balance in this contract. So dev should salvage staking token transferred by mistake.
    function recoverToken(address token, uint256 amount) external override onlyOwner {
        if (token == address(BANANA)) {
            uint256 bananaBalance = BANANA.balanceOf(address(this));
            require(amount <= bananaBalance.sub(bananaHarvested), "VaultFlipToFlip: cannot recover lp's harvested banana");
        }

        IBEP20(token).safeTransfer(owner(), amount);
        emit Recovered(token, amount);
    }
}

File 37 of 43 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    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;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 38 of 43 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 39 of 43 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../utils/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 40 of 43 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 41 of 43 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../utils/Context.sol";

File 42 of 43 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

File 43 of 43 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

Settings
{
  "metadata": {
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_helper","type":"address"},{"internalType":"address","name":"_STAKING_TOKEN","type":"address"},{"internalType":"address","name":"_REWARDS_TOKEN","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"RewardsDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"REWARDS_TOKEN","outputs":[{"internalType":"contract IBEP20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPACE","outputs":[{"internalType":"contract IBEP20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apy","outputs":[{"internalType":"uint256","name":"_usd","type":"uint256"},{"internalType":"uint256","name":"_space","type":"uint256"},{"internalType":"uint256","name":"_bnb","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"helper","outputs":[{"internalType":"contract IStrategyHelper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"info","outputs":[{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"components":[{"internalType":"uint256","name":"usd","type":"uint256"},{"internalType":"uint256","name":"space","type":"uint256"},{"internalType":"uint256","name":"bnb","type":"uint256"}],"internalType":"struct Profit","name":"profit","type":"tuple"},{"internalType":"uint256","name":"poolTVL","type":"uint256"},{"components":[{"internalType":"uint256","name":"usd","type":"uint256"},{"internalType":"uint256","name":"space","type":"uint256"},{"internalType":"uint256","name":"bnb","type":"uint256"}],"internalType":"struct APY","name":"poolAPY","type":"tuple"}],"internalType":"struct UserInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPauseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"principalOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"profitOf","outputs":[{"internalType":"uint256","name":"_usd","type":"uint256"},{"internalType":"uint256","name":"_space","type":"uint256"},{"internalType":"uint256","name":"_bnb","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverBEP20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDistribution","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStrategyHelper","name":"_helper","type":"address"}],"name":"setHelper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsDistribution","type":"address"}],"name":"setRewardsDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"setRewardsDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"permission","type":"bool"}],"name":"setStakePermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"stakeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0604052600060055560006006556276a7006007553480156200002257600080fd5b5060405162002fc338038062002fc3833981016040819052620000459162000515565b60006200005162000229565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35060016002556000620000ac6200022d565b6001600160a01b03161415620000df5760405162461bcd60e51b8152600401620000d69062000716565b60405180910390fd5b600180546001600160a01b03199081163390811783556000908152600e602090815260408220805460ff19169094179093556001600160601b0319606085811b821660a05286901b16608052600f80546001600160a01b038881169190941617905562000170929184169173c0788a3ad43d79aa53b09c2eacc313a787d1d6079190620015b96200023c821b17901c565b620001ab73c0788a3ad43d79aa53b09c2eacc313a787d1d607600019836001600160a01b03166200023c60201b620015b9179092919060201c565b620001e573c0788a3ad43d79aa53b09c2eacc313a787d1d6076000846001600160a01b03166200023c60201b620015b9179092919060201c565b6200022073c0788a3ad43d79aa53b09c2eacc313a787d1d607600019846001600160a01b03166200023c60201b620015b9179092919060201c565b505050620007c4565b3390565b6000546001600160a01b031690565b801580620002cb5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90620002759030908690600401620005c1565b60206040518083038186803b1580156200028e57600080fd5b505afa158015620002a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002c991906200058a565b155b620002ea5760405162461bcd60e51b8152600401620000d690620006b9565b620003458363095ea7b360e01b84846040516024016200030c929190620005db565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200034a16565b505050565b6060620003a6826040518060400160405280602081526020017f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620003e660201b620016b8179092919060201c565b805190915015620003455780806020019051810190620003c7919062000568565b620003455760405162461bcd60e51b8152600401620000d69062000629565b6060620003f7848460008562000401565b90505b9392505050565b606082471015620004265760405162461bcd60e51b8152600401620000d69062000673565b6200043185620004d1565b620004505760405162461bcd60e51b8152600401620000d69062000741565b60006060866001600160a01b031685876040516200046f9190620005a3565b60006040518083038185875af1925050503d8060008114620004ae576040519150601f19603f3d011682016040523d82523d6000602084013e620004b3565b606091505b509092509050620004c6828286620004d7565b979650505050505050565b3b151590565b60608315620004e8575081620003fa565b825115620004f95782518084602001fd5b8160405162461bcd60e51b8152600401620000d69190620005f4565b6000806000606084860312156200052a578283fd5b83516200053781620007ab565b60208501519093506200054a81620007ab565b60408501519092506200055d81620007ab565b809150509250925092565b6000602082840312156200057a578081fd5b81518015158114620003fa578182fd5b6000602082840312156200059c578081fd5b5051919050565b60008251620005b781846020870162000778565b9190910192915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b60006020825282518060208401526200061581604085016020870162000778565b601f01601f19169190910160400192915050565b6020808252602a908201527f5361666542455032303a204245503230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b60208082526036908201527f5361666542455032303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60208082526011908201527013dddb995c881b5d5cdd081899481cd95d607a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60005b83811015620007955781810151838201526020016200077b565b83811115620007a5576000848401525b50505050565b6001600160a01b0381168114620007c157600080fd5b50565b60805160601c60a05160601c6127996200082a600039806109865280610b565280610e1d52806110a8528061144f5250806107fc52806108e0528061123d52806112cc528061131b5280611412528061186a52806119165280611be652506127996000f3fe608060405234801561001057600080fd5b50600436106102525760003560e01c80637b0a47ee11610146578063c8f33c91116100c3578063df136d6511610087578063df136d6514610452578063e0c9ae691461045a578063e5328e0614610462578063ebe2b12b1461046a578063efa0880614610472578063f2fde38b1461048557610252565b8063c8f33c9114610414578063cc1a378f1461041c578063cd3daf9d1461042f578063d7e3433b14610437578063de5f62681461044a57610252565b806391b4ded91161010a57806391b4ded9146103de578063986ccc7f146103e6578063b69ef8a8146102c8578063b6b55f25146103f9578063c56010721461040c57610252565b80637b0a47ee146103ab57806380faa57d146103b3578063853828b6146103bb5780638b876347146103c35780638da5cb5b146103d657610252565b80633c6b16ab116101d45780635c975abb116101985780635c975abb1461037357806361e20a1c1461038857806363b0e66a1461039b57806370a0823114610388578063715018a6146103a357610252565b80633c6b16ab1461031d5780633d18b912146103305780633fc6df6e1461033857806354198ce91461034d57806354d39b341461036057610252565b8063197621431161021b57806319762143146102d05780631c1f78eb146102e35780632e1a7d4d146102eb578063386a9525146102fe5780633bcfc4b81461030657610252565b80628cc262146102575780630700037d146102805780630aae7a6b1461029357806316c38b3c146102b357806318160ddd146102c8575b600080fd5b61026a610265366004611e87565b610498565b604051610277919061263e565b60405180910390f35b61026a61028e366004611e87565b610516565b6102a66102a1366004611e87565b610528565b60405161027791906125e7565b6102c66102c1366004611fb7565b6105d4565b005b61026a610692565b6102c66102de366004611e87565b610699565b61026a6106fa565b6102c66102f9366004611fef565b610718565b61026a610875565b61030e61087b565b604051610277939291906126b7565b6102c661032b366004611fef565b610a54565b6102c6610c66565b610340610df4565b604051610277919061209b565b61030e61035b366004611e87565b610e03565b6102c661036e36600461201f565b610eba565b61037b610ef7565b6040516102779190612146565b61026a610396366004611e87565b610f00565b610340610f1b565b6102c6610f2a565b61026a610fb3565b61026a610fb9565b6102c6610fc7565b61026a6103d1366004611e87565b610fee565b610340611000565b61026a61100f565b6102c66103f4366004611e87565b611015565b6102c6610407366004611fef565b61109c565b6103406110a6565b61026a6110ca565b6102c661042a366004611fef565b6110d0565b61026a611170565b6102c6610445366004611ebf565b6111b8565b6102c6611222565b61026a6112c4565b6103406112ca565b61026a6112ee565b61026a6113cb565b6102c6610480366004611ef7565b6113d1565b6102c6610493366004611e87565b6114f9565b6001600160a01b0381166000908152600c6020908152604080832054600b909252822054610510919061050a90670de0b6b3a764000090610504906104e5906104df611170565b906116d1565b6001600160a01b0388166000908152600d6020526040902054906116f9565b90611733565b90611765565b92915050565b600c6020526000908152604090205481565b610530611e25565b610538611e25565b6001600160a01b0383166000818152600d6020818152604080842054808752868301819052949093525282015261056d611e66565b600080600061057b87610e03565b828752602087018290526040870181905260608801879052919450925090506105a26112ee565b60808601526105af611e66565b6105b761087b565b9183526020830152604082015260a0860152509295945050505050565b6105dc61178a565b6001600160a01b03166105ed611000565b6001600160a01b03161461061c5760405162461bcd60e51b81526004016106139061244c565b60405180910390fd5b60045460ff16151581151514156106325761068f565b6004805460ff1916821515179081905560ff161561064f57426003555b6004546040517f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5916106869160ff90911690612146565b60405180910390a15b50565b600a545b90565b6106a161178a565b6001600160a01b03166106b2611000565b6001600160a01b0316146106d85760405162461bcd60e51b81526004016106139061244c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006107136007546006546116f990919063ffffffff16565b905090565b60028054141561073a5760405162461bcd60e51b8152600401610613906125b0565b6002805533610747611170565b600955610752610fb9565b6008556001600160a01b038116156107995761076d81610498565b6001600160a01b0382166000908152600c6020908152604080832093909355600954600b909152919020555b600082116107b95760405162461bcd60e51b815260040161061390612395565b600a546107c690836116d1565b600a55336000908152600d60205260409020546107e390836116d1565b336000818152600d602052604090209190915561082b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316908461178e565b336001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d583604051610864919061263e565b60405180910390a250506001600255565b60075481565b600a5460009081908190670de0b6b3a764000090806108975750805b60006108b282610504856006546116f990919063ffffffff16565b600f54604051638e333ce560e01b81529192506000916001600160a01b0390911690638e333ce590610908907f00000000000000000000000000000000000000000000000000000000000000009060040161209b565b60206040518083038186803b15801561092057600080fd5b505afa158015610934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109589190612007565b600f54604051632fd6d7f760e01b81529192506000916001600160a01b0390911690632fd6d7f7906109b8907f000000000000000000000000000000000000000000000000000000000000000090670de0b6b3a76400009060040161212d565b60206040518083038186803b1580156109d057600080fd5b505afa1580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a089190612007565b9050600097506000965060009550600081118015610a265750600082115b15610a4a57610a478261050483610a41876301e133806116f9565b906116f9565b95505b5050505050909192565b6001546001600160a01b03163314610a7e5760405162461bcd60e51b815260040161061390612542565b6000610a88611170565b600955610a93610fb9565b6008556001600160a01b03811615610ada57610aae81610498565b6001600160a01b0382166000908152600c6020908152604080832093909355600954600b909152919020555b6005544210610af957600754610af1908390611733565b600655610b3c565b600554600090610b0990426116d1565b90506000610b22600654836116f990919063ffffffff16565b600754909150610b36906105048684611765565b60065550505b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190610b8b90309060040161209b565b60206040518083038186803b158015610ba357600080fd5b505afa158015610bb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdb9190612007565b9050610bf26007548261173390919063ffffffff16565b6006541115610c135760405162461bcd60e51b81526004016106139061233e565b426008819055600754610c269190611765565b6005556040517fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d90610c5990859061263e565b60405180910390a1505050565b600280541415610c885760405162461bcd60e51b8152600401610613906125b0565b6002805533610c95611170565b600955610ca0610fb9565b6008556001600160a01b03811615610ce757610cbb81610498565b6001600160a01b0382166000908152600c6020908152604080832093909355600954600b909152919020555b336000908152600c60205260409020548015610deb57336000908152600c6020526040812055610d16816117ad565b9050610db2338273c0788a3ad43d79aa53b09c2eacc313a787d1d6076001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6a57600080fd5b505afa158015610d7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da29190611ea3565b6001600160a01b0316919061178e565b336001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048682604051610864919061263e565b50506001600255565b6001546001600160a01b031681565b600f54600090819081906001600160a01b0316632fd6d7f77f0000000000000000000000000000000000000000000000000000000000000000610e4587610498565b6040518363ffffffff1660e01b8152600401610e6292919061212d565b60206040518083038186803b158015610e7a57600080fd5b505afa158015610e8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb29190612007565b929491935050565b336000908152600e602052604090205460ff16610ee95760405162461bcd60e51b815260040161061390612504565b610ef38282611acc565b5050565b60045460ff1681565b6001600160a01b03166000908152600d602052604090205490565b600f546001600160a01b031681565b610f3261178a565b6001600160a01b0316610f43611000565b6001600160a01b031614610f695760405162461bcd60e51b81526004016106139061244c565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60065481565b600061071342600554611c59565b336000908152600d60205260409020548015610fe657610fe681610718565b61068f610c66565b600b6020526000908152604090205481565b6000546001600160a01b031690565b60035481565b61101d61178a565b6001600160a01b031661102e611000565b6001600160a01b0316146110545760405162461bcd60e51b81526004016106139061244c565b6001600160a01b03811661107a5760405162461bcd60e51b815260040161061390612184565b600f80546001600160a01b0319166001600160a01b0392909216919091179055565b61068f8133611acc565b7f000000000000000000000000000000000000000000000000000000000000000081565b60085481565b6110d861178a565b6001600160a01b03166110e9611000565b6001600160a01b03161461110f5760405162461bcd60e51b81526004016106139061244c565b600554158061111f575060055442115b61113b5760405162461bcd60e51b815260040161061390612522565b60078190556040517ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d39061068690839061263e565b6000600a54600014156111865750600954610696565b6107136111af600a54610504670de0b6b3a7640000610a41600654610a416008546104df610fb9565b60095490611765565b6111c061178a565b6001600160a01b03166111d1611000565b6001600160a01b0316146111f75760405162461bcd60e51b81526004016106139061244c565b6001600160a01b03919091166000908152600e60205260409020805460ff1916911515919091179055565b6040516370a0823160e01b81526112c2906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319061127290339060040161209b565b60206040518083038186803b15801561128a57600080fd5b505afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104079190612007565b565b60095481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600f54604051638e333ce560e01b815260009182916001600160a01b0390911690638e333ce590611343907f00000000000000000000000000000000000000000000000000000000000000009060040161209b565b60206040518083038186803b15801561135b57600080fd5b505afa15801561136f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113939190612007565b9050600081116113a45760006113c5565b6113c5670de0b6b3a764000061050483600a546116f990919063ffffffff16565b91505090565b60055481565b6113d961178a565b6001600160a01b03166113ea611000565b6001600160a01b0316146114105760405162461bcd60e51b81526004016106139061244c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415801561148457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614155b6114a05760405162461bcd60e51b815260040161061390612481565b6114bc6114ab611000565b6001600160a01b038416908361178e565b7f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2882826040516114ed92919061212d565b60405180910390a15050565b61150161178a565b6001600160a01b0316611512611000565b6001600160a01b0316146115385760405162461bcd60e51b81526004016106139061244c565b6001600160a01b03811661155e5760405162461bcd60e51b81526004016106139061220f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b8015806116415750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906115ef90309086906004016120af565b60206040518083038186803b15801561160757600080fd5b505afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163f9190612007565b155b61165d5760405162461bcd60e51b8152600401610613906123f6565b6116b38363095ea7b360e01b848460405160240161167c92919061212d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c6f565b505050565b60606116c78484600085611cfe565b90505b9392505050565b6000828211156116f35760405162461bcd60e51b8152600401610613906122c1565b50900390565b60008261170857506000610510565b8282028284828161171557fe5b04146116ca5760405162461bcd60e51b8152600401610613906123b5565b60008082116117545760405162461bcd60e51b81526004016106139061235e565b81838161175d57fe5b049392505050565b6000828201838110156116ca5760405162461bcd60e51b81526004016106139061228a565b3390565b6116b38363a9059cbb60e01b848460405160240161167c92919061212d565b60008073c0788a3ad43d79aa53b09c2eacc313a787d1d6076001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b1580156117fd57600080fd5b505afa158015611811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118359190611ea3565b604051635d5155ef60e11b815290915060009073c0788a3ad43d79aa53b09c2eacc313a787d1d6079063baa2abde9061189e907f0000000000000000000000000000000000000000000000000000000000000000908690899087908190309042906004016120ed565b6040805180830381600087803b1580156118b757600080fd5b505af11580156118cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ef9190612043565b506040805160028082526060808301845293945090916020830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061194257fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828160018151811061197057fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600082116119b05760405162461bcd60e51b815260040161061390612255565b6040516338ed173960e01b815273c0788a3ad43d79aa53b09c2eacc313a787d1d607906338ed1739906119f0908590600090869030904290600401612647565b600060405180830381600087803b158015611a0a57600080fd5b505af1158015611a1e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a469190810190611f22565b506040516370a0823160e01b81526001600160a01b038416906370a0823190611a7390309060040161209b565b60206040518083038186803b158015611a8b57600080fd5b505afa158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac39190612007565b95945050505050565b600280541415611aee5760405162461bcd60e51b8152600401610613906125b0565b6002805560045460ff1615611b155760405162461bcd60e51b8152600401610613906124a7565b80611b1e611170565b600955611b29610fb9565b6008556001600160a01b03811615611b7057611b4481610498565b6001600160a01b0382166000908152600c6020908152604080832093909355600954600b909152919020555b60008311611b905760405162461bcd60e51b815260040161061390612395565b600a54611b9d9084611765565b600a556001600160a01b0382166000908152600d6020526040902054611bc39084611765565b6001600160a01b038084166000908152600d6020526040902091909155611c0e907f000000000000000000000000000000000000000000000000000000000000000016333086611dbf565b816001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d84604051611c47919061263e565b60405180910390a25050600160025550565b6000818310611c6857816116ca565b5090919050565b6060611cc4826040518060400160405280602081526020017f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116b89092919063ffffffff16565b8051909150156116b35780806020019051810190611ce29190611fd3565b6116b35760405162461bcd60e51b8152600401610613906121c5565b606082471015611d205760405162461bcd60e51b8152600401610613906122f8565b611d2985611de6565b611d455760405162461bcd60e51b815260040161061390612579565b60006060866001600160a01b03168587604051611d62919061207f565b60006040518083038185875af1925050503d8060008114611d9f576040519150601f19603f3d011682016040523d82523d6000602084013e611da4565b606091505b5091509150611db4828286611dec565b979650505050505050565b611de0846323b872dd60e01b85858560405160240161167c939291906120c9565b50505050565b3b151590565b60608315611dfb5750816116ca565b825115611e0b5782518084602001fd5b8160405162461bcd60e51b81526004016106139190612151565b6040518060c00160405280600081526020016000815260200160008152602001611e4d611e66565b815260200160008152602001611e61611e66565b905290565b60405180606001604052806000815260200160008152602001600081525090565b600060208284031215611e98578081fd5b81356116ca81612740565b600060208284031215611eb4578081fd5b81516116ca81612740565b60008060408385031215611ed1578081fd5b8235611edc81612740565b91506020830135611eec81612755565b809150509250929050565b60008060408385031215611f09578182fd5b8235611f1481612740565b946020939093013593505050565b60006020808385031215611f34578182fd5b825167ffffffffffffffff811115611f4a578283fd5b8301601f81018513611f5a578283fd5b8051611f6d611f68826126f4565b6126cd565b8181528381019083850185840285018601891015611f89578687fd5b8694505b83851015611fab578051835260019490940193918501918501611f8d565b50979650505050505050565b600060208284031215611fc8578081fd5b81356116ca81612755565b600060208284031215611fe4578081fd5b81516116ca81612755565b600060208284031215612000578081fd5b5035919050565b600060208284031215612018578081fd5b5051919050565b60008060408385031215612031578182fd5b823591506020830135611eec81612740565b60008060408385031215612055578182fd5b505080516020909101519092909150565b8051825260208082015190830152604090810151910152565b60008251612091818460208701612714565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b6000602082528251806020840152612170816040850160208701612714565b601f01601f19169190910160400192915050565b60208082526021908201527f5370616365506f6f6c3a2073657448656c706572207a65726f206164647265736040820152607360f81b606082015260800190565b6020808252602a908201527f5361666542455032303a204245503230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252818101527f5370616365506f6f6c3a205f666c6970546f57424e42206e6f20726577617264604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252600690820152651c995dd85c9960d21b604082015260600190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b602080825260069082015265185b5bdd5b9d60d21b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526036908201527f5361666542455032303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600c908201526b746f6b656e4164647265737360a01b604082015260600190565b6020808252603c908201527f5468697320616374696f6e2063616e6e6f7420626520706572666f726d65642060408201527f7768696c652074686520636f6e74726163742069732070617573656400000000606082015260800190565b6020808252600490820152630c2eae8d60e31b604082015260600190565b6020808252600690820152651c195c9a5bd960d21b604082015260600190565b60208082526017908201527f6f6e6c7952657761726473446973747269627574696f6e000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600061014082019050825182526020830151602083015260408301516040830152606083015161261a6060840182612066565b50608083015160c083015260a083015161263760e0840182612066565b5092915050565b90815260200190565b600060a082018783526020878185015260a0604085015281875180845260c0860191508289019350845b818110156126965784516001600160a01b031683529383019391830191600101612671565b50506001600160a01b03969096166060850152505050608001529392505050565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff811182821017156126ec57600080fd5b604052919050565b600067ffffffffffffffff82111561270a578081fd5b5060209081020190565b60005b8381101561272f578181015183820152602001612717565b83811115611de05750506000910152565b6001600160a01b038116811461068f57600080fd5b801515811461068f57600080fdfea2646970667358221220d61e166d2ffd7b0ae1cf421cb8357441179ab53cdf3f81c48dc6d21044dd1f3664736f6c634300060c0033000000000000000000000000e528eef276974b15c93df8d05aa312b9ab6c9c6d000000000000000000000000e486a69e432fdc29622bf00315f6b34c99b45e80000000000000000000000000d0f82498051067e154d1dcd3d88fa95063949d7e

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000e528eef276974b15c93df8d05aa312b9ab6c9c6d000000000000000000000000e486a69e432fdc29622bf00315f6b34c99b45e80000000000000000000000000d0f82498051067e154d1dcd3d88fa95063949d7e

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000e528eef276974b15c93df8d05aa312b9ab6c9c6d
Arg [1] : 000000000000000000000000e486a69e432fdc29622bf00315f6b34c99b45e80
Arg [2] : 000000000000000000000000d0f82498051067e154d1dcd3d88fa95063949d7e


Deployed ByteCode Sourcemap

1737:9473:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10082:196;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2498:42;;;;;;:::i;:::-;;:::i;7614:731::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1701:250:31:-;;;;;;:::i;:::-;;:::i;:::-;;10409:93:5;;;:::i;1639:140:33:-;;;;;;:::i;:::-;;:::i;10284:119:5:-;;;:::i;4693:346::-;;;;;;:::i;:::-;;:::i;2275:40::-;;;:::i;8666:786::-;;;:::i;:::-;;;;;;;;;:::i;6627:717::-;;;;;;:::i;:::-;;:::i;5243:360::-;;;:::i;1393:34:33:-;;;:::i;:::-;;;;;;;:::i;8351:309:5:-;;;;;;:::i;:::-;;:::i;6517:104::-;;;;;;:::i;:::-;;:::i;1406:18:31:-;;;:::i;:::-;;;;;;;:::i;10737:121:5:-;;;;;;:::i;:::-;;:::i;2732:29::-;;;:::i;1717:145:37:-;;;:::i;2240:29:5:-;;;:::i;9748:129::-;;;:::i;5045:192::-;;;:::i;2435:57::-;;;;;;:::i;:::-;;:::i;1085:85:37:-;;;:::i;1372:28:31:-;;;:::i;6185:182:5:-;;;;;;:::i;:::-;;:::i;4144:94::-;;;;;;:::i;:::-;;:::i;2111:37::-;;;:::i;2322:29::-;;;:::i;7350:258::-;;;;;;:::i;:::-;;:::i;9458:284::-;;;:::i;6373:138::-;;;;;;:::i;:::-;;:::i;4244:93::-;;;:::i;2357:35::-;;;:::i;2026:29::-;;;:::i;9883:193::-;;;:::i;2203:31::-;;;:::i;10894:314::-;;;;;;:::i;:::-;;:::i;2011:240:37:-;;;;;;:::i;:::-;;:::i;10082:196:5:-;-1:-1:-1;;;;;10254:16:5;;10136:7;10254:16;;;:7;:16;;;;;;;;;10206:22;:31;;;;;;10162:109;;10254:16;10162:87;;10244:4;;10162:77;;10185:53;;:16;:14;:16::i;:::-;:20;;:53::i;:::-;-1:-1:-1;;;;;10162:18:5;;;;;;:9;:18;;;;;;;:22;:77::i;:::-;:81;;:87::i;:::-;:91;;:109::i;:::-;10155:116;10082:196;-1:-1:-1;;10082:196:5:o;2498:42::-;;;;;;;;;;;;;:::o;7614:731::-;7677:15;;:::i;:::-;7704:24;;:::i;:::-;-1:-1:-1;;;;;7758:18:5;;;;;;:9;:18;;;;;;;;;7739:37;;;7786:18;;;:39;;;7856:18;;;;;7835;;:39;7885:20;;:::i;:::-;7916:11;7929:13;7944:11;7959:17;7968:7;7959:8;:17::i;:::-;7986:16;;;8012:12;;;:20;;;8042:10;;;:16;;;8068:15;;;:24;;;7915:61;;-1:-1:-1;7915:61:5;-1:-1:-1;7915:61:5;-1:-1:-1;8122:5:5;:3;:5::i;:::-;8103:16;;;:24;8138:18;;:::i;:::-;8186:5;:3;:5::i;:::-;8201:17;;;8228:13;;;:21;8259:11;;;:17;8286:16;;;:26;-1:-1:-1;8286:16:5;;7614:731;-1:-1:-1;;;;;7614:731:5:o;1701:250:31:-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;;;;;;;;;1778:6:31::1;::::0;::::1;;1767:17;;::::0;::::1;;;1763:54;;;1800:7;;1763:54;1827:6;:16:::0;;-1:-1:-1;;1827:16:31::1;::::0;::::1;;;::::0;;;;::::1;1857:6;1853:56;;;1895:3;1879:13;:19:::0;1853:56:::1;1937:6;::::0;1924:20:::1;::::0;::::1;::::0;::::1;::::0;1937:6:::1;::::0;;::::1;::::0;1924:20:::1;:::i;:::-;;;;;;;;1367:1:37;1701:250:31::0;:::o;10409:93:5:-;10481:14;;10409:93;;:::o;1639:140:33:-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;1730:19:33::1;:42:::0;;-1:-1:-1;;;;;;1730:42:33::1;-1:-1:-1::0;;;;;1730:42:33;;;::::1;::::0;;;::::1;::::0;;1639:140::o;10284:119:5:-;10339:7;10365:31;10380:15;;10365:10;;:14;;:31;;;;:::i;:::-;10358:38;;10284:119;:::o;4693:346::-;1688:1:42;2277:7;;:19;;2269:63;;;;-1:-1:-1;;;2269:63:42;;;;;;;:::i;:::-;1688:1;2407:18;;4769:10:5::1;3162:16;:14;:16::i;:::-;3139:20;:39:::0;3205:26:::1;:24;:26::i;:::-;3188:14;:43:::0;-1:-1:-1;;;;;3245:21:5;::::1;::::0;3241:154:::1;;3301:15;3308:7;3301:6;:15::i;:::-;-1:-1:-1::0;;;;;3282:16:5;::::1;;::::0;;;:7:::1;:16;::::0;;;;;;;:34;;;;3364:20:::1;::::0;3330:22:::1;:31:::0;;;;;;:54;3241:154:::1;4808:1:::2;4799:6;:10;4791:29;;;;-1:-1:-1::0;;;4791:29:5::2;;;;;;;:::i;:::-;4847:14;::::0;:26:::2;::::0;4866:6;4847:18:::2;:26::i;:::-;4830:14;:43:::0;4917:10:::2;4907:21;::::0;;;:9:::2;:21;::::0;;;;;:33:::2;::::0;4933:6;4907:25:::2;:33::i;:::-;4893:10;4883:21;::::0;;;:9:::2;:21;::::0;;;;:57;;;;4950:38:::2;::::0;:5:::2;-1:-1:-1::0;;;;;4950:18:5::2;::::0;4981:6;4950:18:::2;:38::i;:::-;5013:10;-1:-1:-1::0;;;;;5003:29:5::2;;5025:6;5003:29;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;1645:1:42;2580:7;:22;4693:346:5:o;2275:40::-;;;;:::o;8666:786::-;8909:14;;8756:12;;;;;;8871:4;;8937:18;8933:78;;-1:-1:-1;8987:13:5;8933:78;9021:31;9055:48;9089:13;9055:29;9070:13;9055:10;;:14;;:29;;;;:::i;:48::-;9135:6;;:38;;-1:-1:-1;;;9135:38:5;;9021:82;;-1:-1:-1;9114:18:5;;-1:-1:-1;;;;;9135:6:5;;;;:22;;:38;;9166:5;;9135:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9201:6;;:45;;-1:-1:-1;;;9201:45:5;;9114:59;;-1:-1:-1;9183:15:5;;-1:-1:-1;;;;;9201:6:5;;;;:15;;:45;;9225:13;;9241:4;;9201:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9183:63;;9264:1;9257:8;;9284:1;9275:10;;9302:1;9295:8;;9327:1;9317:7;:11;:29;;;;;9345:1;9332:10;:14;9317:29;9313:133;;;9369:66;9424:10;9369:50;9411:7;9369:37;:23;9397:8;9369:27;:37::i;:::-;:41;;:50::i;:66::-;9362:73;;9313:133;8666:786;;;;;;;;:::o;6627:717::-;1501:19:33;;-1:-1:-1;;;;;1501:19:33;1487:10;:33;1479:69;;;;-1:-1:-1;;;1479:69:33;;;;;;;:::i;:::-;6734:1:5::1;3162:16;:14;:16::i;:::-;3139:20;:39:::0;3205:26:::1;:24;:26::i;:::-;3188:14;:43:::0;-1:-1:-1;;;;;3245:21:5;::::1;::::0;3241:154:::1;;3301:15;3308:7;3301:6;:15::i;:::-;-1:-1:-1::0;;;;;3282:16:5;::::1;;::::0;;;:7:::1;:16;::::0;;;;;;;:34;;;;3364:20:::1;::::0;3330:22:::1;:31:::0;;;;;;:54;3241:154:::1;6771:12:::2;;6752:15;:31;6748:312;;6823:15;::::0;6812:27:::2;::::0;:6;;:10:::2;:27::i;:::-;6799:10;:40:::0;6748:312:::2;;;6890:12;::::0;6870:17:::2;::::0;6890:33:::2;::::0;6907:15:::2;6890:16;:33::i;:::-;6870:53;;6937:16;6956:25;6970:10;;6956:9;:13;;:25;;;;:::i;:::-;7033:15;::::0;6937:44;;-1:-1:-1;7008:41:5::2;::::0;:20:::2;:6:::0;6937:44;7008:10:::2;:20::i;:41::-;6995:10;:54:::0;-1:-1:-1;;6748:312:5::2;7089:38;::::0;-1:-1:-1;;;7089:38:5;;7070:16:::2;::::0;-1:-1:-1;;;;;7089:13:5::2;:23;::::0;::::2;::::0;:38:::2;::::0;7121:4:::2;::::0;7089:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7070:57;;7159:29;7172:15;;7159:8;:12;;:29;;;;:::i;:::-;7145:10;;:43;;7137:62;;;;-1:-1:-1::0;;;7137:62:5::2;;;;;;;:::i;:::-;7227:15;7210:14;:32:::0;;;7287:15:::2;::::0;7267:36:::2;::::0;7227:15;7267:19:::2;:36::i;:::-;7252:12;:51:::0;7318:19:::2;::::0;::::2;::::0;::::2;::::0;7330:6;;7318:19:::2;:::i;:::-;;;;;;;;3404:1;1558::33::1;6627:717:5::0;:::o;5243:360::-;1688:1:42;2277:7;;:19;;2269:63;;;;-1:-1:-1;;;2269:63:42;;;;;;;:::i;:::-;1688:1;2407:18;;5306:10:5::1;3162:16;:14;:16::i;:::-;3139:20;:39:::0;3205:26:::1;:24;:26::i;:::-;3188:14;:43:::0;-1:-1:-1;;;;;3245:21:5;::::1;::::0;3241:154:::1;;3301:15;3308:7;3301:6;:15::i;:::-;-1:-1:-1::0;;;;;3282:16:5;::::1;;::::0;;;:7:::1;:16;::::0;;;;;;;:34;;;;3364:20:::1;::::0;3330:22:::1;:31:::0;;;;;;:54;3241:154:::1;5353:10:::2;5328:14;5345:19:::0;;;:7:::2;:19;::::0;;;;;5378:10;;5374:223:::2;;5412:10;5426:1;5404:19:::0;;;:7:::2;:19;::::0;;;;:23;5450:19:::2;5462:6:::0;5450:11:::2;:19::i;:::-;5441:28;;5483:54;5518:10;5530:6;1950:42;-1:-1:-1::0;;;;;5490:11:5::2;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;5483:34:5::2;::::0;:54;:34:::2;:54::i;:::-;5567:10;-1:-1:-1::0;;;;;5556:30:5::2;;5579:6;5556:30;;;;;;:::i;5374:223::-;-1:-1:-1::0;;1645:1:42;2580:7;:22;5243:360:5:o;1393:34:33:-;;;-1:-1:-1;;;;;1393:34:33;;:::o;8351:309:5:-;8597:6;;8461:12;;;;;;-1:-1:-1;;;;;8597:6:5;:15;8621:13;8637:15;8644:7;8637:6;:15::i;:::-;8597:56;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8351:309;;;;-1:-1:-1;;8351:309:5:o;6517:104::-;3475:10;3458:28;;;;:16;:28;;;;;;;;3450:45;;;;-1:-1:-1;;;3450:45:5;;;;;;;:::i;:::-;6593:21:::1;6602:6;6610:3;6593:8;:21::i;:::-;6517:104:::0;;:::o;1406:18:31:-;;;;;;:::o;10737:121:5:-;-1:-1:-1;;;;;10833:18:5;10807:7;10833:18;;;:9;:18;;;;;;;10737:121::o;2732:29::-;;;-1:-1:-1;;;;;2732:29:5;;:::o;1717:145:37:-;1308:12;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;1823:1:::1;1807:6:::0;;1786:40:::1;::::0;-1:-1:-1;;;;;1807:6:37;;::::1;::::0;1786:40:::1;::::0;1823:1;;1786:40:::1;1853:1;1836:19:::0;;-1:-1:-1;;;;;;1836:19:37::1;::::0;;1717:145::o;2240:29:5:-;;;;:::o;9748:129::-;9805:7;9831:39;9840:15;9857:12;;9831:8;:39::i;5045:192::-;5126:10;5096:17;5116:21;;;:9;:21;;;;;;5151:13;;5147:63;;5180:19;5189:9;5180:8;:19::i;:::-;5219:11;:9;:11::i;2435:57::-;;;;;;;;;;;;;:::o;1085:85:37:-;1131:7;1157:6;-1:-1:-1;;;;;1157:6:37;1085:85;:::o;1372:28:31:-;;;;:::o;6185:182:5:-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;-1:-1:-1;;;;;6266:30:5;::::1;6258:76;;;;-1:-1:-1::0;;;6258:76:5::1;;;;;;;:::i;:::-;6344:6;:16:::0;;-1:-1:-1;;;;;;6344:16:5::1;-1:-1:-1::0;;;;;6344:16:5;;;::::1;::::0;;;::::1;::::0;;6185:182::o;4144:94::-;4203:28;4212:6;4220:10;4203:8;:28::i;2111:37::-;;;:::o;2322:29::-;;;;:::o;7350:258::-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;7441:12:5::1;::::0;:17;;:51:::1;;;7480:12;;7462:15;:30;7441:51;7433:70;;;;-1:-1:-1::0;;;7433:70:5::1;;;;;;;:::i;:::-;7513:15;:34:::0;;;7562:39:::1;::::0;::::1;::::0;::::1;::::0;7531:16;;7562:39:::1;:::i;9458:284::-:0;9505:7;9528:14;;9546:1;9528:19;9524:77;;;-1:-1:-1;9570:20:5;;9563:27;;9524:77;9617:118;9642:92;9719:14;;9642:72;9709:4;9642:62;9693:10;;9642:46;9673:14;;9642:26;:24;:26::i;:92::-;9617:20;;;:24;:118::i;6373:138::-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;-1:-1:-1;;;;;6465:26:5;;;::::1;;::::0;;;:16:::1;:26;::::0;;;;:39;;-1:-1:-1;;6465:39:5::1;::::0;::::1;;::::0;;;::::1;::::0;;6373:138::o;4244:93::-;4302:27;;-1:-1:-1;;;4302:27:5;;4294:36;;-1:-1:-1;;;;;4302:5:5;:15;;;;:27;;4318:10;;4302:27;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;4294:36::-;4244:93::o;2357:35::-;;;;:::o;2026:29::-;;;:::o;9883:193::-;9963:6;;:38;;-1:-1:-1;;;9963:38:5;;9928:7;;;;-1:-1:-1;;;;;9963:6:5;;;;:22;;:38;;9994:5;;9963:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9947:54;;10026:1;10018:5;:9;:51;;10068:1;10018:51;;;10030:35;10060:4;10030:25;10049:5;10030:14;;:18;;:25;;;;:::i;:35::-;10011:58;;;9883:193;:::o;2203:31::-;;;;:::o;10894:314::-;1308:12:37;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;11020:5:5::1;-1:-1:-1::0;;;;;10996:30:5::1;:12;-1:-1:-1::0;;;;;10996:30:5::1;;;:72;;;;;11054:13;-1:-1:-1::0;;;;;11030:38:5::1;:12;-1:-1:-1::0;;;;;11030:38:5::1;;;10996:72;10988:97;;;;-1:-1:-1::0;;;10988:97:5::1;;;;;;;:::i;:::-;11095:55;11129:7;:5;:7::i;:::-;-1:-1:-1::0;;;;;11095:33:5;::::1;::::0;11138:11;11095:33:::1;:55::i;:::-;11165:36;11175:12;11189:11;11165:36;;;;;;;:::i;:::-;;;;;;;;10894:314:::0;;:::o;2011:240:37:-;1308:12;:10;:12::i;:::-;-1:-1:-1;;;;;1297:23:37;:7;:5;:7::i;:::-;-1:-1:-1;;;;;1297:23:37;;1289:68;;;;-1:-1:-1;;;1289:68:37;;;;;;;:::i;:::-;-1:-1:-1;;;;;2099:22:37;::::1;2091:73;;;;-1:-1:-1::0;;;2091:73:37::1;;;;;;;:::i;:::-;2200:6;::::0;;2179:38:::1;::::0;-1:-1:-1;;;;;2179:38:37;;::::1;::::0;2200:6;::::1;::::0;2179:38:::1;::::0;::::1;2227:6;:17:::0;;-1:-1:-1;;;;;;2227:17:37::1;-1:-1:-1::0;;;;;2227:17:37;;;::::1;::::0;;;::::1;::::0;;2011:240::o;1462:622:34:-;1857:10;;;1856:62;;-1:-1:-1;1873:39:34;;-1:-1:-1;;;1873:39:34;;-1:-1:-1;;;;;1873:15:34;;;;;:39;;1897:4;;1904:7;;1873:39;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1856:62;1848:129;;;;-1:-1:-1;;;1848:129:34;;;;;;;:::i;:::-;1987:90;2007:5;2037:22;;;2061:7;2070:5;2014:62;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;2014:62:34;;;;;;;;;;;;;;-1:-1:-1;;;;;2014:62:34;-1:-1:-1;;;;;;2014:62:34;;;;;;;;;;1987:19;:90::i;:::-;1462:622;;;:::o;3581:193:40:-;3684:12;3715:52;3737:6;3745:4;3751:1;3754:12;3715:21;:52::i;:::-;3708:59;;3581:193;;;;;;:::o;3136:155:39:-;3194:7;3226:1;3221;:6;;3213:49;;;;-1:-1:-1;;;3213:49:39;;;;;;;:::i;:::-;-1:-1:-1;3279:5:39;;;3136:155::o;3538:215::-;3596:7;3619:6;3615:20;;-1:-1:-1;3634:1:39;3627:8;;3615:20;3657:5;;;3661:1;3657;:5;:1;3680:5;;;;;:10;3672:56;;;;-1:-1:-1;;;3672:56:39;;;;;;;:::i;4217:150::-;4275:7;4306:1;4302;:5;4294:44;;;;-1:-1:-1;;;4294:44:39;;;;;;;:::i;:::-;4359:1;4355;:5;;;;;;;4217:150;-1:-1:-1;;;4217:150:39:o;2690:175::-;2748:7;2779:5;;;2802:6;;;;2794:46;;;;-1:-1:-1;;;2794:46:39;;;;;;;:::i;598:104:41:-;685:10;598:104;:::o;750:205:34:-;862:86;882:5;912:23;;;937:2;941:5;889:58;;;;;;;;;:::i;5609:570:5:-;5663:14;5689:12;1950:42;-1:-1:-1;;;;;5704:11:5;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5753:90;;-1:-1:-1;;;5753:90:5;;5689:28;;-1:-1:-1;5728:19:5;;1950:42;;5753:22;;:90;;5784:5;;5689:28;;5798:6;;5728:19;;;;5820:4;;5827:15;;5753:90;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5877:16:5;;;5891:1;5877:16;;;5853:21;5877:16;;;;;5727:116;;-1:-1:-1;5877:16:5;;;;;;;;;;;;-1:-1:-1;5877:16:5;5853:40;;5921:5;5903:4;5908:1;5903:7;;;;;;;;;;;;;:24;-1:-1:-1;;;;;5903:24:5;;;-1:-1:-1;;;;;5903:24:5;;;;;5947:4;5937;5942:1;5937:7;;;;;;;;;;;;;:14;-1:-1:-1;;;;;5937:14:5;;;-1:-1:-1;;;;;5937:14:5;;;;;5983:1;5969:11;:15;5961:60;;;;-1:-1:-1;;;5961:60:5;;;;;;;:::i;:::-;6031:85;;-1:-1:-1;;;6031:85:5;;1950:42;;6031:31;;:85;;6063:11;;6076:1;;6079:4;;6093;;6100:15;;6031:85;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6031:85:5;;;;;;;;;;;;:::i;:::-;-1:-1:-1;6135:37:5;;-1:-1:-1;;;6135:37:5;;-1:-1:-1;;;;;6135:22:5;;;;;:37;;6166:4;;6135:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6126:46;5609:570;-1:-1:-1;;;;;5609:570:5:o;4343:344::-;1688:1:42;2277:7;;:19;;2269:63;;;;-1:-1:-1;;;2269:63:42;;;;;;;:::i;:::-;1688:1;2407:18;;1509:6:31::1;::::0;::::1;;1508:7;1500:80;;;;-1:-1:-1::0;;;1500:80:31::1;;;;;;;:::i;:::-;4433:2:5::2;3162:16;:14;:16::i;:::-;3139:20;:39:::0;3205:26:::2;:24;:26::i;:::-;3188:14;:43:::0;-1:-1:-1;;;;;3245:21:5;::::2;::::0;3241:154:::2;;3301:15;3308:7;3301:6;:15::i;:::-;-1:-1:-1::0;;;;;3282:16:5;::::2;;::::0;;;:7:::2;:16;::::0;;;;;;;:34;;;;3364:20:::2;::::0;3330:22:::2;:31:::0;;;;;;:54;3241:154:::2;4464:1:::3;4455:6;:10;4447:29;;;;-1:-1:-1::0;;;4447:29:5::3;;;;;;;:::i;:::-;4503:14;::::0;:26:::3;::::0;4522:6;4503:18:::3;:26::i;:::-;4486:14;:43:::0;-1:-1:-1;;;;;4555:13:5;::::3;;::::0;;;:9:::3;:13;::::0;;;;;:25:::3;::::0;4573:6;4555:17:::3;:25::i;:::-;-1:-1:-1::0;;;;;4539:13:5;;::::3;;::::0;;;:9:::3;:13;::::0;;;;:41;;;;4590:57:::3;::::0;:5:::3;:22;4613:10;4633:4;4640:6:::0;4590:22:::3;:57::i;:::-;4669:2;-1:-1:-1::0;;;;;4662:18:5::3;;4673:6;4662:18;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;1645:1:42;2580:7;:22;-1:-1:-1;4343:344:5:o;399:104:38:-;457:7;487:1;483;:5;:13;;495:1;483:13;;;-1:-1:-1;491:1:38;;476:20;-1:-1:-1;399:104:38:o;3150:763:34:-;3569:23;3595:69;3623:4;3595:69;;;;;;;;;;;;;;;;;3603:5;-1:-1:-1;;;;;3595:27:34;;;:69;;;;;:::i;:::-;3678:17;;3569:95;;-1:-1:-1;3678:21:34;3674:233;;3830:10;3819:30;;;;;;;;;;;;:::i;:::-;3811:85;;;;-1:-1:-1;;;3811:85:34;;;;;;;:::i;4608:523:40:-;4735:12;4792:5;4767:21;:30;;4759:81;;;;-1:-1:-1;;;4759:81:40;;;;;;;:::i;:::-;4858:18;4869:6;4858:10;:18::i;:::-;4850:60;;;;-1:-1:-1;;;4850:60:40;;;;;;;:::i;:::-;4981:12;4995:23;5022:6;-1:-1:-1;;;;;5022:11:40;5042:5;5050:4;5022:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4980:75;;;;5072:52;5090:7;5099:10;5111:12;5072:17;:52::i;:::-;5065:59;4608:523;-1:-1:-1;;;;;;;4608:523:40:o;961:241:34:-;1099:96;1119:5;1149:27;;;1178:4;1184:2;1188:5;1126:68;;;;;;;;;;:::i;1099:96::-;961:241;;;;:::o;726:413:40:-;1086:20;1124:8;;;726:413::o;7091:725::-;7206:12;7234:7;7230:580;;;-1:-1:-1;7264:10:40;7257:17;;7230:580;7375:17;;:21;7371:429;;7633:10;7627:17;7693:15;7680:10;7676:2;7672:19;7665:44;7582:145;7772:12;7765:20;;-1:-1:-1;;;7765:20:40;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;1762:241::-;;1866:2;1854:9;1845:7;1841:23;1837:32;1834:2;;;-1:-1;;1872:12;1834:2;85:6;72:20;97:33;124:5;97:33;:::i;2010:263::-;;2125:2;2113:9;2104:7;2100:23;2096:32;2093:2;;;-1:-1;;2131:12;2093:2;226:6;220:13;238:33;265:5;238:33;:::i;2280:360::-;;;2398:2;2386:9;2377:7;2373:23;2369:32;2366:2;;;-1:-1;;2404:12;2366:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;2456:63;-1:-1;2556:2;2592:22;;1095:20;1120:30;1095:20;1120:30;:::i;:::-;2564:60;;;;2360:280;;;;;:::o;2647:366::-;;;2768:2;2756:9;2747:7;2743:23;2739:32;2736:2;;;-1:-1;;2774:12;2736:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;2826:63;2926:2;2965:22;;;;1551:20;;-1:-1;;;2730:283::o;3020:392::-;;3160:2;;3148:9;3139:7;3135:23;3131:32;3128:2;;;-1:-1;;3166:12;3128:2;3217:17;3211:24;3255:18;3247:6;3244:30;3241:2;;;-1:-1;;3277:12;3241:2;3364:22;;422:4;410:17;;406:27;-1:-1;396:2;;-1:-1;;437:12;396:2;477:6;471:13;499:80;514:64;571:6;514:64;:::i;:::-;499:80;:::i;:::-;607:21;;;664:14;;;;639:17;;;753;;;744:27;;;;741:36;-1:-1;738:2;;;-1:-1;;780:12;738:2;-1:-1;806:10;;800:217;825:6;822:1;819:13;800:217;;;1699:13;;893:61;;847:1;840:9;;;;;968:14;;;;996;;800:217;;;-1:-1;3297:99;3122:290;-1:-1;;;;;;;3122:290::o;3419:235::-;;3520:2;3508:9;3499:7;3495:23;3491:32;3488:2;;;-1:-1;;3526:12;3488:2;1108:6;1095:20;1120:30;1144:5;1120:30;:::i;3661:257::-;;3773:2;3761:9;3752:7;3748:23;3744:32;3741:2;;;-1:-1;;3779:12;3741:2;1243:6;1237:13;1255:30;1279:5;1255:30;:::i;4223:241::-;;4327:2;4315:9;4306:7;4302:23;4298:32;4295:2;;;-1:-1;;4333:12;4295:2;-1:-1;1551:20;;4289:175;-1:-1;4289:175::o;4471:263::-;;4586:2;4574:9;4565:7;4561:23;4557:32;4554:2;;;-1:-1;;4592:12;4554:2;-1:-1;1699:13;;4548:186;-1:-1;4548:186::o;4741:366::-;;;4862:2;4850:9;4841:7;4837:23;4833:32;4830:2;;;-1:-1;;4868:12;4830:2;1564:6;1551:20;4920:63;;5020:2;5063:9;5059:22;72:20;97:33;124:5;97:33;:::i;5114:399::-;;;5246:2;5234:9;5225:7;5221:23;5217:32;5214:2;;;-1:-1;;5252:12;5214:2;-1:-1;;1699:13;;5415:2;5465:22;;;1699:13;;;;;-1:-1;5208:305::o;15348:613::-;15540:23;;17953:37;;15712:4;15701:16;;;15695:23;15772:14;;;17953:37;15865:4;15854:16;;;15848:23;15925:14;;17953:37;15448:513::o;18122:271::-;;7081:5;33554:12;7192:52;7237:6;7232:3;7225:4;7218:5;7214:16;7192:52;:::i;:::-;7256:16;;;;;18256:137;-1:-1;;18256:137::o;18400:222::-;-1:-1;;;;;34854:54;;;;5912:37;;18527:2;18512:18;;18498:124::o;18874:333::-;-1:-1;;;;;34854:54;;;5912:37;;34854:54;;19193:2;19178:18;;5912:37;19029:2;19014:18;;19000:207::o;19214:444::-;-1:-1;;;;;34854:54;;;5912:37;;34854:54;;;;19561:2;19546:18;;5912:37;19644:2;19629:18;;17953:37;;;;19397:2;19382:18;;19368:290::o;19665:924::-;-1:-1;;;;;34854:54;;;5912:37;;34854:54;;;20141:2;20126:18;;5912:37;20224:2;20209:18;;17953:37;;;;20315:2;20300:18;;7711:58;;;;20406:3;20391:19;;7711:58;34854:54;;;34865:42;20475:19;;5912:37;20574:3;20559:19;;17953:37;;;;19976:3;19961:19;;19947:642::o;20596:385::-;-1:-1;;;;;34854:54;;;;5912:37;;20967:2;20952:18;;7711:58;20777:2;20762:18;;20748:233::o;21328:210::-;34643:13;;34636:21;6875:34;;21449:2;21434:18;;21420:118::o;22085:310::-;;22232:2;22253:17;22246:47;8111:5;33554:12;34098:6;22232:2;22221:9;22217:18;34086:19;8205:52;8250:6;34126:14;22221:9;34126:14;22232:2;8231:5;8227:16;8205:52;:::i;:::-;36612:7;36596:14;-1:-1;;36592:28;8269:39;;;;34126:14;8269:39;;22203:192;-1:-1;;22203:192::o;22402:416::-;22602:2;22616:47;;;8545:2;22587:18;;;34086:19;8581:34;34126:14;;;8561:55;-1:-1;;;8636:12;;;8629:25;8673:12;;;22573:245::o;22825:416::-;23025:2;23039:47;;;8924:2;23010:18;;;34086:19;8960:34;34126:14;;;8940:55;-1:-1;;;9015:12;;;9008:34;9061:12;;;22996:245::o;23248:416::-;23448:2;23462:47;;;9312:2;23433:18;;;34086:19;9348:34;34126:14;;;9328:55;-1:-1;;;9403:12;;;9396:30;9445:12;;;23419:245::o;23671:416::-;23871:2;23885:47;;;23856:18;;;34086:19;9732:34;34126:14;;;9712:55;9786:12;;;23842:245::o;24094:416::-;24294:2;24308:47;;;10037:2;24279:18;;;34086:19;10073:29;34126:14;;;10053:50;10122:12;;;24265:245::o;24517:416::-;24717:2;24731:47;;;10373:2;24702:18;;;34086:19;10409:32;34126:14;;;10389:53;10461:12;;;24688:245::o;24940:416::-;25140:2;25154:47;;;10712:2;25125:18;;;34086:19;10748:34;34126:14;;;10728:55;-1:-1;;;10803:12;;;10796:30;10845:12;;;25111:245::o;25363:416::-;25563:2;25577:47;;;11096:1;25548:18;;;34086:19;-1:-1;;;34126:14;;;11111:29;11159:12;;;25534:245::o;25786:416::-;25986:2;26000:47;;;11410:2;25971:18;;;34086:19;11446:28;34126:14;;;11426:49;11494:12;;;25957:245::o;26209:416::-;26409:2;26423:47;;;11745:1;26394:18;;;34086:19;-1:-1;;;34126:14;;;11760:29;11808:12;;;26380:245::o;26632:416::-;26832:2;26846:47;;;12059:2;26817:18;;;34086:19;12095:34;34126:14;;;12075:55;-1:-1;;;12150:12;;;12143:25;12187:12;;;26803:245::o;27055:416::-;27255:2;27269:47;;;12438:2;27240:18;;;34086:19;12474:34;34126:14;;;12454:55;-1:-1;;;12529:12;;;12522:46;12587:12;;;27226:245::o;27478:416::-;27678:2;27692:47;;;27663:18;;;34086:19;12874:34;34126:14;;;12854:55;12928:12;;;27649:245::o;27901:416::-;28101:2;28115:47;;;13179:2;28086:18;;;34086:19;-1:-1;;;34126:14;;;13195:35;13249:12;;;28072:245::o;28324:416::-;28524:2;28538:47;;;13500:2;28509:18;;;34086:19;13536:34;34126:14;;;13516:55;13605:30;13591:12;;;13584:52;13655:12;;;28495:245::o;28747:416::-;28947:2;28961:47;;;13906:1;28932:18;;;34086:19;-1:-1;;;34126:14;;;13921:27;13967:12;;;28918:245::o;29170:416::-;29370:2;29384:47;;;14218:1;29355:18;;;34086:19;-1:-1;;;34126:14;;;14233:29;14281:12;;;29341:245::o;29593:416::-;29793:2;29807:47;;;14532:2;29778:18;;;34086:19;14568:25;34126:14;;;14548:46;14613:12;;;29764:245::o;30016:416::-;30216:2;30230:47;;;14864:2;30201:18;;;34086:19;14900:31;34126:14;;;14880:52;14951:12;;;30187:245::o;30439:416::-;30639:2;30653:47;;;15202:2;30624:18;;;34086:19;15238:33;34126:14;;;15218:54;15291:12;;;30610:245::o;30862:331::-;;31043:3;31032:9;31028:19;31020:27;;16896:16;16890:23;17960:3;17953:37;17066:4;17059:5;17055:16;17049:23;17066:4;17130:3;17126:14;17953:37;17225:4;17218:5;17214:16;17208:23;17225:4;17289:3;17285:14;17953:37;17381:4;17374:5;17370:16;17364:23;17393:113;17381:4;17495:3;17491:14;17477:12;17393:113;:::i;:::-;;17588:4;17581:5;17577:16;17571:23;17657:4;17652:3;17648:14;17953:37;17745:4;17738:5;17734:16;17728:23;17757:107;17858:4;17853:3;17849:14;17835:12;17757:107;:::i;:::-;;31014:179;;;;:::o;31200:222::-;17953:37;;;31327:2;31312:18;;31298:124::o;31429:832::-;;31726:3;31715:9;31711:19;17983:5;17960:3;17953:37;31899:2;35831:24;31899:2;31888:9;31884:18;7711:58;31726:3;31936:2;31925:9;31921:18;31914:48;31976:108;6305:5;33554:12;34098:6;34093:3;34086:19;34126:14;31715:9;34126:14;6317:93;;31899:2;6481:5;33408:14;6493:21;;-1:-1;6520:260;6545:6;6542:1;6539:13;6520:260;;;6606:13;;-1:-1;;;;;34854:54;5912:37;;33941:14;;;;5674;;;;3255:18;6560:9;6520:260;;;-1:-1;;;;;;;34854:54;;;;32163:2;32148:18;;5912:37;-1:-1;;;32246:3;32231:19;17953:37;31968:116;31697:564;-1:-1;;;31697:564::o;32268:444::-;17953:37;;;32615:2;32600:18;;17953:37;;;;32698:2;32683:18;;17953:37;32451:2;32436:18;;32422:290::o;32719:256::-;32781:2;32775:9;32807:17;;;32882:18;32867:34;;32903:22;;;32864:62;32861:2;;;32939:1;;32929:12;32861:2;32781;32948:22;32759:216;;-1:-1;32759:216::o;32982:304::-;;33141:18;33133:6;33130:30;33127:2;;;-1:-1;;33163:12;33127:2;-1:-1;33208:4;33196:17;;;33261:15;;33064:222::o;36252:268::-;36317:1;36324:101;36338:6;36335:1;36332:13;36324:101;;;36405:11;;;36399:18;36386:11;;;36379:39;36360:2;36353:10;36324:101;;;36440:6;36437:1;36434:13;36431:2;;;-1:-1;;36317:1;36487:16;;36480:27;36301:219::o;36633:117::-;-1:-1;;;;;34854:54;;36692:35;;36682:2;;36741:1;;36731:12;36757:111;36838:5;34643:13;34636:21;36816:5;36813:32;36803:2;;36859:1;;36849:12

Swarm Source

ipfs://d61e166d2ffd7b0ae1cf421cb8357441179ab53cdf3f81c48dc6d21044dd1f36
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.