Kashi <> Cauldron
681 linee
/**
/**
 *Submitted for verification at Etherscan.io on 2021-03-27
 *Submitted for verification at Etherscan.io on 2021-07-06
*/
*/
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: MIXED
// Kashi Lending Medium Risk
//  __  __             __    __      _____                  __ __
// |  |/  .---.-.-----|  |--|__|    |     |_.-----.-----.--|  |__.-----.-----.
// |     <|  _  |__ --|     |  |    |       |  -__|     |  _  |  |     |  _  |
// |__|\__|___._|_____|__|__|__|    |_______|_____|__|__|_____|__|__|__|___  |
//                                                                     |_____|
// Copyright (c) 2021 BoringCrypto - All rights reserved
// Twitter: @Boring_Crypto
// Special thanks to:
// @0xKeno - for all his invaluable contributions
// @burger_crypto - for the idea of trying to let the LPs benefit from liquidations
// Version: 22-Feb-2021
Text moved to lines 622-624 
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
// solhint-disable avoid-low-level-calls
// solhint-disable no-inline-assembly
// solhint-disable not-rely-on-time
// File @boringcrypto/boring-solidity/contracts/libraries/BoringMath.sol@v1.2.0
// File @boringcrypto/boring-solidity/contracts/libraries/BoringMath.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
/// @notice A library for performing overflow-/underflow-safe math,
/// @notice A library for performing overflow-/underflow-safe math,
/// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math).
/// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math).
library BoringMath {
library BoringMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
    function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow");
        require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow");
    }
    }
    function to128(uint256 a) internal pure returns (uint128 c) {
    function to128(uint256 a) internal pure returns (uint128 c) {
        require(a <= uint128(-1), "BoringMath: uint128 Overflow");
        require(a <= uint128(-1), "BoringMath: uint128 Overflow");
        c = uint128(a);
        c = uint128(a);
    }
    }
    function to64(uint256 a) internal pure returns (uint64 c) {
    function to64(uint256 a) internal pure returns (uint64 c) {
        require(a <= uint64(-1), "BoringMath: uint64 Overflow");
        require(a <= uint64(-1), "BoringMath: uint64 Overflow");
        c = uint64(a);
        c = uint64(a);
    }
    }
    function to32(uint256 a) internal pure returns (uint32 c) {
    function to32(uint256 a) internal pure returns (uint32 c) {
        require(a <= uint32(-1), "BoringMath: uint32 Overflow");
        require(a <= uint32(-1), "BoringMath: uint32 Overflow");
        c = uint32(a);
        c = uint32(a);
    }
    }
}
}
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128.
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128.
library BoringMath128 {
library BoringMath128 {
    function add(uint128 a, uint128 b) internal pure returns (uint128 c) {
    function add(uint128 a, uint128 b) internal pure returns (uint128 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }
    }
    function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {
    function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
    }
}
}
// File @boringcrypto/boring-solidity/contracts/BoringOwnable.sol@v1.2.0
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint64.
library BoringMath64 {
    function add(uint64 a, uint64 b) internal pure returns (uint64 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }
    function sub(uint64 a, uint64 b) internal pure returns (uint64 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
}
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint32.
library BoringMath32 {
    function add(uint32 a, uint32 b) internal pure returns (uint32 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }
    function sub(uint32 a, uint32 b) internal pure returns (uint32 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
}
// File @boringcrypto/boring-solidity/contracts/BoringOwnable.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
// Audit on 5-Jan-2021 by Keno and BoringCrypto
// Audit on 5-Jan-2021 by Keno and BoringCrypto
// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
// Edited by BoringCrypto
// Edited by BoringCrypto
contract BoringOwnableData {
contract BoringOwnableData {
    address public owner;
    address public owner;
    address public pendingOwner;
    address public pendingOwner;
}
}
contract BoringOwnable is BoringOwnableData {
contract BoringOwnable is BoringOwnableData {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    /// @notice `owner` defaults to msg.sender on construction.
    /// @notice `owner` defaults to msg.sender on construction.
    constructor() public {
    constructor() public {
        owner = msg.sender;
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
        emit OwnershipTransferred(address(0), msg.sender);
    }
    }
    /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
    /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
    /// Can only be invoked by the current `owner`.
    /// Can only be invoked by the current `owner`.
    /// @param newOwner Address of the new owner.
    /// @param newOwner Address of the new owner.
    /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
    /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
    /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
    /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
    function transferOwnership(
    function transferOwnership(
        address newOwner,
        address newOwner,
        bool direct,
        bool direct,
        bool renounce
        bool renounce
    ) public onlyOwner {
    ) public onlyOwner {
        if (direct) {
        if (direct) {
            // Checks
            // Checks
            require(newOwner != address(0) || renounce, "Ownable: zero address");
            require(newOwner != address(0) || renounce, "Ownable: zero address");
            // Effects
            // Effects
            emit OwnershipTransferred(owner, newOwner);
            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
            owner = newOwner;
            pendingOwner = address(0);
            pendingOwner = address(0);
        } else {
        } else {
            // Effects
            // Effects
            pendingOwner = newOwner;
            pendingOwner = newOwner;
        }
        }
    }
    }
    /// @notice Needs to be called by `pendingOwner` to claim ownership.
    /// @notice Needs to be called by `pendingOwner` to claim ownership.
    function claimOwnership() public {
    function claimOwnership() public {
        address _pendingOwner = pendingOwner;
        address _pendingOwner = pendingOwner;
        // Checks
        // Checks
        require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
        require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
        // Effects
        // Effects
        emit OwnershipTransferred(owner, _pendingOwner);
        emit OwnershipTransferred(owner, _pendingOwner);
        owner = _pendingOwner;
        owner = _pendingOwner;
        pendingOwner = address(0);
        pendingOwner = address(0);
    }
    }
    /// @notice Only allows the `owner` to execute the function.
    /// @notice Only allows the `owner` to execute the function.
    modifier onlyOwner() {
    modifier onlyOwner() {
        require(msg.sender == owner, "Ownable: caller is not the owner");
        require(msg.sender == owner, "Ownable: caller is not the owner");
        _;
        _;
    }
    }
}
}
// File @boringcrypto/boring-solidity/contracts/Domain.sol@v1.2.0
// File @boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol@v1.2.2
// License-Identifier: MIT
Text moved with changes from lines 403-412 (96.7% similarity)
pragma solidity 0.6.12;
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
Text moved from lines 417-426 
    /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}
// File @boringcrypto/boring-solidity/contracts/Domain.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
// Based on code and smartness by Ross Campbell and Keno
// Based on code and smartness by Ross Campbell and Keno
// Uses immutable to store the domain separator to reduce gas usage
// Uses immutable to store the domain separator to reduce gas usage
// If the chain id changes due to a fork, the forked chain will calculate on the fly.
// If the chain id changes due to a fork, the forked chain will calculate on the fly.
pragma solidity 0.6.12;
// solhint-disable no-inline-assembly
contract Domain {
contract Domain {
    bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
    bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
    // See https://eips.ethereum.org/EIPS/eip-191
    // See https://eips.ethereum.org/EIPS/eip-191
    string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";
    string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";
    // solhint-disable var-name-mixedcase
    // solhint-disable var-name-mixedcase
    bytes32 private immutable _DOMAIN_SEPARATOR;
    bytes32 private immutable _DOMAIN_SEPARATOR;
    uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID;
    uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID;    
    /// @dev Calculate the DOMAIN_SEPARATOR
    /// @dev Calculate the DOMAIN_SEPARATOR
    function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
    function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
        return keccak256(abi.encode(DOMAIN_SEPARATOR_SIGNATURE_HASH, chainId, address(this)));
        return keccak256(
            abi.encode(
                DOMAIN_SEPARATOR_SIGNATURE_HASH,
                chainId,
                address(this)
            )
        );
    }
    }
    constructor() public {
    constructor() public {
        uint256 chainId;
        uint256 chainId; assembly {chainId := chainid()}
        assembly {
            chainId := chainid()
        }
        _DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = chainId);
        _DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = chainId);
    }
    }
    /// @dev Return the DOMAIN_SEPARATOR
    /// @dev Return the DOMAIN_SEPARATOR
    // It's named internal to allow making it public from the contract that uses it by creating a simple view function
    // It's named internal to allow making it public from the contract that uses it by creating a simple view function
    // with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator.
    // with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator.
    // solhint-disable-next-line func-name-mixedcase
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() public view returns (bytes32) {
    function _domainSeparator() internal view returns (bytes32) {
        uint256 chainId;
        uint256 chainId; assembly {chainId := chainid()}
        assembly {
            chainId := chainid()
        }
        return chainId == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(chainId);
        return chainId == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(chainId);
    }
    }
    function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) {
    function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) {
        digest = keccak256(abi.encodePacked(EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, DOMAIN_SEPARATOR(), dataHash));
        digest =
            keccak256(
                abi.encodePacked(
                    EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA,
                    _domainSeparator(),
                    dataHash
                )
            );
    }
    }
}
}
// File @boringcrypto/boring-solidity/contracts/ERC20.sol@v1.2.0
// File @boringcrypto/boring-solidity/contracts/ERC20.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
// solhint-disable no-inline-assembly
// solhint-disable no-inline-assembly
// solhint-disable not-rely-on-time
// solhint-disable not-rely-on-time
// Data part taken out for building of contracts that receive delegate calls
// Data part taken out for building of contracts that receive delegate calls
contract ERC20Data {
contract ERC20Data {
    /// @notice owner > balance mapping.
    /// @notice owner > balance mapping.
    mapping(address => uint256) public balanceOf;
    mapping(address => uint256) public balanceOf;
    /// @notice owner > spender > allowance mapping.
    /// @notice owner > spender > allowance mapping.
    mapping(address => mapping(address => uint256)) public allowance;
    mapping(address => mapping(address => uint256)) public allowance;
    /// @notice owner > nonce mapping. Used in `permit`.
    /// @notice owner > nonce mapping. Used in `permit`.
    mapping(address => uint256) public nonces;
    mapping(address => uint256) public nonces;
}
}
contract ERC20 is ERC20Data, Domain {
abstract contract ERC20 is IERC20, Domain {
    /// @notice owner > balance mapping.
    mapping(address => uint256) public override balanceOf;
    /// @notice owner > spender > allowance mapping.
    mapping(address => mapping(address => uint256)) public override allowance;
    /// @notice owner > nonce mapping. Used in `permit`.
    mapping(address => uint256) public nonces;
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    /// @notice Transfers `amount` tokens from `msg.sender` to `to`.
    /// @notice Transfers `amount` tokens from `msg.sender` to `to`.
    /// @param to The address to move the tokens.
    /// @param to The address to move the tokens.
    /// @param amount of the tokens to move.
    /// @param amount of the tokens to move.
    /// @return (bool) Returns True if succeeded.
    /// @return (bool) Returns True if succeeded.
    function transfer(address to, uint256 amount) public returns (bool) {
    function transfer(address to, uint256 amount) public returns (bool) {
        // If `amount` is 0, or `msg.sender` is `to` nothing happens
        // If `amount` is 0, or `msg.sender` is `to` nothing happens
        if (amount != 0) {
        if (amount != 0 || msg.sender == to) {
            uint256 srcBalance = balanceOf[msg.sender];
            uint256 srcBalance = balanceOf[msg.sender];
            require(srcBalance >= amount, "ERC20: balance too low");
            require(srcBalance >= amount, "ERC20: balance too low");
            if (msg.sender != to) {
            if (msg.sender != to) {
                require(to != address(0), "ERC20: no zero address"); // Moved down so low balance calls safe some gas
                require(to != address(0), "ERC20: no zero address"); // Moved down so low balance calls safe some gas
                balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked
                balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked
                balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1
                balanceOf[to] += amount;
            }
            }
        }
        }
        emit Transfer(msg.sender, to, amount);
        emit Transfer(msg.sender, to, amount);
        return true;
        return true;
    }
    }
    /// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.
    /// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.
    /// @param from Address to draw tokens from.
    /// @param from Address to draw tokens from.
    /// @param to The address to move the tokens.
    /// @param to The address to move the tokens.
    /// @param amount The token amount to move.
    /// @param amount The token amount to move.
    /// @return (bool) Returns True if succeeded.
    /// @return (bool) Returns True if succeeded.
    function transferFrom(
    function transferFrom(
        address from,
        address from,
        address to,
        address to,
        uint256 amount
        uint256 amount
    ) public returns (bool) {
    ) public returns (bool) {
        // If `amount` is 0, or `from` is `to` nothing happens
        // If `amount` is 0, or `from` is `to` nothing happens
        if (amount != 0) {
        if (amount != 0) {
            uint256 srcBalance = balanceOf[from];
            uint256 srcBalance = balanceOf[from];
            require(srcBalance >= amount, "ERC20: balance too low");
            require(srcBalance >= amount, "ERC20: balance too low");
            if (from != to) {
            if (from != to) {
                uint256 spenderAllowance = allowance[from][msg.sender];
                uint256 spenderAllowance = allowance[from][msg.sender];
                // If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
                // If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
                if (spenderAllowance != type(uint256).max) {
                if (spenderAllowance != type(uint256).max) {
                    require(spenderAllowance >= amount, "ERC20: allowance too low");
                    require(spenderAllowance >= amount, "ERC20: allowance too low");
                    allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked
                    allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked
                }
                }
                require(to != address(0), "ERC20: no zero address"); // Moved down so other failed calls safe some gas
                require(to != address(0), "ERC20: no zero address"); // Moved down so other failed calls safe some gas
                balanceOf[from] = srcBalance - amount; // Underflow is checked
                balanceOf[from] = srcBalance - amount; // Underflow is checked
                balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1
                balanceOf[to] += amount;
            }
            }
        }
        }
        emit Transfer(from, to, amount);
        emit Transfer(from, to, amount);
        return true;
        return true;
    }
    }
    /// @notice Approves `amount` from sender to be spend by `spender`.
    /// @notice Approves `amount` from sender to be spend by `spender`.
    /// @param spender Address of the party that can draw from msg.sender's account.
    /// @param spender Address of the party that can draw from msg.sender's account.
    /// @param amount The maximum collective amount that `spender` can draw.
    /// @param amount The maximum collective amount that `spender` can draw.
    /// @return (bool) Returns True if approved.
    /// @return (bool) Returns True if approved.
    function approve(address spender, uint256 amount) public returns (bool) {
    function approve(address spender, uint256 amount) public override returns (bool) {
        allowance[msg.sender][spender] = amount;
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        emit Approval(msg.sender, spender, amount);
        return true;
        return true;
    }
    }
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32) {
        return _domainSeparator();
    }
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    /// @notice Approves `value` from `owner_` to be spend by `spender`.
    /// @notice Approves `value` from `owner_` to be spend by `spender`.
    /// @param owner_ Address of the owner.
    /// @param owner_ Address of the owner.
    /// @param spender The address of the spender that gets approved to draw from `owner_`.
    /// @param spender The address of the spender that gets approved to draw from `owner_`.
    /// @param value The maximum collective amount that `spender` can draw.
    /// @param value The maximum collective amount that `spender` can draw.
    /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
    /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
    function permit(
    function permit(
        address owner_,
        address owner_,
        address spender,
        address spender,
        uint256 value,
        uint256 value,
        uint256 deadline,
        uint256 deadline,
        uint8 v,
        uint8 v,
        bytes32 r,
        bytes32 r,
        bytes32 s
        bytes32 s
    ) external {
    ) external override {
        require(owner_ != address(0), "ERC20: Owner cannot be 0");
        require(owner_ != address(0), "ERC20: Owner cannot be 0");
        require(block.timestamp < deadline, "ERC20: Expired");
        require(block.timestamp < deadline, "ERC20: Expired");
        require(
        require(
            ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) ==
            ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) ==
                owner_,
                owner_,
            "ERC20: Invalid Signature"
            "ERC20: Invalid Signature"
        );
        );
        allowance[owner_][spender] = value;
        allowance[owner_][spender] = value;
        emit Approval(owner_, spender, value);
        emit Approval(owner_, spender, value);
    }
    }
}
}
// File @boringcrypto/boring-solidity/contracts/interfaces/IMasterContract.sol@v1.2.0
contract ERC20WithSupply is IERC20, ERC20 {
    uint256 public override totalSupply;
    function _mint(address user, uint256 amount) private {
        uint256 newTotalSupply = totalSupply + amount;
        require(newTotalSupply >= totalSupply, "Mint overflow");
        totalSupply = newTotalSupply;
        balanceOf[user] += amount;
    }
    function _burn(address user, uint256 amount) private {
        require(balanceOf[user] >= amount, "Burn too much");
        totalSupply -= amount;
        balanceOf[user] -= amount;
    }
}
// File @boringcrypto/boring-solidity/contracts/interfaces/IMasterContract.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
interface IMasterContract {
interface IMasterContract {
    /// @notice Init function that gets called from `BoringFactory.deploy`.
    /// @notice Init function that gets called from `BoringFactory.deploy`.
    /// Also kown as the constructor for cloned contracts.
    /// Also kown as the constructor for cloned contracts.
    /// Any ETH send to `BoringFactory.deploy` ends up here.
    /// Any ETH send to `BoringFactory.deploy` ends up here.
    /// @param data Can be abi encoded arguments or anything else.
    /// @param data Can be abi encoded arguments or anything else.
    function init(bytes calldata data) external payable;
    function init(bytes calldata data) external payable;
}
}
// File @boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol@v1.2.0
// File @boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
struct Rebase {
struct Rebase {
    uint128 elastic;
    uint128 elastic;
    uint128 base;
    uint128 base;
}
}
/// @notice A rebasing library using overflow-/underflow-safe math.
/// @notice A rebasing library using overflow-/underflow-safe math.
library RebaseLibrary {
library RebaseLibrary {
    using BoringMath for uint256;
    using BoringMath for uint256;
    using BoringMath128 for uint128;
    using BoringMath128 for uint128;
    /// @notice Calculates the base value in relationship to `elastic` and `total`.
    /// @notice Calculates the base value in relationship to `elastic` and `total`.
    function toBase(
    function toBase(
        Rebase memory total,
        Rebase memory total,
        uint256 elastic,
        uint256 elastic,
        bool roundUp
        bool roundUp
    ) internal pure returns (uint256 base) {
    ) internal pure returns (uint256 base) {
        if (total.elastic == 0) {
        if (total.elastic == 0) {
            base = elastic;
            base = elastic;
        } else {
        } else {
            base = elastic.mul(total.base) / total.elastic;
            base = elastic.mul(total.base) / total.elastic;
            if (roundUp && base.mul(total.elastic) / total.base < elastic) {
            if (roundUp && base.mul(total.elastic) / total.base < elastic) {
                base = base.add(1);
                base = base.add(1);
            }
            }
        }
        }
    }
    }
    /// @notice Calculates the elastic value in relationship to `base` and `total`.
    /// @notice Calculates the elastic value in relationship to `base` and `total`.
    function toElastic(
    function toElastic(
        Rebase memory total,
        Rebase memory total,
        uint256 base,
        uint256 base,
        bool roundUp
        bool roundUp
    ) internal pure returns (uint256 elastic) {
    ) internal pure returns (uint256 elastic) {
        if (total.base == 0) {
        if (total.base == 0) {
            elastic = base;
            elastic = base;
        } else {
        } else {
            elastic = base.mul(total.elastic) / total.base;
            elastic = base.mul(total.elastic) / total.base;
            if (roundUp && elastic.mul(total.base) / total.elastic < base) {
            if (roundUp && elastic.mul(total.base) / total.elastic < base) {
                elastic = elastic.add(1);
                elastic = elastic.add(1);
            }
            }
        }
        }
    }
    }
    /// @notice Add `elastic` to `total` and doubles `total.base`.
    /// @notice Add `elastic` to `total` and doubles `total.base`.
    /// @return (Rebase) The new total.
    /// @return (Rebase) The new total.
    /// @return base in relationship to `elastic`.
    /// @return base in relationship to `elastic`.
    function add(
    function add(
        Rebase memory total,
        Rebase memory total,
        uint256 elastic,
        uint256 elastic,
        bool roundUp
        bool roundUp
    ) internal pure returns (Rebase memory, uint256 base) {
    ) internal pure returns (Rebase memory, uint256 base) {
        base = toBase(total, elastic, roundUp);
        base = toBase(total, elastic, roundUp);
        total.elastic = total.elastic.add(elastic.to128());
        total.elastic = total.elastic.add(elastic.to128());
        total.base = total.base.add(base.to128());
        total.base = total.base.add(base.to128());
        return (total, base);
        return (total, base);
    }
    }
    /// @notice Sub `base` from `total` and update `total.elastic`.
    /// @notice Sub `base` from `total` and update `total.elastic`.
    /// @return (Rebase) The new total.
    /// @return (Rebase) The new total.
    /// @return elastic in relationship to `base`.
    /// @return elastic in relationship to `base`.
    function sub(
    function sub(
        Rebase memory total,
        Rebase memory total,
        uint256 base,
        uint256 base,
        bool roundUp
        bool roundUp
    ) internal pure returns (Rebase memory, uint256 elastic) {
    ) internal pure returns (Rebase memory, uint256 elastic) {
        elastic = toElastic(total, base, roundUp);
        elastic = toElastic(total, base, roundUp);
        total.elastic = total.elastic.sub(elastic.to128());
        total.elastic = total.elastic.sub(elastic.to128());
        total.base = total.base.sub(base.to128());
        total.base = total.base.sub(base.to128());
        return (total, elastic);
        return (total, elastic);
    }
    }
    /// @notice Add `elastic` and `base` to `total`.
    /// @notice Add `elastic` and `base` to `total`.
    function add(
    function add(
        Rebase memory total,
        Rebase memory total,
        uint256 elastic,
        uint256 elastic,
        uint256 base
        uint256 base
    ) internal pure returns (Rebase memory) {
    ) internal pure returns (Rebase memory) {
        total.elastic = total.elastic.add(elastic.to128());
        total.elastic = total.elastic.add(elastic.to128());
        total.base = total.base.add(base.to128());
        total.base = total.base.add(base.to128());
        return total;
        return total;
    }
    }
    /// @notice Subtract `elastic` and `base` to `total`.
    /// @notice Subtract `elastic` and `base` to `total`.
    function sub(
    function sub(
        Rebase memory total,
        Rebase memory total,
        uint256 elastic,
        uint256 elastic,
        uint256 base
        uint256 base
    ) internal pure returns (Rebase memory) {
    ) internal pure returns (Rebase memory) {
        total.elastic = total.elastic.sub(elastic.to128());
        total.elastic = total.elastic.sub(elastic.to128());
        total.base = total.base.sub(base.to128());
        total.base = total.base.sub(base.to128());
        return total;
        return total;
    }
    }
}
// File @boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol@v1.2.0
Text moved with changes to lines 143-152 (96.7% similarity)
// License-Identifier: MIT
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    /// @notice Add `elastic` to `total` and update storage.
    event Approval(address indexed owner, address indexed spender, uint256 value);
    /// @return newElastic Returns updated `elastic`.
    function addElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) {
        newElastic = total.elastic = total.elastic.add(elastic.to128());
    }
Text moved to lines 157-166 
    /// @notice EIP 2612
    /// @notice Subtract `elastic` from `total` and update storage.
    function permit(
    /// @return newElastic Returns updated `elastic`.
        address owner,
    function subElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) {
        address spender,
        newElastic = total.elastic = total.elastic.sub(elastic.to128());
        uint256 value,
    }
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}
}
// File @boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol@v1.2.0
// File @boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol@v1.2.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
// solhint-disable avoid-low-level-calls
library BoringERC20 {
library BoringERC20 {
    bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()
    bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()
    bytes4 private constant SIG_NAME = 0x06fdde03; // name()
    bytes4 private constant SIG_NAME = 0x06fdde03; // name()
    bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()
    bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()
    bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256)
    bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256)
    bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256)
    bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256)
    function returnDataToString(bytes memory data) internal pure returns (string memory) {
    function returnDataToString(bytes memory data) internal pure returns (string memory) {
        if (data.length >= 64) {
        if (data.length >= 64) {
            return abi.decode(data, (string));
            return abi.decode(data, (string));
        } else if (data.length == 32) {
        } else if (data.length == 32) {
            uint8 i = 0;
            uint8 i = 0;
            while (i < 32 && data[i] != 0) {
            while(i < 32 && data[i] != 0) {
                i++;
                i++;
            }
            }
            bytes memory bytesArray = new bytes(i);
            bytes memory bytesArray = new bytes(i);
            for (i = 0; i < 32 && data[i] != 0; i++) {
            for (i = 0; i < 32 && data[i] != 0; i++) {
                bytesArray[i] = data[i];
                bytesArray[i] = data[i];
            }
            }
            return string(bytesArray);
            return string(bytesArray);
        } else {
        } else {
            return "???";
            return "???";
        }
        }
    }
    }
    /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.
    /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token symbol.
    /// @return (string) Token symbol.
    function safeSymbol(IERC20 token) internal view returns (string memory) {
    function safeSymbol(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));
        return success ? returnDataToString(data) : "???";
        return success ? returnDataToString(data) : "???";
    }
    }
    /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.
    /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token name.
    /// @return (string) Token name.
    function safeName(IERC20 token) internal view returns (string memory) {
    function safeName(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));
        return success ? returnDataToString(data) : "???";
        return success ? returnDataToString(data) : "???";
    }
    }
    /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
    /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
    /// @param token The address of the ERC-20 token contract.
    /// @param token The address of the ERC-20 token contract.
    /// @return (uint8) Token decimals.
    /// @return (uint8) Token decimals.
    function safeDecimals(IERC20 token) internal view returns (uint8) {
    function safeDecimals(IERC20 token) internal view returns (uint8) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));
        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
    }
    }
    /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations.
    /// Reverts on a failed transfer.
    /// @param token The address of the ERC-20 token.
    /// @param to Transfer tokens to.
    /// @param amount The token amount.
    function safeTransfer(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER, to, amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed");
    }
    /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations.
    /// Reverts on a failed transfer.
    /// @param token The address of the ERC-20 token.
    /// @param from Transfer tokens from.
    /// @param to Transfer tokens to.
    /// @param amount The token amount.
Text moved with changes from lines 601-606 (91.4% similarity)
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed");
    }
}
}
// File @sushiswap/bentobox-sdk/contracts/IBatchFlashBorrower.sol@v1.0.1
// File @sushiswap/bentobox-sdk/contracts/IBatchFlashBorrower.sol@v1.0.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
interface IBatchFlashBorrower {
interface IBatchFlashBorrower {
    function onBatchFlashLoan(
    function onBatchFlashLoan(
        address sender,
        address sender,
        IERC20[] calldata tokens,
        IERC20[] calldata tokens,
        uint256[] calldata amounts,
        uint256[] calldata amounts,
        uint256[] calldata fees,
        uint256[] calldata fees,
        bytes calldata data
        bytes calldata data
    ) external;
    ) external;
}
}
// File @sushiswap/bentobox-sdk/contracts/IFlashBorrower.sol@v1.0.1
// File @sushiswap/bentobox-sdk/contracts/IFlashBorrower.sol@v1.0.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
interface IFlashBorrower {
interface IFlashBorrower {
    function onFlashLoan(
    function onFlashLoan(
        address sender,
        address sender,
        IERC20 token,
        IERC20 token,
        uint256 amount,
        uint256 amount,
        uint256 fee,
        uint256 fee,
        bytes calldata data
        bytes calldata data
    ) external;
    ) external;
}
}
// File @sushiswap/bentobox-sdk/contracts/IStrategy.sol@v1.0.1
// File @sushiswap/bentobox-sdk/contracts/IStrategy.sol@v1.0.2
// License-Identifier: MIT
// License-Identifier: MIT
pragma solidity 0.6.12;
interface IStrategy {
interface IStrategy {
    // Send the assets to the Strategy and call skim to invest them
    // Send the assets to the Strategy and call skim to invest them
    function skim(uint256 amount) external;
    function skim(uint256 amount) external;
    // Harvest any profits made converted to the asset and pass them to the caller
    // Harvest any profits made converted to the asset and pass them to the caller
    function harvest(uint256 balance, address sender) external returns (int256 amountAdded);
    function harvest(uint256 balance, address sender) external returns (int256 amountAdded);
    // Withdraw assets. The returned amount can differ from the requested amount due to rounding.
    // Withdraw assets. The returned amount can differ from the requested amount due to rounding.
    // The actualAmount should be very close to the amount. The difference should NOT be used to report a loss. That's what harvest is for.
    // The actualAmount should be very close to the amount. The difference should NOT be used to report a loss. That's what harvest is for.
    function withdraw(uint256 amount) external returns (uint256 actualAmount);
    function withdraw(uint256 amount) external returns (uint256 actualAmount);
    // Withdraw all assets in the safest way possible. This shouldn't fail.
    // Withdraw all assets in the safest way possible. This shouldn't fail.
    function exit(uint256 balance) external returns (int256 amountAdded);
    function exit(uint256 balance) external returns (int256 amountAdded);
}
}
// File @sushiswap/bentobox-sdk/contracts/IBentoBoxV1.sol@v1.0.1
// File @sushiswap/bentobox-sdk/contracts/IBentoBoxV1.sol@v1.0.2
// License-Identifier: MIT
// License-Identifier: MIT
Text moved from lines 22-24 
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
interface IBentoBoxV1 {
interface IBentoBoxV1 {
    event LogDeploy(address indexed masterContract, bytes data, address indexed cloneAddress);
    event LogDeploy(address indexed masterContract, bytes data, address indexed cloneAddress);
    event LogDeposit(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);
    event LogDeposit(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);
    event LogFlashLoan(address indexed borrower, address indexed token, uint256 amount, uint256 feeAmount, address indexed receiver);
    event LogFlashLoan(address indexed borrower, address indexed token, uint256 amount, uint256 feeAmount, address indexed receiver);
    event LogRegisterProtocol(address indexed protocol);
    event LogRegisterProtocol(address indexed protocol);
    event LogSetMasterContractApproval(address indexed masterContract, address indexed user, bool approved);
    event LogSetMasterContractApproval(address indexed masterContract, address indexed user, bool approved);
    event LogStrategyDivest(address indexed token, uint256 amount);
    event LogStrategyDivest(address indexed token, uint256 amount);
    event LogStrategyInvest(address indexed token, uint256 amount);
    event LogStrategyInvest(address indexed token, uint256 amount);
    event LogStrategyLoss(address indexed token, uint256 amount);
    event LogStrategyLoss(address indexed token, uint256 amount);
    event LogStrategyProfit(address indexed token, uint256 amount);
    event LogStrategyProfit(address indexed token, uint256 amount);
    event LogStrategyQueued(address indexed token, address indexed strategy);
    event LogStrategyQueued(address indexed token, address indexed strategy);
    event LogStrategySet(address indexed token, address indexed strategy);
    event LogStrategySet(address indexed token, address indexed strategy);
    event LogStrategyTargetPercentage(address indexed token, uint256 targetPercentage);
    event LogStrategyTargetPercentage(address indexed token, uint256 targetPercentage);
    event LogTransfer(address indexed token, address indexed from, address indexed to, uint256 share);
    event LogTransfer(address indexed token, address indexed from, address indexed to, uint256 share);
    event LogWhiteListMasterContract(address indexed masterContract, bool approved);
    event LogWhiteListMasterContract(address indexed masterContract, bool approved);
    event LogWithdraw(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);
    event LogWithdraw(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    function balanceOf(IERC20, address) external view returns (uint
    function balanceOf(IERC20, address) external view returns (uint256);
    function batch(bytes[] calldata calls, bool revertOnFail) external payable returns (bool[] memory successes, bytes[] memory results);
    function batchFlashLoan(
        IBatchFlashBorrower borrower,
        address[] calldata receivers,
        IERC20[] calldata tokens,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
    function claimOwnership() external;
    function deploy(
        address masterContract,
        bytes calldata data,
        bool useCreate2
    ) external payable;
    function deposit(
        IERC20 token_,
        address from,
        address to,
        uint256 amount,
        uint256 share
    ) external payable returns (uint256 amountOut, uint256 shareOut);
    function flashLoan(
        IFlashBorrower borrower,
        address receiver,
        IERC20 token,
        uint256 amount,
        bytes calldata data
    ) external;
    function harvest(
        IERC20 token,
        bool balance,
        uint256 maxChangeAmount
    ) external;
    function masterContractApproved(address, address) external view returns (bool);
    function masterContractOf(address) external view returns (address);
    function nonces(address) external view returns (uint256);
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function pendingStrategy(IERC20) external view returns (IStrategy);
Text moved with changes to lines 562-567 (91.4% similarity)
    function permitToken(
        IERC20 token,
        address from,
        address to,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
    function registerProtocol() external;
    function setMasterContractApproval(
        address user,
        address masterContract,
        bool approved,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
    function setStrategy(IERC20 token, IStrategy newStrategy) external;
    function setStrategyTargetPercentage(IERC20 token, uint64 targetPercentage_) external;
    function strategy(IERC20) external view returns (IStrategy);
    function strategyData(IERC20)
        external
        view
        returns (
            uint64 strategyStartDate,
            uint64 targetPercentage,
            uint128 balance
        );
    function toAmount(
        IERC20 token,
        uint256 share,
        bool roundUp
    ) external view returns (uint256 amount);
    function toShare(
        IERC20 token,
        uint256 amount,
        bool roundUp
    ) external view returns (uint256 share);
    function totals(IERC20) external view returns (Rebase memory totals_);
    function transfer(
        IERC20 token,
        address from,
        address to,
        uint256 share
    ) external;
    function transferMultiple(
        IERC20 token,
        address from,
        address[] calldata tos,
        uint256[] calldata shares
    ) external;
    function transferOwnership(
        address newOwner,
        bool direct,
        bool renounce
    ) external;
    function whitelistMasterContract(address masterContract, bool approved) external;
    function whitelistedMasterContracts(address) external view returns (bool);
    function withdraw(
        IERC20 token_,
        address from,
        address to,
        uint256 amount,