UNPKG

@luckyfinance/core

Version:

Core contracts for the LuckySwap protocol

10 lines 5.4 MB
{ "id": "2fb09a6fa5875a05bc375fa4deed14ed", "_format": "hh-sol-build-info-1", "solcVersion": "0.6.12", "solcLongVersion": "0.6.12+commit.27d51765", "input": { "language": "Solidity", "sources": { "contracts/alpine/GoldVeinPairMediumRiskV1.sol": { "content": "// SPDX-License-Identifier: UNLICENSED\n// Gold Vein Lending Medium Risk\n\n// Copyright (c) 2021 BoringCrypto - All rights reserved\n// Twitter: @Boring_Crypto\n\n// Special thanks to:\n// @0xKeno - for all his invaluable contributions\n// @burger_crypto - for the idea of trying to let the LPs benefit from liquidations\n\n// Version: 22-Feb-2021\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n// solhint-disable avoid-low-level-calls\n// solhint-disable no-inline-assembly\n// solhint-disable not-rely-on-time\n\n// File @boringcrypto/boring-solidity/contracts/libraries/BoringMath.sol@v1.2.0\n// License-Identifier: MIT\n\n/// @notice A library for performing overflow-/underflow-safe math,\n/// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math).\nlibrary BoringMath {\n function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require((c = a + b) >= b, \"BoringMath: Add Overflow\");\n }\n\n function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require((c = a - b) <= a, \"BoringMath: Underflow\");\n }\n\n function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require(b == 0 || (c = a * b) / b == a, \"BoringMath: Mul Overflow\");\n }\n\n function to128(uint256 a) internal pure returns (uint128 c) {\n require(a <= uint128(-1), \"BoringMath: uint128 Overflow\");\n c = uint128(a);\n }\n\n function to64(uint256 a) internal pure returns (uint64 c) {\n require(a <= uint64(-1), \"BoringMath: uint64 Overflow\");\n c = uint64(a);\n }\n\n function to32(uint256 a) internal pure returns (uint32 c) {\n require(a <= uint32(-1), \"BoringMath: uint32 Overflow\");\n c = uint32(a);\n }\n}\n\n/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128.\nlibrary BoringMath128 {\n function add(uint128 a, uint128 b) internal pure returns (uint128 c) {\n require((c = a + b) >= b, \"BoringMath: Add Overflow\");\n }\n\n function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {\n require((c = a - b) <= a, \"BoringMath: Underflow\");\n }\n}\n\n// File @boringcrypto/boring-solidity/contracts/BoringOwnable.sol@v1.2.0\n// License-Identifier: MIT\n\n// Audit on 5-Jan-2021 by Keno and BoringCrypto\n// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol\n// Edited by BoringCrypto\n\ncontract BoringOwnableData {\n address public owner;\n address public pendingOwner;\n}\n\ncontract BoringOwnable is BoringOwnableData {\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /// @notice `owner` defaults to msg.sender on construction.\n constructor() public {\n owner = msg.sender;\n emit OwnershipTransferred(address(0), msg.sender);\n }\n\n /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.\n /// Can only be invoked by the current `owner`.\n /// @param newOwner Address of the new owner.\n /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.\n /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.\n function transferOwnership(\n address newOwner,\n bool direct,\n bool renounce\n ) public onlyOwner {\n if (direct) {\n // Checks\n require(newOwner != address(0) || renounce, \"Ownable: zero address\");\n\n // Effects\n emit OwnershipTransferred(owner, newOwner);\n owner = newOwner;\n pendingOwner = address(0);\n } else {\n // Effects\n pendingOwner = newOwner;\n }\n }\n\n /// @notice Needs to be called by `pendingOwner` to claim ownership.\n function claimOwnership() public {\n address _pendingOwner = pendingOwner;\n\n // Checks\n require(msg.sender == _pendingOwner, \"Ownable: caller != pending owner\");\n\n // Effects\n emit OwnershipTransferred(owner, _pendingOwner);\n owner = _pendingOwner;\n pendingOwner = address(0);\n }\n\n /// @notice Only allows the `owner` to execute the function.\n modifier onlyOwner() {\n require(msg.sender == owner, \"Ownable: caller is not the owner\");\n _;\n }\n}\n\n// File @boringcrypto/boring-solidity/contracts/Domain.sol@v1.2.0\n// License-Identifier: MIT\n// Based on code and smartness by Ross Campbell and Keno\n// Uses immutable to store the domain separator to reduce gas usage\n// If the chain id changes due to a fork, the forked chain will calculate on the fly.\n\ncontract Domain {\n bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256(\"EIP712Domain(uint256 chainId,address verifyingContract)\");\n // See https://eips.ethereum.org/EIPS/eip-191\n string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = \"\\x19\\x01\";\n\n // solhint-disable var-name-mixedcase\n bytes32 private immutable _DOMAIN_SEPARATOR;\n uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID;\n\n /// @dev Calculate the DOMAIN_SEPARATOR\n function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {\n return keccak256(abi.encode(DOMAIN_SEPARATOR_SIGNATURE_HASH, chainId, address(this)));\n }\n\n constructor() public {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n _DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = chainId);\n }\n\n /// @dev Return the DOMAIN_SEPARATOR\n // It's named internal to allow making it public from the contract that uses it by creating a simple view function\n // with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator.\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(chainId);\n }\n\n function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) {\n digest = keccak256(abi.encodePacked(EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, DOMAIN_SEPARATOR(), dataHash));\n }\n}\n\n// File @boringcrypto/boring-solidity/contracts/ERC20.sol@v1.2.0\n// License-Identifier: MIT\n\n// solhint-disable no-inline-assembly\n// solhint-disable not-rely-on-time\n\n// Data part taken out for building of contracts that receive delegate calls\ncontract ERC20Data {\n /// @notice owner > balance mapping.\n mapping(address => uint256) public balanceOf;\n /// @notice owner > spender > allowance mapping.\n mapping(address => mapping(address => uint256)) public allowance;\n /// @notice owner > nonce mapping. Used in `permit`.\n mapping(address => uint256) public nonces;\n}\n\ncontract ERC20 is ERC20Data, Domain {\n event Transfer(address indexed _from, address indexed _to, uint256 _value);\n event Approval(address indexed _owner, address indexed _spender, uint256 _value);\n\n /// @notice Transfers `amount` tokens from `msg.sender` to `to`.\n /// @param to The address to move the tokens.\n /// @param amount of the tokens to move.\n /// @return (bool) Returns True if succeeded.\n function transfer(address to, uint256 amount) public returns (bool) {\n // If `amount` is 0, or `msg.sender` is `to` nothing happens\n if (amount != 0) {\n uint256 srcBalance = balanceOf[msg.sender];\n require(srcBalance >= amount, \"ERC20: balance too low\");\n if (msg.sender != to) {\n require(to != address(0), \"ERC20: no zero address\"); // Moved down so low balance calls safe some gas\n\n balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked\n balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1\n }\n }\n emit Transfer(msg.sender, to, amount);\n return true;\n }\n\n /// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.\n /// @param from Address to draw tokens from.\n /// @param to The address to move the tokens.\n /// @param amount The token amount to move.\n /// @return (bool) Returns True if succeeded.\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public returns (bool) {\n // If `amount` is 0, or `from` is `to` nothing happens\n if (amount != 0) {\n uint256 srcBalance = balanceOf[from];\n require(srcBalance >= amount, \"ERC20: balance too low\");\n\n if (from != to) {\n uint256 spenderAllowance = allowance[from][msg.sender];\n // If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).\n if (spenderAllowance != type(uint256).max) {\n require(spenderAllowance >= amount, \"ERC20: allowance too low\");\n allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked\n }\n require(to != address(0), \"ERC20: no zero address\"); // Moved down so other failed calls safe some gas\n\n balanceOf[from] = srcBalance - amount; // Underflow is checked\n balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1\n }\n }\n emit Transfer(from, to, amount);\n return true;\n }\n\n /// @notice Approves `amount` from sender to be spend by `spender`.\n /// @param spender Address of the party that can draw from msg.sender's account.\n /// @param amount The maximum collective amount that `spender` can draw.\n /// @return (bool) Returns True if approved.\n function approve(address spender, uint256 amount) public returns (bool) {\n allowance[msg.sender][spender] = amount;\n emit Approval(msg.sender, spender, amount);\n return true;\n }\n\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n\n /// @notice Approves `value` from `owner_` to be spend by `spender`.\n /// @param owner_ Address of the owner.\n /// @param spender The address of the spender that gets approved to draw from `owner_`.\n /// @param value The maximum collective amount that `spender` can draw.\n /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).\n function permit(\n address owner_,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(owner_ != address(0), \"ERC20: Owner cannot be 0\");\n require(block.timestamp < deadline, \"ERC20: Expired\");\n require(\n ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) ==\n owner_,\n \"ERC20: Invalid Signature\"\n );\n allowance[owner_][spender] = value;\n emit Approval(owner_, spender, value);\n }\n}\n\n// File @boringcrypto/boring-solidity/contracts/interfaces/IMasterContract.sol@v1.2.0\n// License-Identifier: MIT\n\ninterface IMasterContract {\n /// @notice Init function that gets called from `BoringFactory.deploy`.\n /// Also kown as the constructor for cloned contracts.\n /// Any ETH send to `BoringFactory.deploy` ends up here.\n /// @param data Can be abi encoded arguments or anything else.\n function init(bytes calldata data) external payable;\n}\n\n// File @boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol@v1.2.0\n// License-Identifier: MIT\n\nstruct Rebase {\n uint128 elastic;\n uint128 base;\n}\n\n/// @notice A rebasing library using overflow-/underflow-safe math.\nlibrary RebaseLibrary {\n using BoringMath for uint256;\n using BoringMath128 for uint128;\n\n /// @notice Calculates the base value in relationship to `elastic` and `total`.\n function toBase(\n Rebase memory total,\n uint256 elastic,\n bool roundUp\n ) internal pure returns (uint256 base) {\n if (total.elastic == 0) {\n base = elastic;\n } else {\n base = elastic.mul(total.base) / total.elastic;\n if (roundUp && base.mul(total.elastic) / total.base < elastic) {\n base = base.add(1);\n }\n }\n }\n\n /// @notice Calculates the elastic value in relationship to `base` and `total`.\n function toElastic(\n Rebase memory total,\n uint256 base,\n bool roundUp\n ) internal pure returns (uint256 elastic) {\n if (total.base == 0) {\n elastic = base;\n } else {\n elastic = base.mul(total.elastic) / total.base;\n if (roundUp && elastic.mul(total.base) / total.elastic < base) {\n elastic = elastic.add(1);\n }\n }\n }\n\n /// @notice Add `elastic` to `total` and doubles `total.base`.\n /// @return (Rebase) The new total.\n /// @return base in relationship to `elastic`.\n function add(\n Rebase memory total,\n uint256 elastic,\n bool roundUp\n ) internal pure returns (Rebase memory, uint256 base) {\n base = toBase(total, elastic, roundUp);\n total.elastic = total.elastic.add(elastic.to128());\n total.base = total.base.add(base.to128());\n return (total, base);\n }\n\n /// @notice Sub `base` from `total` and update `total.elastic`.\n /// @return (Rebase) The new total.\n /// @return elastic in relationship to `base`.\n function sub(\n Rebase memory total,\n uint256 base,\n bool roundUp\n ) internal pure returns (Rebase memory, uint256 elastic) {\n elastic = toElastic(total, base, roundUp);\n total.elastic = total.elastic.sub(elastic.to128());\n total.base = total.base.sub(base.to128());\n return (total, elastic);\n }\n\n /// @notice Add `elastic` and `base` to `total`.\n function add(\n Rebase memory total,\n uint256 elastic,\n uint256 base\n ) internal pure returns (Rebase memory) {\n total.elastic = total.elastic.add(elastic.to128());\n total.base = total.base.add(base.to128());\n return total;\n }\n\n /// @notice Subtract `elastic` and `base` to `total`.\n function sub(\n Rebase memory total,\n uint256 elastic,\n uint256 base\n ) internal pure returns (Rebase memory) {\n total.elastic = total.elastic.sub(elastic.to128());\n total.base = total.base.sub(base.to128());\n return total;\n }\n}\n\n// File @boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol@v1.2.0\n// License-Identifier: MIT\n\ninterface IERC20 {\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice EIP 2612\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n\n// File @boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol@v1.2.0\n// License-Identifier: MIT\n\nlibrary BoringERC20 {\n bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()\n bytes4 private constant SIG_NAME = 0x06fdde03; // name()\n bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()\n bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256)\n bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256)\n\n function returnDataToString(bytes memory data) internal pure returns (string memory) {\n if (data.length >= 64) {\n return abi.decode(data, (string));\n } else if (data.length == 32) {\n uint8 i = 0;\n while (i < 32 && data[i] != 0) {\n i++;\n }\n bytes memory bytesArray = new bytes(i);\n for (i = 0; i < 32 && data[i] != 0; i++) {\n bytesArray[i] = data[i];\n }\n return string(bytesArray);\n } else {\n return \"???\";\n }\n }\n\n /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.\n /// @param token The address of the ERC-20 token contract.\n /// @return (string) Token symbol.\n function safeSymbol(IERC20 token) internal view returns (string memory) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));\n return success ? returnDataToString(data) : \"???\";\n }\n\n /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.\n /// @param token The address of the ERC-20 token contract.\n /// @return (string) Token name.\n function safeName(IERC20 token) internal view returns (string memory) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));\n return success ? returnDataToString(data) : \"???\";\n }\n\n /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.\n /// @param token The address of the ERC-20 token contract.\n /// @return (uint8) Token decimals.\n function safeDecimals(IERC20 token) internal view returns (uint8) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));\n return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n }\n}\n\n// File @luckyfinance/alpine-sdk/contracts/IBatchFlashBorrower.sol@v1.0.1\n// License-Identifier: MIT\n\ninterface IBatchFlashBorrower {\n function onBatchFlashLoan(\n address sender,\n IERC20[] calldata tokens,\n uint256[] calldata amounts,\n uint256[] calldata fees,\n bytes calldata data\n ) external;\n}\n\n// File @luckyfinance/alpine-sdk/contracts/IFlashBorrower.sol@v1.0.1\n// License-Identifier: MIT\n\ninterface IFlashBorrower {\n function onFlashLoan(\n address sender,\n IERC20 token,\n uint256 amount,\n uint256 fee,\n bytes calldata data\n ) external;\n}\n\n// File @luckyfinance/alpine-sdk/contracts/IStrategy.sol@v1.0.1\n// License-Identifier: MIT\n\ninterface IStrategy {\n // Send the assets to the Strategy and call skim to invest them\n function skim(uint256 amount) external;\n\n // Harvest any profits made converted to the asset and pass them to the caller\n function harvest(uint256 balance, address sender) external returns (int256 amountAdded);\n\n // Withdraw assets. The returned amount can differ from the requested amount due to rounding.\n // 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.\n function withdraw(uint256 amount) external returns (uint256 actualAmount);\n\n // Withdraw all assets in the safest way possible. This shouldn't fail.\n function exit(uint256 balance) external returns (int256 amountAdded);\n}\n\n// File @luckyfinance/alpine-sdk/contracts/IAlpineV1.sol@v1.0.1\n// License-Identifier: MIT\n\ninterface IAlpineV1 {\n event LogDeploy(address indexed masterContract, bytes data, address indexed cloneAddress);\n event LogDeposit(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);\n event LogFlashLoan(address indexed borrower, address indexed token, uint256 amount, uint256 feeAmount, address indexed receiver);\n event LogRegisterProtocol(address indexed protocol);\n event LogSetMasterContractApproval(address indexed masterContract, address indexed user, bool approved);\n event LogStrategyDivest(address indexed token, uint256 amount);\n event LogStrategyInvest(address indexed token, uint256 amount);\n event LogStrategyLoss(address indexed token, uint256 amount);\n event LogStrategyProfit(address indexed token, uint256 amount);\n event LogStrategyQueued(address indexed token, address indexed strategy);\n event LogStrategySet(address indexed token, address indexed strategy);\n event LogStrategyTargetPercentage(address indexed token, uint256 targetPercentage);\n event LogTransfer(address indexed token, address indexed from, address indexed to, uint256 share);\n event LogWhiteListMasterContract(address indexed masterContract, bool approved);\n event LogWithdraw(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 share);\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n function balanceOf(IERC20, address) external view returns (uint256);\n\n function batch(bytes[] calldata calls, bool revertOnFail) external payable returns (bool[] memory successes, bytes[] memory results);\n\n function batchFlashLoan(\n IBatchFlashBorrower borrower,\n address[] calldata receivers,\n IERC20[] calldata tokens,\n uint256[] calldata amounts,\n bytes calldata data\n ) external;\n\n function claimOwnership() external;\n\n function deploy(\n address masterContract,\n bytes calldata data,\n bool useCreate2\n ) external payable;\n\n function deposit(\n IERC20 token_,\n address from,\n address to,\n uint256 amount,\n uint256 share\n ) external payable returns (uint256 amountOut, uint256 shareOut);\n\n function flashLoan(\n IFlashBorrower borrower,\n address receiver,\n IERC20 token,\n uint256 amount,\n bytes calldata data\n ) external;\n\n function harvest(\n IERC20 token,\n bool balance,\n uint256 maxChangeAmount\n ) external;\n\n function masterContractApproved(address, address) external view returns (bool);\n\n function masterContractOf(address) external view returns (address);\n\n function nonces(address) external view returns (uint256);\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function pendingStrategy(IERC20) external view returns (IStrategy);\n\n function permitToken(\n IERC20 token,\n address from,\n address to,\n uint256 amount,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function registerProtocol() external;\n\n function setMasterContractApproval(\n address user,\n address masterContract,\n bool approved,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function setStrategy(IERC20 token, IStrategy newStrategy) external;\n\n function setStrategyTargetPercentage(IERC20 token, uint64 targetPercentage_) external;\n\n function strategy(IERC20) external view returns (IStrategy);\n\n function strategyData(IERC20)\n external\n view\n returns (\n uint64 strategyStartDate,\n uint64 targetPercentage,\n uint128 balance\n );\n\n function toAmount(\n IERC20 token,\n uint256 share,\n bool roundUp\n ) external view returns (uint256 amount);\n\n function toShare(\n IERC20 token,\n uint256 amount,\n bool roundUp\n ) external view returns (uint256 share);\n\n function totals(IERC20) external view returns (Rebase memory totals_);\n\n function transfer(\n IERC20 token,\n address from,\n address to,\n uint256 share\n ) external;\n\n function transferMultiple(\n IERC20 token,\n address from,\n address[] calldata tos,\n uint256[] calldata shares\n ) external;\n\n function transferOwnership(\n address newOwner,\n bool direct,\n bool renounce\n ) external;\n\n function whitelistMasterContract(address masterContract, bool approved) external;\n\n function whitelistedMasterContracts(address) external view returns (bool);\n\n function withdraw(\n IERC20 token_,\n address from,\n address to,\n uint256 amount,\n uint256 share\n ) external returns (uint256 amountOut, uint256 shareOut);\n}\n\n// File contracts/interfaces/IOracle.sol\n// License-Identifier: MIT\n\ninterface IOracle {\n /// @notice Get the latest exchange rate.\n /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.\n /// For example:\n /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));\n /// @return success if no valid (recent) rate is available, return false else true.\n /// @return rate The rate of the requested asset / pair / pool.\n function get(bytes calldata data) external returns (bool success, uint256 rate);\n\n /// @notice Check the last exchange rate without any state changes.\n /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.\n /// For example:\n /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));\n /// @return success if no valid (recent) rate is available, return false else true.\n /// @return rate The rate of the requested asset / pair / pool.\n function peek(bytes calldata data) external view returns (bool success, uint256 rate);\n\n /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek().\n /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.\n /// For example:\n /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));\n /// @return rate The rate of the requested asset / pair / pool.\n function peekSpot(bytes calldata data) external view returns (uint256 rate);\n\n /// @notice Returns a human readable (short) name about this oracle.\n /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.\n /// For example:\n /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));\n /// @return (string) A human readable symbol name about this oracle.\n function symbol(bytes calldata data) external view returns (string memory);\n\n /// @notice Returns a human readable name about this oracle.\n /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.\n /// For example:\n /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));\n /// @return (string) A human readable name about this oracle.\n function name(bytes calldata data) external view returns (string memory);\n}\n\n// File contracts/interfaces/ISwapper.sol\n// License-Identifier: MIT\n\ninterface ISwapper {\n /// @notice Withdraws 'amountFrom' of token 'from' from the Alpine account for this swapper.\n /// Swaps it for at least 'amountToMin' of token 'to'.\n /// Transfers the swapped tokens of 'to' into the Alpine using a plain ERC20 transfer.\n /// Returns the amount of tokens 'to' transferred to Alpine.\n /// (The Alpine skim function will be used by the caller to get the swapped funds).\n function swap(\n IERC20 fromToken,\n IERC20 toToken,\n address recipient,\n uint256 shareToMin,\n uint256 shareFrom\n ) external returns (uint256 extraShare, uint256 shareReturned);\n\n /// @notice Calculates the amount of token 'from' needed to complete the swap (amountFrom),\n /// this should be less than or equal to amountFromMax.\n /// Withdraws 'amountFrom' of token 'from' from the Alpine account for this swapper.\n /// Swaps it for exactly 'exactAmountTo' of token 'to'.\n /// Transfers the swapped tokens of 'to' into the Alpine using a plain ERC20 transfer.\n /// Transfers allocated, but unused 'from' tokens within the Alpine to 'refundTo' (amountFromMax - amountFrom).\n /// Returns the amount of 'from' tokens withdrawn from Alpine (amountFrom).\n /// (The Alpine skim function will be used by the caller to get the swapped funds).\n function swapExact(\n IERC20 fromToken,\n IERC20 toToken,\n address recipient,\n address refundTo,\n uint256 shareFromSupplied,\n uint256 shareToExact\n ) external returns (uint256 shareUsed, uint256 shareReturned);\n}\n\n// File contracts/GoldVeinPair.sol\n// License-Identifier: UNLICENSED\n// Gold Vein Lending Medium Risk\n\n/// @title GoldVeinPair\n/// @dev This contract allows contract calls to any contract (except Alpine)\n/// from arbitrary callers thus, don't trust calls from this contract in any circumstances.\ncontract GoldVeinPairMediumRiskV1 is ERC20, BoringOwnable, IMasterContract {\n using BoringMath for uint256;\n using BoringMath128 for uint128;\n using RebaseLibrary for Rebase;\n using BoringERC20 for IERC20;\n\n event LogExchangeRate(uint256 rate);\n event LogAccrue(uint256 accruedAmount, uint256 feeFraction, uint64 rate, uint256 utilization);\n event LogAddCollateral(address indexed from, address indexed to, uint256 share);\n event LogAddAsset(address indexed from, address indexed to, uint256 share, uint256 fraction);\n event LogRemoveCollateral(address indexed from, address indexed to, uint256 share);\n event LogRemoveAsset(address indexed from, address indexed to, uint256 share, uint256 fraction);\n event LogBorrow(address indexed from, address indexed to, uint256 amount, uint256 feeAmount, uint256 part);\n event LogRepay(address indexed from, address indexed to, uint256 amount, uint256 part);\n event LogFeeTo(address indexed newFeeTo);\n event LogWithdrawFees(address indexed feeTo, uint256 feesEarnedFraction);\n\n // Immutables (for MasterContract and all clones)\n IAlpineV1 public immutable alPine;\n GoldVeinPairMediumRiskV1 public immutable masterContract;\n\n // MasterContract variables\n address public feeTo;\n mapping(ISwapper => bool) public swappers;\n\n // Per clone variables\n // Clone init settings\n IERC20 public collateral;\n IERC20 public asset;\n IOracle public oracle;\n bytes public oracleData;\n\n // Total amounts\n uint256 public totalCollateralShare; // Total collateral supplied\n Rebase public totalAsset; // elastic = Alpine shares held by the GoldVeinPair, base = Total fractions held by asset suppliers\n Rebase public totalBorrow; // elastic = Total token amount to be repayed by borrowers, base = Total parts of the debt held by borrowers\n\n // User balances\n mapping(address => uint256) public userCollateralShare;\n // userAssetFraction is called balanceOf for ERC20 compatibility (it's in ERC20.sol)\n mapping(address => uint256) public userBorrowPart;\n\n /// @notice Exchange and interest rate tracking.\n /// This is 'cached' here because calls to Oracles can be very expensive.\n uint256 public exchangeRate;\n\n struct AccrueInfo {\n uint64 interestPerSecond;\n uint64 lastAccrued;\n uint128 feesEarnedFraction;\n }\n\n AccrueInfo public accrueInfo;\n\n // ERC20 'variables'\n function symbol() external view returns (string memory) {\n return string(abi.encodePacked(\"km\", collateral.safeSymbol(), \"/\", asset.safeSymbol(), \"-\", oracle.symbol(oracleData)));\n }\n\n function name() external view returns (string memory) {\n return string(abi.encodePacked(\"Gold Vein Medium Risk \", collateral.safeName(), \"/\", asset.safeName(), \"-\", oracle.name(oracleData)));\n }\n\n function decimals() external view returns (uint8) {\n return asset.safeDecimals();\n }\n\n // totalSupply for ERC20 compatibility\n function totalSupply() public view returns (uint256) {\n return totalAsset.base;\n }\n\n // Settings for the Medium Risk GoldVeinPair\n uint256 private constant CLOSED_COLLATERIZATION_RATE = 75000; // 75%\n uint256 private constant OPEN_COLLATERIZATION_RATE = 77000; // 77%\n uint256 private constant COLLATERIZATION_RATE_PRECISION = 1e5; // Must be less than EXCHANGE_RATE_PRECISION (due to optimization in math)\n uint256 private constant MINIMUM_TARGET_UTILIZATION = 7e17; // 70%\n uint256 private constant MAXIMUM_TARGET_UTILIZATION = 8e17; // 80%\n uint256 private constant UTILIZATION_PRECISION = 1e18;\n uint256 private constant FULL_UTILIZATION = 1e18;\n uint256 private constant FULL_UTILIZATION_MINUS_MAX = FULL_UTILIZATION - MAXIMUM_TARGET_UTILIZATION;\n uint256 private constant FACTOR_PRECISION = 1e18;\n\n uint64 private constant STARTING_INTEREST_PER_SECOND = 317097920; // approx 1% APR\n uint64 private constant MINIMUM_INTEREST_PER_SECOND = 79274480; // approx 0.25% APR\n uint64 private constant MAXIMUM_INTEREST_PER_SECOND = 317097920000; // approx 1000% APR\n uint256 private constant INTEREST_ELASTICITY = 28800e36; // Half or double in 28800 seconds (8 hours) if linear\n\n uint256 private constant EXCHANGE_RATE_PRECISION = 1e18;\n\n uint256 private constant LIQUIDATION_MULTIPLIER = 112000; // add 12%\n uint256 private constant LIQUIDATION_MULTIPLIER_PRECISION = 1e5;\n\n // Fees\n uint256 private constant PROTOCOL_FEE = 10000; // 10%\n uint256 private constant PROTOCOL_FEE_DIVISOR = 1e5;\n uint256 private constant BORROW_OPENING_FEE = 50; // 0.05%\n uint256 private constant BORROW_OPENING_FEE_PRECISION = 1e5;\n\n /// @notice The constructor is only used for the initial master contract. Subsequent clones are initialised via `init`.\n constructor(IAlpineV1 alPine_) public {\n alPine = alPine_;\n masterContract = this;\n feeTo = msg.sender;\n }\n\n /// @notice Serves as the constructor for clones, as clones can't have a regular constructor\n /// @dev `data` is abi encoded in the format: (IERC20 collateral, IERC20 asset, IOracle oracle, bytes oracleData)\n function init(bytes calldata data) public payable override {\n require(address(collateral) == address(0), \"GoldVeinPair: already initialized\");\n (collateral, asset, oracle, oracleData) = abi.decode(data, (IERC20, IERC20, IOracle, bytes));\n require(address(collateral) != address(0), \"GoldVeinPair: bad pair\");\n\n accrueInfo.interestPerSecond = uint64(STARTING_INTEREST_PER_SECOND); // 1% APR, with 1e18 being 100%\n }\n\n /// @notice Accrues the interest on the borrowed tokens and handles the accumulation of fees.\n function accrue() public {\n AccrueInfo memory _accrueInfo = accrueInfo;\n // Number of seconds since accrue was called\n uint256 elapsedTime = block.timestamp - _accrueInfo.lastAccrued;\n if (elapsedTime == 0) {\n return;\n }\n _accrueInfo.lastAccrued = uint64(block.timestamp);\n\n Rebase memory _totalBorrow = totalBorrow;\n if (_totalBorrow.base == 0) {\n // If there are no borrows, reset the interest rate\n if (_accrueInfo.interestPerSecond != STARTING_INTEREST_PER_SECOND) {\n _accrueInfo.interestPerSecond = STARTING_INTEREST_PER_SECOND;\n emit LogAccrue(0, 0, STARTING_INTEREST_PER_SECOND, 0);\n }\n accrueInfo = _accrueInfo;\n return;\n }\n\n uint256 extraAmount = 0;\n uint256 feeFraction = 0;\n Rebase memory _totalAsset = totalAsset;\n\n // Accrue interest\n extraAmount = uint256(_totalBorrow.elastic).mul(_accrueInfo.interestPerSecond).mul(elapsedTime) / 1e18;\n _totalBorrow.elastic = _totalBorrow.elastic.add(extraAmount.to128());\n uint256 fullAssetAmount = alPine.toAmount(asset, _totalAsset.elastic, false).add(_totalBorrow.elastic);\n\n uint256 feeAmount = extraAmount.mul(PROTOCOL_FEE) / PROTOCOL_FEE_DIVISOR; // % of interest paid goes to fee\n feeFraction = feeAmount.mul(_totalAsset.base) / fullAssetAmount;\n _accrueInfo.feesEarnedFraction = _accrueInfo.feesEarnedFraction.add(feeFraction.to128());\n totalAsset.base = _totalAsset.base.add(feeFraction.to128());\n totalBorrow = _totalBorrow;\n\n // Update interest rate\n uint256 utilization = uint256(_totalBorrow.elastic).mul(UTILIZATION_PRECISION) / fullAssetAmount;\n if (utilization < MINIMUM_TARGET_UTILIZATION) {\n uint256 underFactor = MINIMUM_TARGET_UTILIZATION.sub(utilization).mul(FACTOR_PRECISION) / MINIMUM_TARGET_UTILIZATION;\n uint256 scale = INTEREST_ELASTICITY.add(underFactor.mul(underFactor).mul(elapsedTime));\n _accrueInfo.interestPerSecond = uint64(uint256(_accrueInfo.interestPerSecond).mul(INTEREST_ELASTICITY) / scale);\n\n if (_accrueInfo.interestPerSecond < MINIMUM_INTEREST_PER_SECOND) {\n _accrueInfo.interestPerSecond = MINIMUM_INTEREST_PER_SECOND; // 0.25% APR minimum\n }\n } else if (utilization > MAXIMUM_TARGET_UTILIZATION) {\n uint256 overFactor = utilization.sub(MAXIMUM_TARGET_UTILIZATION).mul(FACTOR_PRECISION) / FULL_UTILIZATION_MINUS_MAX;\n uint256 scale = INTEREST_ELASTICITY.add(overFactor.mul(overFactor).mul(elapsedTime));\n uint256 newInterestPerSecond = uint256(_accrueInfo.interestPerSecond).mul(scale) / INTEREST_ELASTICITY;\n if (newInterestPerSecond > MAXIMUM_INTEREST_PER_SECOND) {\n newInterestPerSecond = MAXIMUM_INTEREST_PER_SECOND; // 1000% APR maximum\n }\n _accrueInfo.interestPerSecond = uint64(newInterestPerSecond);\n }\n\n emit LogAccrue(extraAmount, feeFraction, _accrueInfo.interestPerSecond, utilization);\n accrueInfo = _accrueInfo;\n }\n\n /// @notice Concrete implementation of `isSolvent`. Includes a third parameter to allow caching `exchangeRate`.\n /// @param _exchangeRate The exchange rate. Used to cache the `exchangeRate` between calls.\n function _isSolvent(\n address user,\n bool open,\n uint256 _exchangeRate\n ) internal view returns (bool) {\n // accrue must have already been called!\n uint256 borrowPart = userBorrowPart[user];\n if (borrowPart == 0) return true;\n uint256 collateralShare = userCollateralShare[user];\n if (collateralShare == 0) return false;\n\n Rebase memory _totalBorrow = totalBorrow;\n\n return\n alPine.toAmount(\n collateral,\n collateralShare.mul(EXCHANGE_RATE_PRECISION / COLLATERIZATION_RATE_PRECISION).mul(\n open ? OPEN_COLLATERIZATION_RATE : CLOSED_COLLATERIZATION_RATE\n ),\n false\n ) >=\n // Moved exchangeRate here instead of dividing the other side to preserve more precision\n borrowPart.mul(_totalBorrow.elastic).mul(_exchangeRate) / _totalBorrow.base;\n }\n\n /// @dev Checks if the user is solvent in the closed liquidation case at the end of the function body.\n modifier solvent() {\n _;\n require(_isSolvent(msg.sender, false, exchangeRate), \"GoldVeinPair: user insolvent\");\n }\n\n /// @notice Gets the exchange rate. I.e how much collateral to buy 1e18 asset.\n /// This function is supposed to be invoked if needed because Oracle queries can be expensive.\n /// @return updated True if `exchangeRate` was updated.\n /// @return rate The new exchange rate.\n function updateExchangeRate() public returns (bool updated, uint256 rate) {\n (updated, rate) = oracle.get(oracleData);\n\n if (updated) {\n exchangeRate = rate;\n emit LogExchangeRate(rate);\n } else {\n // Return the old rate if fetching wasn't successful\n rate = exchangeRate;\n }\n }\n\n /// @dev Helper function to move tokens.\n /// @param token The ERC-20 token.\n /// @param share The amount in shares to add.\n /// @param total Grand total amount to deduct from this contract's balance. Only applicable if `skim` is True.\n /// Only used for accounting checks.\n /// @param skim If True, only does a balance check on this contract.\n /// False if tokens from msg.sender in `alPine` should be transferred.\n function _addTokens(\n IERC20 token,\n uint256 share,\n uint256 total,\n bool skim\n ) internal {\n if (skim) {\n require(share <= alPine.balanceOf(token, address(this)).sub(total), \"GoldVeinPair: Skim too much\");\n } else {\n alPine.transfer(token, msg.sender, address(this), share);\n }\n }\n\n /// @notice Adds `collateral` from msg.sender to the account `to`.\n /// @param to The receiver of the tokens.\n /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.\n /// False if tokens from msg.sender in `alPine` should be transferred.\n /// @param share The amount of shares to add for `to`.\n function addCollateral(\n address to,\n bool skim,\n uint256 share\n ) public {\n userCollateralShare[to] = userCollateralShare[to].add(share);\n uint256 oldTotalCollateralShare = totalCollateralShare;\n totalCollateralShare = oldTotalCollateralShare.add(share);\n _addTokens(collateral, share, oldTotalCollateralShare, skim);\n emit LogAddCollateral(skim ? address(alPine) : msg.sender, to, share);\n }\n\n /// @dev Concrete implementation of `removeCollateral`.\n function _removeCollateral(address to, uint256 share) internal {\n userCollateralShare[msg.sender] = userCollateralShare[msg.sender].sub(share);\n totalCollateralShare = totalCollateralShare.sub(share);\n emit LogRemoveCollateral(msg.sender, to, share);\n alPine.transfer(collateral, address(this), to, share);\n }\n\n /// @notice Removes `share` amount of collateral and transfers it to `to`.\n /// @param to The receiver of the shares.\n /// @param share Amount of shares to remove.\n function removeCollateral(address to, uint256 share) public solvent {\n // accrue must be called because we check solvency\n accrue();\n _removeCollateral(to, share);\n }\n\n /// @dev Concrete implementation of `addAsset`.\n function _addAsset(\n address to,\n bool skim,\n uint256 share\n ) internal returns (uint256 fraction) {\n Rebase memory _totalAsset = totalAsset;\n uint256 totalAssetShare = _totalAsset.elastic;\n uint256 allShare = _totalAsset.elastic + alPine.toShare(asset, totalBorrow.elastic, true);\n fraction = allShare == 0 ? share : share.mul(_totalAsset.base) / allShare;\n if (_totalAsset.base.add(fraction.to128()) < 1000) {\n return 0;\n }\n totalAsset = _totalAsset.add(share, fraction);\n balanceOf[to] = balanceOf[to].add(fraction);\n _addTokens(asset, share, totalAssetShare, skim);\n emit LogAddAsset(skim ? address(alPine) : msg.sender, to, share, fraction);\n }\n\n /// @notice Adds assets to the lending pair.\n /// @param to The address of the user to receive the assets.\n /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.\n /// False if tokens from msg.sender in `alPine` should be transferred.\n /// @param share The amount of shares to add.\n /// @return fraction Total fractions added.\n function addAsset(\n address to,\n bool skim,\n uint256 share\n ) public returns (uint256 fraction) {\n accrue();\n fraction = _addAsset(to, skim, share);\n }\n\n /// @dev Concrete implementation of `removeAsset`.\n function _removeAsset(address to, uint256 fraction) internal returns (uint256 share) {\n Rebase memory _totalAsset = totalAsset;\n uint256 allShare = _totalAsset.elastic + alPine.toShare(asset, totalBorrow.elastic, true);\n share = fraction.mul(allShare) / _totalAsset.base;\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(fraction);\n _totalAsset.elastic = _totalAsset.elastic.sub(share.to128());\n _totalAsset.base = _totalAsset.base.sub(fraction.to128());\n require(_totalAsset.base >= 1000, \"GoldVein: below minimum\");\n totalAsset = _totalAsset;\n emit LogRemoveAsset(msg.sender, to, share, fraction);\n alPine.transfer(asset, address(this), to, share);\n }\n\n /// @notice Removes an asset from msg.sender and transfers it to `to`.\n /// @param to The user that receives the removed assets.\n /// @param fraction The amount/fraction of assets held to remove.\n /// @return share The amount of shares transferred to `to`.\n function removeAsset(address to, uint256 fraction) public returns (uint256 share) {\n accrue();\n share = _removeAsset(to, fraction);\n }\n\n /// @dev Concrete implementation of `borrow`.\n function _borrow(address to, uint256 amount) internal returns (uint256 part, uint256 share) {\n uint256 feeAmount = amount.mul(BORROW_OPENING_FEE) / BORROW_OPENING_FEE_PRECISION; // A flat % fee is charged for any borrow\n\n (totalBorrow, part) = totalBorrow.add(amount.add(feeAmount), true);\n userBorrowPart[msg.sender] = userBorrowPart[msg.sender].add(part);\n emit LogBorrow(msg.sender, to, amount, feeAmount, part);\n\n share = alPine.toShare(asset, amount, false);\n Rebase memory _totalAsset = totalAsset;\n require(_totalAsset.base >= 1000, \"GoldVein: below minimum\");\n _totalAsset.elastic = _totalAsset.elastic.sub(share.to128());\n totalAsset = _totalAsset;\n alPine.transfer(asset, address(this), to, share);\n }\n\n /// @notice Sender borrows `amount` and transfers it to `to`.\n /// @return part Total part of the debt held by borrowers.\n /// @return share Total amount in shares borrowed.\n function borrow(address to, uint256 amount) public solvent returns (uint256 part, uint256 share) {\n accrue();\n (part, share) = _borrow(to, amount);\n }\n\n /// @dev Concrete implementation of `repay`.\n function _repay(\n address to,\n bool skim,\n uint256 part\n ) internal returns (uint256 amount) {\n (totalBorrow, amount) = totalBorrow.sub(part, true);\n userBorrowPart[to] = userBorrowPart[to].sub(part);\n\n uint256 share = alPine.toShare(asset, amount, true);\n uint128 totalShare = totalAsset.elastic;\n _addTokens(asset, share, uint256(totalShare), skim);\n totalAsset.elastic = totalShare.add(share.to128());\n emit LogRepay(skim ? address(alPine) : msg.sender, to, amount, part);\n }\n\n /// @notice Repays a loan.\n /// @param to Address of the user this payment should go.\n /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.\n /// False if tokens from msg.sender in `alPine` should be transferred.\n /// @param part The amount to repay. See `userBorrowPart`.\n /// @return amount The total amount repayed.\n function repay(\n address to,\n bool skim,\n uint256 part\n ) public returns (uint256 amount) {\n accrue();\n amount = _repay(to, skim, part);\n }\n\n // Functions that need accrue to be called\n uint8 internal constant ACTION_ADD_ASSET = 1;\n uint8 internal constant ACTION_REPAY = 2;\n uint8 internal constant ACTION_REMOVE_ASSET = 3;\n uint8 internal constant ACTION_REMOVE_COLLATERAL = 4;\n uint8 internal constant ACTION_BORROW = 5;\n uint8 internal constant ACTION_GET_REPAY_SHARE = 6;\n uint8 internal constant ACTION_GET_REPAY_PART = 7;\n uint8 internal constant ACTION_ACCRUE = 8;\n\n // Functions that don't need accrue to be called\n uint8 internal constant ACTION_ADD_COLLATERAL = 10;\n uint8 internal constant ACTION_UPDATE_EXCHANGE_RATE = 11;\n\n // Function on Alpine\n uint8 internal constant ACTION_ALP_DEPOSIT = 20;\n uint8 internal constant A