Kashi <> Cauldron

Created Diff never expires
/**
/**
*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
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
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);

/// @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
/// @notice Add `elastic` to `total` and update storage.
// License-Identifier: MIT
/// @return newElastic Returns updated `elastic`.

function addElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) {
interface IERC20 {
newElastic = total.elastic = total.elastic.add(elastic.to128());
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);


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

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,