Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
13810899 | 1068 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
DataCompressor
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; pragma experimental ABIEncoderV2; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; import {PercentageMath} from "../libraries/math/PercentageMath.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditAccount} from "../interfaces/ICreditAccount.sol"; import {ICreditManager} from "../interfaces/ICreditManager.sol"; import {CreditManager} from "../credit/CreditManager.sol"; import {IPoolService} from "../interfaces/IPoolService.sol"; import {ICreditFilter} from "../interfaces/ICreditFilter.sol"; import {IPriceOracle} from "../interfaces/IPriceOracle.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/EnumerableSet.sol"; import {AddressProvider} from "./AddressProvider.sol"; import {ContractsRegister} from "./ContractsRegister.sol"; import {DataTypes} from "../libraries/data/Types.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; /// @title Data compressor /// @notice Collects data from different contracts to send it to dApp /// Do not use for data from data compressor for state-changing functions contract DataCompressor { using SafeMath for uint256; using PercentageMath for uint256; AddressProvider public addressProvider; ContractsRegister public immutable contractsRegister; address public immutable WETHToken; // Contract version uint256 public constant version = 1; /// @dev Allows provide data for registered pools only to eliminated usage for non-gearbox contracts modifier registeredPoolOnly(address pool) { // Could be optimised by adding internal list of pools require(contractsRegister.isPool(pool), Errors.REGISTERED_POOLS_ONLY); // T:[WG-1] _; } /// @dev Allows provide data for registered credit managers only to eliminated usage for non-gearbox contracts modifier registeredCreditManagerOnly(address creditManager) { // Could be optimised by adding internal list of creditManagers require( contractsRegister.isCreditManager(creditManager), Errors.REGISTERED_CREDIT_ACCOUNT_MANAGERS_ONLY ); // T:[WG-3] _; } constructor(address _addressProvider) { require( _addressProvider != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED ); addressProvider = AddressProvider(_addressProvider); contractsRegister = ContractsRegister( addressProvider.getContractsRegister() ); WETHToken = addressProvider.getWethToken(); } /// @dev Returns CreditAccountData for all opened account for particluar borrower /// @param borrower Borrower address function getCreditAccountList(address borrower) external view returns (DataTypes.CreditAccountData[] memory) { // Counts how much opened account a borrower has uint256 count; for ( uint256 i = 0; i < contractsRegister.getCreditManagersCount(); i++ ) { address creditManager = contractsRegister.creditManagers(i); if ( ICreditManager(creditManager).hasOpenedCreditAccount(borrower) ) { count++; } } DataTypes.CreditAccountData[] memory result = new DataTypes.CreditAccountData[](count); // Get data & fill the array count = 0; for ( uint256 i = 0; i < contractsRegister.getCreditManagersCount(); i++ ) { address creditManager = contractsRegister.creditManagers(i); if ( ICreditManager(creditManager).hasOpenedCreditAccount(borrower) ) { result[count] = getCreditAccountData(creditManager, borrower); count++; } } return result; } function hasOpenedCreditAccount(address _creditManager, address borrower) public view registeredCreditManagerOnly(_creditManager) returns (bool) { ICreditManager creditManager = ICreditManager(_creditManager); return creditManager.hasOpenedCreditAccount(borrower); } /// @dev Returns CreditAccountData for particular account for creditManager and borrower /// @param _creditManager Credit manager address /// @param borrower Borrower address function getCreditAccountData(address _creditManager, address borrower) public view returns (DataTypes.CreditAccountData memory) { ( ICreditManager creditManager, ICreditFilter creditFilter ) = getCreditContracts(_creditManager); address creditAccount = creditManager.getCreditAccountOrRevert( borrower ); DataTypes.CreditAccountData memory result; result.borrower = borrower; result.creditManager = _creditManager; result.addr = creditAccount; result.underlyingToken = creditFilter.underlyingToken(); result.totalValue = creditFilter.calcTotalValue(creditAccount); result.healthFactor = creditFilter.calcCreditAccountHealthFactor( creditAccount ); address pool = creditManager.poolService(); result.borrowRate = IPoolService(pool).borrowAPY_RAY(); uint256 allowedTokenCount = creditFilter.allowedTokensCount(); result.balances = new DataTypes.TokenBalance[](allowedTokenCount); for (uint256 i = 0; i < allowedTokenCount; i++) { DataTypes.TokenBalance memory balance; (balance.token, balance.balance, , ) = creditFilter .getCreditAccountTokenById(creditAccount, i); balance.isAllowed = creditFilter.isTokenAllowed(balance.token); result.balances[i] = balance; } result.borrowedAmountPlusInterest = creditFilter .calcCreditAccountAccruedInterest(creditAccount); return result; } /// @dev Returns CreditAccountDataExtendeds for particular account for creditManager and borrower /// @param creditManager Credit manager address /// @param borrower Borrower address function getCreditAccountDataExtended( address creditManager, address borrower ) external view registeredCreditManagerOnly(creditManager) returns (DataTypes.CreditAccountDataExtended memory) { DataTypes.CreditAccountDataExtended memory result; DataTypes.CreditAccountData memory data = getCreditAccountData( creditManager, borrower ); result.addr = data.addr; result.borrower = data.borrower; result.creditManager = data.creditManager; result.underlyingToken = data.underlyingToken; result.borrowedAmountPlusInterest = data.borrowedAmountPlusInterest; result.totalValue = data.totalValue; result.healthFactor = data.healthFactor; result.borrowRate = data.borrowRate; result.balances = data.balances; address creditAccount = ICreditManager(creditManager) .getCreditAccountOrRevert(borrower); result.borrowedAmount = ICreditAccount(creditAccount).borrowedAmount(); result.cumulativeIndexAtOpen = ICreditAccount(creditAccount) .cumulativeIndexAtOpen(); result.since = ICreditAccount(creditAccount).since(); result.repayAmount = ICreditManager(creditManager).calcRepayAmount( borrower, false ); result.liquidationAmount = ICreditManager(creditManager) .calcRepayAmount(borrower, true); (, , uint256 remainingFunds, , ) = CreditManager(creditManager) ._calcClosePayments(creditAccount, data.totalValue, false); result.canBeClosed = remainingFunds > 0; return result; } /// @dev Returns all credit managers data + hasOpendAccount flag for bborrower /// @param borrower Borrower address function getCreditManagersList(address borrower) external view returns (DataTypes.CreditManagerData[] memory) { uint256 creditManagersCount = contractsRegister .getCreditManagersCount(); DataTypes.CreditManagerData[] memory result = new DataTypes.CreditManagerData[](creditManagersCount); for (uint256 i = 0; i < creditManagersCount; i++) { address creditManager = contractsRegister.creditManagers(i); result[i] = getCreditManagerData(creditManager, borrower); } return result; } /// @dev Returns CreditManagerData for particular _creditManager and /// set flg hasOpenedCreditAccount for provided borrower /// @param _creditManager CreditManager address /// @param borrower Borrower address function getCreditManagerData(address _creditManager, address borrower) public view returns (DataTypes.CreditManagerData memory) { ( ICreditManager creditManager, ICreditFilter creditFilter ) = getCreditContracts(_creditManager); DataTypes.CreditManagerData memory result; result.addr = _creditManager; result.hasAccount = creditManager.hasOpenedCreditAccount(borrower); result.underlyingToken = creditFilter.underlyingToken(); result.isWETH = result.underlyingToken == WETHToken; IPoolService pool = IPoolService(creditManager.poolService()); result.canBorrow = pool.creditManagersCanBorrow(_creditManager); result.borrowRate = pool.borrowAPY_RAY(); result.availableLiquidity = pool.availableLiquidity(); result.minAmount = creditManager.minAmount(); result.maxAmount = creditManager.maxAmount(); result.maxLeverageFactor = creditManager.maxLeverageFactor(); uint256 allowedTokenCount = creditFilter.allowedTokensCount(); result.allowedTokens = new address[](allowedTokenCount); for (uint256 i = 0; i < allowedTokenCount; i++) { result.allowedTokens[i] = creditFilter.allowedTokens(i); } uint256 allowedContractsCount = creditFilter.allowedContractsCount(); result.adapters = new DataTypes.ContractAdapter[]( allowedContractsCount ); for (uint256 i = 0; i < allowedContractsCount; i++) { DataTypes.ContractAdapter memory adapter; adapter.allowedContract = creditFilter.allowedContracts(i); adapter.adapter = creditFilter.contractToAdapter( adapter.allowedContract ); result.adapters[i] = adapter; } return result; } /// @dev Returns PoolData for particulr pool /// @param _pool Pool address function getPoolData(address _pool) public view registeredPoolOnly(_pool) returns (DataTypes.PoolData memory) { DataTypes.PoolData memory result; IPoolService pool = IPoolService(_pool); result.addr = _pool; result.expectedLiquidity = pool.expectedLiquidity(); result.expectedLiquidityLimit = pool.expectedLiquidityLimit(); result.availableLiquidity = pool.availableLiquidity(); result.totalBorrowed = pool.totalBorrowed(); result.dieselRate_RAY = pool.getDieselRate_RAY(); result.linearCumulativeIndex = pool.calcLinearCumulative_RAY(); result.borrowAPY_RAY = pool.borrowAPY_RAY(); result.underlyingToken = pool.underlyingToken(); result.dieselToken = pool.dieselToken(); result.dieselRate_RAY = pool.getDieselRate_RAY(); result.withdrawFee = pool.withdrawFee(); result.isWETH = result.underlyingToken == WETHToken; result.timestampLU = pool._timestampLU(); result.cumulativeIndex_RAY = pool._cumulativeIndex_RAY(); uint256 dieselSupply = IERC20(result.dieselToken).totalSupply(); uint256 totalLP = pool.fromDiesel(dieselSupply); result.depositAPY_RAY = totalLP == 0 ? result.borrowAPY_RAY : result .borrowAPY_RAY .mul(result.totalBorrowed) .percentMul( PercentageMath.PERCENTAGE_FACTOR.sub(result.withdrawFee) ).div(totalLP); return result; } /// @dev Returns PoolData for all registered pools function getPoolsList() external view returns (DataTypes.PoolData[] memory) { uint256 poolsCount = contractsRegister.getPoolsCount(); DataTypes.PoolData[] memory result = new DataTypes.PoolData[]( poolsCount ); for (uint256 i = 0; i < poolsCount; i++) { address pool = contractsRegister.pools(i); result[i] = getPoolData(pool); } return result; } /// @dev Returns compressed token data for particular token. /// Be careful, it can be reverted for non-standart tokens which has no "symbol" method for example function getTokenData(address[] memory addr) external view returns (DataTypes.TokenInfo[] memory) { DataTypes.TokenInfo[] memory result = new DataTypes.TokenInfo[]( addr.length ); for (uint256 i = 0; i < addr.length; i++) { result[i] = DataTypes.TokenInfo( addr[i], ERC20(addr[i]).symbol(), ERC20(addr[i]).decimals() ); } return result; } /// @dev Returns adapter address for particular creditManager and protocol function getAdapter(address _creditManager, address _allowedContract) external view registeredCreditManagerOnly(_creditManager) returns (address) { return ICreditManager(_creditManager).creditFilter().contractToAdapter( _allowedContract ); } function calcExpectedHf( address _creditManager, address borrower, uint256[] memory balances ) external view returns (uint256) { ( ICreditManager creditManager, ICreditFilter creditFilter ) = getCreditContracts(_creditManager); address creditAccount = creditManager.getCreditAccountOrRevert( borrower ); IPriceOracle priceOracle = IPriceOracle(creditFilter.priceOracle()); uint256 tokenLength = creditFilter.allowedTokensCount(); require(balances.length == tokenLength, "Incorrect balances size"); uint256 total = 0; address underlyingToken = creditManager.underlyingToken(); for (uint256 i = 0; i < tokenLength; i++) { { total = total.add( priceOracle .convert( balances[i], creditFilter.allowedTokens(i), underlyingToken ).mul( creditFilter.liquidationThresholds( creditFilter.allowedTokens(i) ) ) ); } } return total.div( creditFilter.calcCreditAccountAccruedInterest(creditAccount) ); } function calcExpectedAtOpenHf( address _creditManager, address token, uint256 amount, uint256 borrowedAmount ) external view returns (uint256) { ( ICreditManager creditManager, ICreditFilter creditFilter ) = getCreditContracts(_creditManager); IPriceOracle priceOracle = IPriceOracle(creditFilter.priceOracle()); uint256 total = priceOracle .convert(amount, token, creditManager.underlyingToken()) .mul(creditFilter.liquidationThresholds(token)); return total.div(borrowedAmount); } function getCreditContracts(address _creditManager) internal view registeredCreditManagerOnly(_creditManager) returns (ICreditManager creditManager, ICreditFilter creditFilter) { creditManager = ICreditManager(_creditManager); creditFilter = ICreditFilter(creditManager.creditFilter()); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.7.4; import {Errors} from "../helpers/Errors.sol"; /** * @title PercentageMath library * @author Aave * @notice Provides functions to perform percentage calculations * @dev Percentages are defined by default with 2 decimals of precision (100.00). The precision is indicated by PERCENTAGE_FACTOR * @dev Operations are rounded half up **/ library PercentageMath { uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2; /** * @dev Executes a percentage multiplication * @param value The value of which the percentage needs to be calculated * @param percentage The percentage of the value to be calculated * @return The percentage of value **/ function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) { if (value == 0 || percentage == 0) { return 0; // T:[PM-1] } require( value <= (type(uint256).max - HALF_PERCENT) / percentage, Errors.MATH_MULTIPLICATION_OVERFLOW ); // T:[PM-1] return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR; // T:[PM-1] } /** * @dev Executes a percentage division * @param value The value of which the percentage needs to be calculated * @param percentage The percentage of the value to be calculated * @return The value divided the percentage **/ function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) { require(percentage != 0, Errors.MATH_DIVISION_BY_ZERO); // T:[PM-2] uint256 halfPercentage = percentage / 2; // T:[PM-2] require( value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR, Errors.MATH_MULTIPLICATION_OVERFLOW ); // T:[PM-2] return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title Reusable Credit Account interface /// @notice Implements general credit account: /// - Keeps token balances /// - Keeps token balances /// - Stores general parameters: borrowed amount, cumulative index at open and block when it was initialized /// - Approves tokens for 3rd party contracts /// - Transfers assets /// - Execute financial orders /// /// More: https://dev.gearbox.fi/developers/creditManager/vanillacreditAccount interface ICreditAccount { /// @dev Initializes clone contract function initialize() external; /// @dev Connects credit account to credit manager /// @param _creditManager Credit manager address function connectTo( address _creditManager, uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external; // /// @dev Set general credit account parameters. Restricted to credit managers only // /// @param _borrowedAmount Amount which pool lent to credit account // /// @param _cumulativeIndexAtOpen Cumulative index at open. Uses for interest calculation // function setGenericParameters( // // ) external; /// @dev Updates borrowed amount. Restricted to credit managers only /// @param _borrowedAmount Amount which pool lent to credit account function updateParameters( uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external; /// @dev Approves particular token for swap contract /// @param token ERC20 token for allowance /// @param swapContract Swap contract address function approveToken(address token, address swapContract) external; /// @dev Cancels allowance for particular contract /// @param token Address of token for allowance /// @param targetContract Address of contract to cancel allowance function cancelAllowance(address token, address targetContract) external; /// Transfers tokens from credit account to provided address. Restricted for pool calls only /// @param token Token which should be tranferred from credit account /// @param to Address of recipient /// @param amount Amount to be transferred function safeTransfer( address token, address to, uint256 amount ) external; /// @dev Returns borrowed amount function borrowedAmount() external view returns (uint256); /// @dev Returns cumulative index at time of opening credit account function cumulativeIndexAtOpen() external view returns (uint256); /// @dev Returns Block number when it was initialised last time function since() external view returns (uint256); /// @dev Address of last connected credit manager function creditManager() external view returns (address); /// @dev Address of last connected credit manager function factory() external view returns (address); /// @dev Executed financial order on 3rd party service. Restricted for pool calls only /// @param destination Contract address which should be called /// @param data Call data which should be sent function execute(address destination, bytes memory data) external returns (bytes memory); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; pragma abicoder v2; import {ICreditFilter} from "../interfaces/ICreditFilter.sol"; import {IAppCreditManager} from "./app/IAppCreditManager.sol"; import {DataTypes} from "../libraries/data/Types.sol"; /// @title Credit Manager interface /// @notice It encapsulates business logic for managing credit accounts /// /// More info: https://dev.gearbox.fi/developers/credit/credit_manager interface ICreditManager is IAppCreditManager { // Emits each time when the credit account is opened event OpenCreditAccount( address indexed sender, address indexed onBehalfOf, address indexed creditAccount, uint256 amount, uint256 borrowAmount, uint256 referralCode ); // Emits each time when the credit account is closed event CloseCreditAccount( address indexed owner, address indexed to, uint256 remainingFunds ); // Emits each time when the credit account is liquidated event LiquidateCreditAccount( address indexed owner, address indexed liquidator, uint256 remainingFunds ); // Emits each time when borrower increases borrowed amount event IncreaseBorrowedAmount(address indexed borrower, uint256 amount); // Emits each time when borrower adds collateral event AddCollateral( address indexed onBehalfOf, address indexed token, uint256 value ); // Emits each time when the credit account is repaid event RepayCreditAccount(address indexed owner, address indexed to); // Emit each time when financial order is executed event ExecuteOrder(address indexed borrower, address indexed target); // Emits each time when new fees are set event NewParameters( uint256 minAmount, uint256 maxAmount, uint256 maxLeverage, uint256 feeInterest, uint256 feeLiquidation, uint256 liquidationDiscount ); event TransferAccount(address indexed oldOwner, address indexed newOwner); // // CREDIT ACCOUNT MANAGEMENT // /** * @dev Opens credit account and provides credit funds. * - Opens credit account (take it from account factory) * - Transfers trader /farmers initial funds to credit account * - Transfers borrowed leveraged amount from pool (= amount x leverageFactor) calling lendCreditAccount() on connected Pool contract. * - Emits OpenCreditAccount event * Function reverts if user has already opened position * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#open-credit-account * * @param amount Borrowers own funds * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param leverageFactor Multiplier to borrowers own funds * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man */ function openCreditAccount( uint256 amount, address onBehalfOf, uint256 leverageFactor, uint256 referralCode ) external override; /** * @dev Closes credit account * - Swaps all assets to underlying one using default swap protocol * - Pays borrowed amount + interest accrued + fees back to the pool by calling repayCreditAccount * - Transfers remaining funds to the trader / farmer * - Closes the credit account and return it to account factory * - Emits CloseCreditAccount event * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#close-credit-account * * @param to Address to send remaining funds * @param paths Exchange type data which provides paths + amountMinOut */ function closeCreditAccount(address to, DataTypes.Exchange[] calldata paths) external override; /** * @dev Liquidates credit account * - Transfers discounted total credit account value from liquidators account * - Pays borrowed funds + interest + fees back to pool, than transfers remaining funds to credit account owner * - Transfer all assets from credit account to liquidator ("to") account * - Returns credit account to factory * - Emits LiquidateCreditAccount event * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#liquidate-credit-account * * @param borrower Borrower address * @param to Address to transfer all assets from credit account * @param force If true, use transfer function for transferring tokens instead of safeTransfer */ function liquidateCreditAccount( address borrower, address to, bool force ) external; /// @dev Repays credit account /// More info: https://dev.gearbox.fi/developers/credit/credit_manager#repay-credit-account /// /// @param to Address to send credit account assets function repayCreditAccount(address to) external override; /// @dev Repays credit account with ETH. Restricted to be called by WETH Gateway only /// /// @param borrower Address of borrower /// @param to Address to send credit account assets function repayCreditAccountETH(address borrower, address to) external returns (uint256); /// @dev Increases borrowed amount by transferring additional funds from /// the pool if after that HealthFactor > minHealth /// More info: https://dev.gearbox.fi/developers/credit/credit_manager#increase-borrowed-amount /// /// @param amount Amount to increase borrowed amount function increaseBorrowedAmount(uint256 amount) external override; /// @dev Adds collateral to borrower's credit account /// @param onBehalfOf Address of borrower to add funds /// @param token Token address /// @param amount Amount to add function addCollateral( address onBehalfOf, address token, uint256 amount ) external override; /// @dev Returns true if the borrower has opened a credit account /// @param borrower Borrower account function hasOpenedCreditAccount(address borrower) external view override returns (bool); /// @dev Calculates Repay amount = borrow amount + interest accrued + fee /// /// More info: https://dev.gearbox.fi/developers/credit/economy#repay /// https://dev.gearbox.fi/developers/credit/economy#liquidate /// /// @param borrower Borrower address /// @param isLiquidated True if calculated repay amount for liquidator function calcRepayAmount(address borrower, bool isLiquidated) external view override returns (uint256); /// @dev Returns minimal amount for open credit account function minAmount() external view returns (uint256); /// @dev Returns maximum amount for open credit account function maxAmount() external view returns (uint256); /// @dev Returns maximum leveraged factor allowed for this pool function maxLeverageFactor() external view returns (uint256); /// @dev Returns underlying token address function underlyingToken() external view returns (address); /// @dev Returns address of connected pool function poolService() external view returns (address); /// @dev Returns address of CreditFilter function creditFilter() external view returns (ICreditFilter); /// @dev Returns address of CreditFilter function creditAccounts(address borrower) external view returns (address); /// @dev Executes filtered order on credit account which is connected with particular borrowers /// @param borrower Borrower address /// @param target Target smart-contract /// @param data Call data for call function executeOrder( address borrower, address target, bytes memory data ) external returns (bytes memory); /// @dev Approves token for msg.sender's credit account function approve(address targetContract, address token) external; /// @dev Approve tokens for credit accounts. Restricted for adapters only function provideCreditAccountAllowance( address creditAccount, address toContract, address token ) external; function transferAccountOwnership(address newOwner) external; /// @dev Returns address of borrower's credit account and reverts of borrower has no one. /// @param borrower Borrower address function getCreditAccountOrRevert(address borrower) external view override returns (address); // function feeSuccess() external view returns (uint256); function feeInterest() external view returns (uint256); function feeLiquidation() external view returns (uint256); function liquidationDiscount() external view returns (uint256); function minHealthFactor() external view returns (uint256); function defaultSwapContract() external view override returns (address); }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; pragma abicoder v2; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; import {PercentageMath} from "../libraries/math/PercentageMath.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import {IAccountFactory} from "../interfaces/IAccountFactory.sol"; import {ICreditAccount} from "../interfaces/ICreditAccount.sol"; import {IPoolService} from "../interfaces/IPoolService.sol"; import {IWETHGateway} from "../interfaces/IWETHGateway.sol"; import {ICreditManager} from "../interfaces/ICreditManager.sol"; import {ICreditFilter} from "../interfaces/ICreditFilter.sol"; import {AddressProvider} from "../core/AddressProvider.sol"; import {ACLTrait} from "../core/ACLTrait.sol"; import {Constants} from "../libraries/helpers/Constants.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {DataTypes} from "../libraries/data/Types.sol"; /// @title Credit Manager /// @notice It encapsulates business logic for managing credit accounts /// /// More info: https://dev.gearbox.fi/developers/credit/credit_manager /// /// #define roughEq(uint256 a, uint256 b) bool = /// a == b || a + 1 == b || a == b + 1; /// /// #define borrowedPlusInterest(address creditAccount) uint = /// let borrowedAmount, cumIndexAtOpen := getCreditAccountParameters(creditAccount) in /// let curCumulativeIndex := IPoolService(poolService).calcLinearCumulative_RAY() in /// borrowedAmount.mul(curCumulativeIndex).div(cumIndexAtOpen); contract CreditManager is ICreditManager, ACLTrait, ReentrancyGuard { using SafeMath for uint256; using PercentageMath for uint256; using SafeERC20 for IERC20; using Address for address payable; // Minimal amount for open credit account uint256 public override minAmount; // Maximum amount for open credit account uint256 public override maxAmount; // Maximum leveraged factor allowed for this pool uint256 public override maxLeverageFactor; // Minimal allowed Hf after increasing borrow amount uint256 public override minHealthFactor; // Mapping between borrowers'/farmers' address and credit account mapping(address => address) public override creditAccounts; // Account manager - provides credit accounts to pool IAccountFactory internal _accountFactory; // Credit Manager filter ICreditFilter public override creditFilter; // Underlying token address address public override underlyingToken; // Address of connected pool address public override poolService; // Address of WETH token address public wethAddress; // Address of WETH Gateway address public wethGateway; // Default swap contracts - uses for automatic close address public override defaultSwapContract; uint256 public override feeInterest; uint256 public override feeLiquidation; uint256 public override liquidationDiscount; // Contract version uint constant public version = 1; // // MODIFIERS // /// @dev Restricts actions for users with opened credit accounts only modifier allowedAdaptersOnly(address targetContract) { require( creditFilter.contractToAdapter(targetContract) == msg.sender, Errors.CM_TARGET_CONTRACT_iS_NOT_ALLOWED ); _; } /// @dev Constructor /// @param _addressProvider Address Repository for upgradable contract model /// @param _minAmount Minimal amount for open credit account /// @param _maxAmount Maximum amount for open credit account /// @param _maxLeverage Maximum allowed leverage factor /// @param _poolService Address of pool service /// @param _creditFilterAddress CreditFilter address. It should be finalised /// @param _defaultSwapContract Default IUniswapV2Router02 contract to change assets in case of closing account constructor( address _addressProvider, uint256 _minAmount, uint256 _maxAmount, uint256 _maxLeverage, address _poolService, address _creditFilterAddress, address _defaultSwapContract ) ACLTrait(_addressProvider) { require( _addressProvider != address(0) && _poolService != address(0) && _creditFilterAddress != address(0) && _defaultSwapContract != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED ); AddressProvider addressProvider = AddressProvider(_addressProvider); // T:[CM-1] poolService = _poolService; // T:[CM-1] underlyingToken = IPoolService(_poolService).underlyingToken(); // T:[CM-1] wethAddress = addressProvider.getWethToken(); // T:[CM-1] wethGateway = addressProvider.getWETHGateway(); // T:[CM-1] defaultSwapContract = _defaultSwapContract; // T:[CM-1] _accountFactory = IAccountFactory(addressProvider.getAccountFactory()); // T:[CM-1] _setParams( _minAmount, _maxAmount, _maxLeverage, Constants.FEE_INTEREST, Constants.FEE_LIQUIDATION, Constants.LIQUIDATION_DISCOUNTED_SUM ); // T:[CM-1] creditFilter = ICreditFilter(_creditFilterAddress); // T:[CM-1] } // // CREDIT ACCOUNT MANAGEMENT // /** * @dev Opens credit account and provides credit funds. * - Opens credit account (take it from account factory^1) * - Transfers trader /farmers initial funds to credit account * - Transfers borrowed leveraged amount from pool (= amount x leverageFactor) calling lendCreditAccount() on connected Pool contract. * - Emits OpenCreditAccount event * Function reverts if user has already opened position * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#open-credit-account * * @param amount Borrowers own funds * @param onBehalfOf The address that we open credit account. Same as msg.sender if the user wants to open it for his own wallet, * or a different address if the beneficiary is a different wallet * @param leverageFactor Multiplier to borrowers own funds * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man * * #if_succeeds {:msg "A credit account with the correct balance is opened."} * let newAccount := creditAccounts[onBehalfOf] in * newAccount != address(0) && * IERC20(underlyingToken).balanceOf(newAccount) >= * amount.add(amount.mul(leverageFactor).div(Constants.LEVERAGE_DECIMALS)); * * #if_succeeds {:msg "Sender looses amount tokens." } * IERC20(underlyingToken).balanceOf(msg.sender) == old(IERC20(underlyingToken).balanceOf(msg.sender)) - amount; * * #if_succeeds {:msg "Pool provides correct leverage (amount x leverageFactor)." } * IERC20(underlyingToken).balanceOf(poolService) == old(IERC20(underlyingToken).balanceOf(poolService)) - amount.mul(leverageFactor).div(Constants.LEVERAGE_DECIMALS); * * #if_succeeds {:msg "The new account is healthy."} * creditFilter.calcCreditAccountHealthFactor(creditAccounts[onBehalfOf]) >= PercentageMath.PERCENTAGE_FACTOR; * * #if_succeeds {:msg "The new account has balance <= 1 for all tokens other than the underlying token."} * let newAccount := creditAccounts[onBehalfOf] in * forall (uint i in 1...creditFilter.allowedTokensCount()) * IERC20(creditFilter.allowedTokens(i)).balanceOf(newAccount) <= 1; */ function openCreditAccount( uint256 amount, address onBehalfOf, uint256 leverageFactor, uint256 referralCode ) external override whenNotPaused // T:[CM-39] nonReentrant { // Checks that amount is in limits require( amount >= minAmount && amount <= maxAmount && leverageFactor > 0 && leverageFactor <= maxLeverageFactor, Errors.CM_INCORRECT_PARAMS ); // T:[CM-2] // Checks that user "onBehalfOf" has no opened accounts // require( // !hasOpenedCreditAccount(onBehalfOf) && onBehalfOf != address(0), // Errors.CM_ZERO_ADDRESS_OR_USER_HAVE_ALREADY_OPEN_CREDIT_ACCOUNT // ); // T:[CM-3] _checkAccountTransfer(onBehalfOf); // borrowedAmount = amount * leverageFactor uint256 borrowedAmount = amount.mul(leverageFactor).div( Constants.LEVERAGE_DECIMALS ); // T:[CM-7] // Get Reusable Credit account creditAccount address creditAccount = _accountFactory.takeCreditAccount( borrowedAmount, IPoolService(poolService).calcLinearCumulative_RAY() ); // T:[CM-5] // Initializes enabled tokens for the account. Enabled tokens is a bit mask which // holds information which tokens were used by user creditFilter.initEnabledTokens(creditAccount); // T:[CM-5] // Transfer pool tokens to new credit account IPoolService(poolService).lendCreditAccount( borrowedAmount, creditAccount ); // T:[CM-7] // Transfer borrower own fund to credit account IERC20(underlyingToken).safeTransferFrom( msg.sender, creditAccount, amount ); // T:[CM-6] // link credit account address with borrower address creditAccounts[onBehalfOf] = creditAccount; // T:[CM-5] // emit new event emit OpenCreditAccount( msg.sender, onBehalfOf, creditAccount, amount, borrowedAmount, referralCode ); // T:[CM-8] } /** * @dev Closes credit account * - Swaps all assets to underlying one using default swap protocol * - Pays borrowed amount + interest accrued + fees back to the pool by calling repayCreditAccount * - Transfers remaining funds to the trader / farmer * - Closes the credit account and return it to account factory * - Emits CloseCreditAccount event * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#close-credit-account * * @param to Address to send remaining funds * @param paths Exchange type data which provides paths + amountMinOut * * #if_succeeds {:msg "Can only be called by account holder"} old(creditAccounts[msg.sender]) != address(0x0); * #if_succeeds {:msg "Can only close healthy accounts" } old(creditFilter.calcCreditAccountHealthFactor(creditAccounts[msg.sender])) > PercentageMath.PERCENTAGE_FACTOR; * #if_succeeds {:msg "If this succeeded the pool gets paid at least borrowed + interest"} * let minAmountOwedToPool := old(borrowedPlusInterest(creditAccounts[msg.sender])) in * IERC20(underlyingToken).balanceOf(poolService) >= old(IERC20(underlyingToken).balanceOf(poolService)).add(minAmountOwedToPool); */ function closeCreditAccount(address to, DataTypes.Exchange[] calldata paths) external override whenNotPaused // T:[CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(msg.sender); // T: [CM-9, 44] // Converts all assets to underlying one. _convertAllAssetsToUnderlying is virtual _convertAllAssetsToUnderlying(creditAccount, paths); // T: [CM-44] // total value equals underlying assets after converting all assets uint256 totalValue = IERC20(underlyingToken).balanceOf(creditAccount); // T: [CM-44] (, uint256 remainingFunds) = _closeCreditAccountImpl( creditAccount, Constants.OPERATION_CLOSURE, totalValue, msg.sender, address(0), to ); // T: [CM-44] emit CloseCreditAccount(msg.sender, to, remainingFunds); // T: [CM-44] } /** * @dev Liquidates credit account * - Transfers discounted total credit account value from liquidators account * - Pays borrowed funds + interest + fees back to pool, than transfers remaining funds to credit account owner * - Transfer all assets from credit account to liquidator ("to") account * - Returns credit account to factory * - Emits LiquidateCreditAccount event * * More info: https://dev.gearbox.fi/developers/credit/credit_manager#liquidate-credit-account * * @param borrower Borrower address * @param to Address to transfer all assets from credit account * * #if_succeeds {:msg "Can only be called by account holder"} old(creditAccounts[msg.sender]) != address(0x0); * #if_succeeds {:msg "Can only liquidate an un-healthy accounts" } old(creditFilter.calcCreditAccountHealthFactor(creditAccounts[msg.sender])) < PercentageMath.PERCENTAGE_FACTOR; */ function liquidateCreditAccount( address borrower, address to, bool force ) external override whenNotPaused // T:[CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(borrower); // T: [CM-9] // transfers assets to "to" address and compute total value (tv) & threshold weighted value (twv) (uint256 totalValue, uint256 tvw) = _transferAssetsTo( creditAccount, to, force ); // T:[CM-13, 16, 17] // Checks that current Hf < 1 require( tvw < creditFilter .calcCreditAccountAccruedInterest(creditAccount) .mul(PercentageMath.PERCENTAGE_FACTOR), Errors.CM_CAN_LIQUIDATE_WITH_SUCH_HEALTH_FACTOR ); // T:[CM-13, 16, 17] // Liquidate credit account (, uint256 remainingFunds) = _closeCreditAccountImpl( creditAccount, Constants.OPERATION_LIQUIDATION, totalValue, borrower, msg.sender, to ); // T:[CM-13] emit LiquidateCreditAccount(borrower, msg.sender, remainingFunds); // T:[CM-13] } /// @dev Repays credit account /// More info: https://dev.gearbox.fi/developers/credit/credit_manager#repay-credit-account /// /// @param to Address to send credit account assets /// #if_succeeds {:msg "Can only be called by account holder"} old(creditAccounts[msg.sender]) != address(0x0); /// #if_succeeds {:msg "If this succeeded the pool gets paid at least borrowed + interest"} /// let minAmountOwedToPool := old(borrowedPlusInterest(creditAccounts[msg.sender])) in /// IERC20(underlyingToken).balanceOf(poolService) >= old(IERC20(underlyingToken).balanceOf(poolService)).add(minAmountOwedToPool); function repayCreditAccount(address to) external override whenNotPaused // T:[CM-39] nonReentrant { _repayCreditAccountImpl(msg.sender, to); // T:[CM-17] } /// @dev Repay credit account with ETH. Restricted to be called by WETH Gateway only /// /// @param borrower Address of borrower /// @param to Address to send credit account assets /// #if_succeeds {:msg "If this succeeded the pool gets paid at least borrowed + interest"} /// let minAmountOwedToPool := old(borrowedPlusInterest(creditAccounts[borrower])) in /// IERC20(underlyingToken).balanceOf(poolService) >= old(IERC20(underlyingToken).balanceOf(poolService)).add(minAmountOwedToPool); function repayCreditAccountETH(address borrower, address to) external override whenNotPaused // T:[CM-39] nonReentrant returns (uint256) { // Checks that msg.sender is WETH Gateway require(msg.sender == wethGateway, Errors.CM_WETH_GATEWAY_ONLY); // T:[CM-38] // Difference with usual Repay is that there is borrower in repay implementation call return _repayCreditAccountImpl(borrower, to); // T:[WG-11] } /// @dev Implements logic for repay credit accounts /// /// @param borrower Borrower address /// @param to Address to transfer assets from credit account function _repayCreditAccountImpl(address borrower, address to) internal returns (uint256) { address creditAccount = getCreditAccountOrRevert(borrower); (uint256 totalValue, ) = _transferAssetsTo(creditAccount, to, false); // T:[CM-17, 23] (uint256 amountToPool, ) = _closeCreditAccountImpl( creditAccount, Constants.OPERATION_REPAY, totalValue, borrower, borrower, to ); // T:[CM-17] emit RepayCreditAccount(borrower, to); // T:[CM-18] return amountToPool; } /// @dev Implementation for all closing account procedures /// #if_succeeds {:msg "Credit account balances should be <= 1 for all allowed tokens after closing"} /// forall (uint i in 0...creditFilter.allowedTokensCount()) /// IERC20(creditFilter.allowedTokens(i)).balanceOf(creditAccount) <= 1; function _closeCreditAccountImpl( address creditAccount, uint8 operation, uint256 totalValue, address borrower, address liquidator, address to ) internal returns (uint256, uint256) { bool isLiquidated = operation == Constants.OPERATION_LIQUIDATION; ( uint256 borrowedAmount, uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss ) = _calcClosePayments(creditAccount, totalValue, isLiquidated); // T:[CM-11, 15, 17] if (operation == Constants.OPERATION_CLOSURE) { ICreditAccount(creditAccount).safeTransfer( underlyingToken, poolService, amountToPool ); // T:[CM-11] // close operation with loss is not allowed require(remainingFunds > 0, Errors.CM_CANT_CLOSE_WITH_LOSS); // T:[CM-42] // transfer remaining funds to borrower _safeTokenTransfer( creditAccount, underlyingToken, to, remainingFunds, false ); // T:[CM-11] } // LIQUIDATION else if (operation == Constants.OPERATION_LIQUIDATION) { // repay amount to pool IERC20(underlyingToken).safeTransferFrom( liquidator, poolService, amountToPool ); // T:[CM-14] // transfer remaining funds to borrower if (remainingFunds > 0) { IERC20(underlyingToken).safeTransferFrom( liquidator, borrower, remainingFunds ); //T:[CM-14] } } // REPAY else { // repay amount to pool IERC20(underlyingToken).safeTransferFrom( msg.sender, // msg.sender in case of WETH Gateway poolService, amountToPool ); // T:[CM-17] } // Return creditAccount _accountFactory.returnCreditAccount(creditAccount); // T:[CM-21] // Release memory delete creditAccounts[borrower]; // T:[CM-27] // Transfer pool tokens to new credit account IPoolService(poolService).repayCreditAccount( borrowedAmount, profit, loss ); // T:[CM-11, 15] return (amountToPool, remainingFunds); // T:[CM-11] } /// @dev Collects data and call calc payments pure function during closure procedures /// @param creditAccount Credit account address /// @param totalValue Credit account total value /// @param isLiquidated True if calculations needed for liquidation function _calcClosePayments( address creditAccount, uint256 totalValue, bool isLiquidated ) public view returns ( uint256 _borrowedAmount, uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss ) { // Gets credit account parameters ( uint256 borrowedAmount, uint256 cumulativeIndexAtCreditAccountOpen_RAY ) = getCreditAccountParameters(creditAccount); // T:[CM-13] return _calcClosePaymentsPure( totalValue, isLiquidated, borrowedAmount, cumulativeIndexAtCreditAccountOpen_RAY, IPoolService(poolService).calcLinearCumulative_RAY() ); } /// @dev Computes all close parameters based on data /// @param totalValue Credit account total value /// @param isLiquidated True if calculations needed for liquidation /// @param borrowedAmount Credit account borrow amount /// @param cumulativeIndexAtCreditAccountOpen_RAY Cumulative index at opening credit account in RAY format /// @param cumulativeIndexNow_RAY Current value of cumulative index in RAY format function _calcClosePaymentsPure( uint256 totalValue, bool isLiquidated, uint256 borrowedAmount, uint256 cumulativeIndexAtCreditAccountOpen_RAY, uint256 cumulativeIndexNow_RAY ) public view returns ( uint256 _borrowedAmount, uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss ) { uint256 totalFunds = isLiquidated ? totalValue.mul(liquidationDiscount).div( PercentageMath.PERCENTAGE_FACTOR ) : totalValue; // T:[CM-45] _borrowedAmount = borrowedAmount; // T:[CM-45] uint256 borrowedAmountWithInterest = borrowedAmount .mul(cumulativeIndexNow_RAY) .div(cumulativeIndexAtCreditAccountOpen_RAY); // T:[CM-45] if (totalFunds < borrowedAmountWithInterest) { amountToPool = totalFunds.sub(1); // T:[CM-45] loss = borrowedAmountWithInterest.sub(amountToPool); // T:[CM-45] } else { amountToPool = isLiquidated ? totalFunds.percentMul(feeLiquidation).add( borrowedAmountWithInterest ) : borrowedAmountWithInterest.add( borrowedAmountWithInterest.sub(borrowedAmount).percentMul( feeInterest ) ); // T:[CM-45] if (totalFunds > amountToPool) { remainingFunds = totalFunds.sub(amountToPool).sub(1); // T:[CM-45] } else { amountToPool = totalFunds.sub(1); // T:[CM-45] } profit = amountToPool.sub(borrowedAmountWithInterest); // T:[CM-45] } } /// @dev Transfers all assets from borrower credit account to "to" account and converts WETH => ETH if applicable /// @param creditAccount Credit account address /// @param to Address to transfer all assets to function _transferAssetsTo( address creditAccount, address to, bool force ) internal returns (uint256 totalValue, uint256 totalWeightedValue) { uint256 tokenMask; uint256 enabledTokens = creditFilter.enabledTokens(creditAccount); require(to != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED); for (uint256 i = 0; i < creditFilter.allowedTokensCount(); i++) { tokenMask = 1 << i; if (enabledTokens & tokenMask > 0) { ( address token, uint256 amount, uint256 tv, uint256 tvw ) = creditFilter.getCreditAccountTokenById(creditAccount, i); // T:[CM-14, 17, 22, 23] if (amount > 1) { if ( _safeTokenTransfer( creditAccount, token, to, amount.sub(1), // Michael Egorov gas efficiency trick force ) ) { totalValue = totalValue.add(tv); // T:[CM-14, 17, 22, 23] totalWeightedValue = totalWeightedValue.add(tvw); // T:[CM-14, 17, 22, 23] } } } } } /// @dev Transfers token to particular address from credit account and converts WETH => ETH if applicable /// @param creditAccount Address of credit account /// @param token Token address /// @param to Address to transfer asset /// @param amount Amount to be transferred /// @param force If true it will skip reverts of safeTransfer function. Used for force liquidation if there is /// a blocked token on creditAccount /// @return true if transfer were successful otherwise false function _safeTokenTransfer( address creditAccount, address token, address to, uint256 amount, bool force ) internal returns (bool) { if (token != wethAddress) { try ICreditAccount(creditAccount).safeTransfer(token, to, amount) // T:[CM-14, 17] {} catch { require(force, Errors.CM_TRANSFER_FAILED); // T:[CM-50] return false; } } else { ICreditAccount(creditAccount).safeTransfer( token, wethGateway, amount ); // T:[CM-22, 23] IWETHGateway(wethGateway).unwrapWETH(to, amount); // T:[CM-22, 23] } return true; } /// @dev Increases borrowed amount by transferring additional funds from /// the pool if after that HealthFactor > minHealth /// More info: https://dev.gearbox.fi/developers/credit/credit_manager#increase-borrowed-amount /// /// @param amount Amount to increase borrowed amount function increaseBorrowedAmount(uint256 amount) external override whenNotPaused // T:[CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(msg.sender); // T: [CM-9, 30] ( uint256 borrowedAmount, uint256 cumulativeIndexAtOpen ) = getCreditAccountParameters(creditAccount); // T:[CM-30] // uint256 newBorrowedAmount = borrowedAmount.add(amount); uint256 newCumulativeIndex = IPoolService(poolService) .calcCumulativeIndexAtBorrowMore( borrowedAmount, amount, cumulativeIndexAtOpen ); // T:[CM-30] require( newBorrowedAmount.mul(Constants.LEVERAGE_DECIMALS) < maxAmount.mul(maxLeverageFactor), Errors.CM_INCORRECT_AMOUNT ); // T:[CM-51] // // Increase _totalBorrowed, it used to compute forecasted interest IPoolService(poolService).lendCreditAccount(amount, creditAccount); // T:[CM-29] // // Set parameters for new credit account ICreditAccount(creditAccount).updateParameters( newBorrowedAmount, newCumulativeIndex ); // T:[CM-30] // creditFilter.revertIfCantIncreaseBorrowing( creditAccount, minHealthFactor ); // T:[CM-28] emit IncreaseBorrowedAmount(msg.sender, amount); // T:[CM-29] } /// @dev Adds collateral to borrower's credit account /// @param onBehalfOf Address of borrower to add funds /// @param token Token address /// @param amount Amount to add function addCollateral( address onBehalfOf, address token, uint256 amount ) external override whenNotPaused // T:[CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(onBehalfOf); // T: [CM-9] creditFilter.checkAndEnableToken(creditAccount, token); // T:[CM-48] IERC20(token).safeTransferFrom(msg.sender, creditAccount, amount); // T:[CM-48] emit AddCollateral(onBehalfOf, token, amount); // T: [CM-48] } /// @dev Sets fees. Restricted for configurator role only /// @param _minAmount Minimum amount to open account /// @param _maxAmount Maximum amount to open account /// @param _maxLeverageFactor Maximum leverage factor /// @param _feeInterest Interest fee multiplier /// @param _feeLiquidation Liquidation fee multiplier (for totalValue) /// @param _liquidationDiscount Liquidation premium multiplier (= PERCENTAGE_FACTOR - premium) function setParams( uint256 _minAmount, uint256 _maxAmount, uint256 _maxLeverageFactor, uint256 _feeInterest, uint256 _feeLiquidation, uint256 _liquidationDiscount ) public configuratorOnly // T:[CM-36] { _setParams( _minAmount, _maxAmount, _maxLeverageFactor, _feeInterest, _feeLiquidation, _liquidationDiscount ); } function _setParams( uint256 _minAmount, uint256 _maxAmount, uint256 _maxLeverageFactor, uint256 _feeInterest, uint256 _feeLiquidation, uint256 _liquidationDiscount ) internal { require( _minAmount <= _maxAmount && _maxLeverageFactor > 0, Errors.CM_INCORRECT_PARAMS ); // T:[CM-34] minAmount = _minAmount; // T:[CM-32] maxAmount = _maxAmount; // T:[CM-32] maxLeverageFactor = _maxLeverageFactor; feeInterest = _feeInterest; // T:[CM-37] feeLiquidation = _feeLiquidation; // T:[CM-37] liquidationDiscount = _liquidationDiscount; // T:[CM-37] // Compute minHealthFactor: https://dev.gearbox.fi/developers/credit/credit_manager#increase-borrow-amount // LT_U = liquidationDiscount - feeLiquidation minHealthFactor = liquidationDiscount .sub(feeLiquidation) .mul(maxLeverageFactor.add(Constants.LEVERAGE_DECIMALS)) .div(maxLeverageFactor); // T:[CM-41] if (address(creditFilter) != address(0)) { creditFilter.updateUnderlyingTokenLiquidationThreshold(); // T:[CM-49] } emit NewParameters( minAmount, maxAmount, maxLeverageFactor, feeInterest, feeLiquidation, liquidationDiscount ); // T:[CM-37] } /// @dev Approves credit account for 3rd party contract /// @param targetContract Contract to check allowance /// @param token Token address of contract function approve(address targetContract, address token) external override whenNotPaused // T:[CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(msg.sender); // Checks that targetContract is allowed - it has non-zero address adapter require( creditFilter.contractToAdapter(targetContract) != address(0), Errors.CM_TARGET_CONTRACT_iS_NOT_ALLOWED ); creditFilter.revertIfTokenNotAllowed(token); // ToDo: add test _provideCreditAccountAllowance(creditAccount, targetContract, token); } /// @dev Approve tokens for credit accounts. Restricted for adapters only /// @param creditAccount Credit account address /// @param targetContract Contract to check allowance /// @param token Token address of contract function provideCreditAccountAllowance( address creditAccount, address targetContract, address token ) external override allowedAdaptersOnly(targetContract) // T:[CM-46] whenNotPaused // T:[CM-39] nonReentrant { _provideCreditAccountAllowance(creditAccount, targetContract, token); // T:[CM-35] } /// @dev Checks that credit account has enough allowance for operation by comparing existing one with x10 times more than needed /// @param creditAccount Credit account address /// @param toContract Contract to check allowance /// @param token Token address of contract function _provideCreditAccountAllowance( address creditAccount, address toContract, address token ) internal { // Get 10x reserve in allowance if ( IERC20(token).allowance(creditAccount, toContract) < Constants.MAX_INT_4 ) { ICreditAccount(creditAccount).approveToken(token, toContract); // T:[CM-35] } } /// @dev Converts all assets to underlying one using uniswap V2 protocol /// @param creditAccount Credit Account address /// @param paths Exchange type data which provides paths + amountMinOut function _convertAllAssetsToUnderlying( address creditAccount, DataTypes.Exchange[] calldata paths ) internal { uint256 tokenMask; uint256 enabledTokens = creditFilter.enabledTokens(creditAccount); // T: [CM-44] require( paths.length == creditFilter.allowedTokensCount(), Errors.INCORRECT_PATH_LENGTH ); // ToDo: check for (uint256 i = 1; i < paths.length; i++) { tokenMask = 1 << i; if (enabledTokens & tokenMask > 0) { (address tokenAddr, uint256 amount, , ) = creditFilter .getCreditAccountTokenById(creditAccount, i); // T: [CM-44] if (amount > 1) { _provideCreditAccountAllowance( creditAccount, defaultSwapContract, tokenAddr ); // T: [CM-44] address[] memory currentPath = paths[i].path; currentPath[0] = tokenAddr; currentPath[paths[i].path.length - 1] = underlyingToken; bytes memory data = abi.encodeWithSelector( bytes4(0x38ed1739), // "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)", amount.sub(1), paths[i].amountOutMin, // T: [CM-45] currentPath, creditAccount, block.timestamp ); // T: [CM-44] ICreditAccount(creditAccount).execute( defaultSwapContract, data ); // T: [CM-44] } } } } /// @dev Executes filtered order on credit account which is connected with particular borrower /// @param borrower Borrower address /// @param target Target smart-contract /// @param data Call data for call function executeOrder( address borrower, address target, bytes memory data ) external override allowedAdaptersOnly(target) // T:[CM-46] whenNotPaused // T:[CM-39] nonReentrant returns (bytes memory) { address creditAccount = getCreditAccountOrRevert(borrower); // T:[CM-9] emit ExecuteOrder(borrower, target); return ICreditAccount(creditAccount).execute(target, data); // : [CM-47] } // // GETTERS // /// @dev Returns true if the borrower has opened a credit account /// @param borrower Borrower account function hasOpenedCreditAccount(address borrower) public view override returns (bool) { return creditAccounts[borrower] != address(0); // T:[CM-26] } /// @dev Returns address of borrower's credit account and reverts of borrower has no one. /// @param borrower Borrower address function getCreditAccountOrRevert(address borrower) public view override returns (address) { address result = creditAccounts[borrower]; // T: [CM-9] require(result != address(0), Errors.CM_NO_OPEN_ACCOUNT); // T: [CM-9] return result; } /// @dev Calculates repay / liquidation amount /// repay amount = borrow amount + interest accrued + fee amount /// /// More info: https://dev.gearbox.fi/developers/credit/economy#repay /// https://dev.gearbox.fi/developers/credit/economy#liquidate /// @param borrower Borrower address /// @param isLiquidated True if calculated repay amount for liquidator function calcRepayAmount(address borrower, bool isLiquidated) external view override returns (uint256) { address creditAccount = getCreditAccountOrRevert(borrower); uint256 totalValue = creditFilter.calcTotalValue(creditAccount); ( , uint256 amountToPool, uint256 remainingFunds, , ) = _calcClosePayments(creditAccount, totalValue, isLiquidated); // T:[CM-14, 17, 31] return isLiquidated ? amountToPool.add(remainingFunds) : amountToPool; // T:[CM-14, 17, 31] } /// @dev Gets credit account generic parameters /// @param creditAccount Credit account address /// @return borrowedAmount Amount which pool lent to credit account /// @return cumulativeIndexAtOpen Cumulative index at open. Used for interest calculation function getCreditAccountParameters(address creditAccount) internal view returns (uint256 borrowedAmount, uint256 cumulativeIndexAtOpen) { borrowedAmount = ICreditAccount(creditAccount).borrowedAmount(); cumulativeIndexAtOpen = ICreditAccount(creditAccount) .cumulativeIndexAtOpen(); } /// @dev Transfers account ownership to another account /// @param newOwner Address of new owner function transferAccountOwnership(address newOwner) external override whenNotPaused // T: [CM-39] nonReentrant { address creditAccount = getCreditAccountOrRevert(msg.sender); // M:[LA-1,2,3,4,5,6,7,8] // T:[CM-52,53, 54] _checkAccountTransfer(newOwner); delete creditAccounts[msg.sender]; // T:[CM-54], M:[LA-1,2,3,4,5,6,7,8] creditAccounts[newOwner] = creditAccount; // T:[CM-54], M:[LA-1,2,3,4,5,6,7,8] emit TransferAccount(msg.sender, newOwner); // T:[CM-54] } function _checkAccountTransfer(address newOwner) internal view { require( newOwner != address(0) && !hasOpenedCreditAccount(newOwner), Errors.CM_ZERO_ADDRESS_OR_USER_HAVE_ALREADY_OPEN_CREDIT_ACCOUNT ); // T:[CM-52,53] if (msg.sender != newOwner) { creditFilter.revertIfAccountTransferIsNotAllowed( msg.sender, newOwner ); // T:[54,55] } } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {IAppPoolService} from "./app/IAppPoolService.sol"; /// @title Pool Service Interface /// @notice Implements business logic: /// - Adding/removing pool liquidity /// - Managing diesel tokens & diesel rates /// - Lending/repaying funds to credit Manager /// More: https://dev.gearbox.fi/developers/pool/abstractpoolservice interface IPoolService is IAppPoolService { // Emits each time when LP adds liquidity to the pool event AddLiquidity( address indexed sender, address indexed onBehalfOf, uint256 amount, uint256 referralCode ); // Emits each time when LP removes liquidity to the pool event RemoveLiquidity( address indexed sender, address indexed to, uint256 amount ); // Emits each time when Credit Manager borrows money from pool event Borrow( address indexed creditManager, address indexed creditAccount, uint256 amount ); // Emits each time when Credit Manager repays money from pool event Repay( address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss ); // Emits each time when Interest Rate model was changed event NewInterestRateModel(address indexed newInterestRateModel); // Emits each time when new credit Manager was connected event NewCreditManagerConnected(address indexed creditManager); // Emits each time when borrow forbidden for credit manager event BorrowForbidden(address indexed creditManager); // Emits each time when uncovered (non insured) loss accrued event UncoveredLoss(address indexed creditManager, uint256 loss); // Emits after expected liquidity limit update event NewExpectedLiquidityLimit(uint256 newLimit); // Emits each time when withdraw fee is udpated event NewWithdrawFee(uint256 fee); // // LIQUIDITY MANAGEMENT // /** * @dev Adds liquidity to pool * - transfers lp tokens to pool * - mint diesel (LP) tokens and provide them * @param amount Amount of tokens to be transfer * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man */ function addLiquidity( uint256 amount, address onBehalfOf, uint256 referralCode ) external override; /** * @dev Removes liquidity from pool * - burns lp's diesel (LP) tokens * - returns underlying tokens to lp * @param amount Amount of tokens to be transfer * @param to Address to transfer liquidity */ function removeLiquidity(uint256 amount, address to) external override returns (uint256); /** * @dev Transfers money from the pool to credit account * and updates the pool parameters * @param borrowedAmount Borrowed amount for credit account * @param creditAccount Credit account address */ function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external; /** * @dev Recalculates total borrowed & borrowRate * mints/burns diesel tokens */ function repayCreditAccount( uint256 borrowedAmount, uint256 profit, uint256 loss ) external; // // GETTERS // /** * @return expected pool liquidity */ function expectedLiquidity() external view returns (uint256); /** * @return expected liquidity limit */ function expectedLiquidityLimit() external view returns (uint256); /** * @dev Gets available liquidity in the pool (pool balance) * @return available pool liquidity */ function availableLiquidity() external view returns (uint256); /** * @dev Calculates interest accrued from the last update using the linear model */ function calcLinearCumulative_RAY() external view returns (uint256); /** * @dev Calculates borrow rate * @return borrow rate in RAY format */ function borrowAPY_RAY() external view returns (uint256); /** * @dev Gets the amount of total borrowed funds * @return Amount of borrowed funds at current time */ function totalBorrowed() external view returns (uint256); /** * @return Current diesel rate **/ function getDieselRate_RAY() external view returns (uint256); /** * @dev Underlying token address getter * @return address of underlying ERC-20 token */ function underlyingToken() external view returns (address); /** * @dev Diesel(LP) token address getter * @return address of diesel(LP) ERC-20 token */ function dieselToken() external view returns (address); /** * @dev Credit Manager address getter * @return address of Credit Manager contract by id */ function creditManagers(uint256 id) external view returns (address); /** * @dev Credit Managers quantity * @return quantity of connected credit Managers */ function creditManagersCount() external view returns (uint256); function creditManagersCanBorrow(address id) external view returns (bool); function toDiesel(uint256 amount) external view returns (uint256); function fromDiesel(uint256 amount) external view returns (uint256); function withdrawFee() external view returns (uint256); function _timestampLU() external view returns (uint256); function _cumulativeIndex_RAY() external view returns (uint256); function calcCumulativeIndexAtBorrowMore( uint256 amount, uint256 dAmount, uint256 cumulativeIndexAtOpen ) external view returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; interface ICreditFilter { // Emits each time token is allowed or liquidtion threshold changed event TokenAllowed(address indexed token, uint256 liquidityThreshold); // Emits each time token is allowed or liquidtion threshold changed event TokenForbidden(address indexed token); // Emits each time contract is allowed or adapter changed event ContractAllowed(address indexed protocol, address indexed adapter); // Emits each time contract is forbidden event ContractForbidden(address indexed protocol); // Emits each time when fast check parameters are updated event NewFastCheckParameters(uint256 chiThreshold, uint256 fastCheckDelay); event TransferAccountAllowed( address indexed from, address indexed to, bool state ); event TransferPluginAllowed( address indexed pugin, bool state ); event PriceOracleUpdated(address indexed newPriceOracle); // // STATE-CHANGING FUNCTIONS // /// @dev Adds token to the list of allowed tokens /// @param token Address of allowed token /// @param liquidationThreshold The constant showing the maximum allowable ratio of Loan-To-Value for the i-th asset. function allowToken(address token, uint256 liquidationThreshold) external; /// @dev Adds contract to the list of allowed contracts /// @param targetContract Address of contract to be allowed /// @param adapter Adapter contract address function allowContract(address targetContract, address adapter) external; /// @dev Forbids contract and removes it from the list of allowed contracts /// @param targetContract Address of allowed contract function forbidContract(address targetContract) external; /// @dev Checks financial order and reverts if tokens aren't in list or collateral protection alerts /// @param creditAccount Address of credit account /// @param tokenIn Address of token In in swap operation /// @param tokenOut Address of token Out in swap operation /// @param amountIn Amount of tokens in /// @param amountOut Amount of tokens out function checkCollateralChange( address creditAccount, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut ) external; function checkMultiTokenCollateral( address creditAccount, uint256[] memory amountIn, uint256[] memory amountOut, address[] memory tokenIn, address[] memory tokenOut ) external; /// @dev Connects credit managaer, hecks that all needed price feeds exists and finalize config function connectCreditManager(address poolService) external; /// @dev Sets collateral protection for new credit accounts function initEnabledTokens(address creditAccount) external; function checkAndEnableToken(address creditAccount, address token) external; // // GETTERS // /// @dev Returns quantity of contracts in allowed list function allowedContractsCount() external view returns (uint256); /// @dev Returns of contract address from the allowed list by its id function allowedContracts(uint256 id) external view returns (address); /// @dev Reverts if token isn't in token allowed list function revertIfTokenNotAllowed(address token) external view; /// @dev Returns true if token is in allowed list otherwise false function isTokenAllowed(address token) external view returns (bool); /// @dev Returns quantity of tokens in allowed list function allowedTokensCount() external view returns (uint256); /// @dev Returns of token address from allowed list by its id function allowedTokens(uint256 id) external view returns (address); /// @dev Calculates total value for provided address /// More: https://dev.gearbox.fi/developers/credit/economy#total-value /// /// @param creditAccount Token creditAccount address function calcTotalValue(address creditAccount) external view returns (uint256 total); /// @dev Calculates Threshold Weighted Total Value /// More: https://dev.gearbox.fi/developers/credit/economy#threshold-weighted-value /// ///@param creditAccount Credit account address function calcThresholdWeightedValue(address creditAccount) external view returns (uint256 total); function contractToAdapter(address allowedContract) external view returns (address); /// @dev Returns address of underlying token function underlyingToken() external view returns (address); /// @dev Returns address & balance of token by the id of allowed token in the list /// @param creditAccount Credit account address /// @param id Id of token in allowed list /// @return token Address of token /// @return balance Token balance function getCreditAccountTokenById(address creditAccount, uint256 id) external view returns ( address token, uint256 balance, uint256 tv, uint256 twv ); /** * @dev Calculates health factor for the credit account * * sum(asset[i] * liquidation threshold[i]) * Hf = -------------------------------------------- * borrowed amount + interest accrued * * * More info: https://dev.gearbox.fi/developers/credit/economy#health-factor * * @param creditAccount Credit account address * @return Health factor in percents (see PERCENTAGE FACTOR in PercentageMath.sol) */ function calcCreditAccountHealthFactor(address creditAccount) external view returns (uint256); /// @dev Calculates credit account interest accrued /// More: https://dev.gearbox.fi/developers/credit/economy#interest-rate-accrued /// /// @param creditAccount Credit account address function calcCreditAccountAccruedInterest(address creditAccount) external view returns (uint256); /// @dev Return enabled tokens - token masks where each bit is "1" is token is enabled function enabledTokens(address creditAccount) external view returns (uint256); function liquidationThresholds(address token) external view returns (uint256); function priceOracle() external view returns (address); function updateUnderlyingTokenLiquidationThreshold() external; function revertIfCantIncreaseBorrowing( address creditAccount, uint256 minHealthFactor ) external view; function revertIfAccountTransferIsNotAllowed( address onwer, address creditAccount ) external view; function approveAccountTransfers(address from, bool state) external; function allowanceForAccountTransfers(address from, address to) external view returns (bool); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title Price oracle interface interface IPriceOracle { // Emits each time new configurator is set up event NewPriceFeed(address indexed token, address indexed priceFeed); /** * @dev Sets price feed if it doesn't exists * If pricefeed exists, it changes nothing * This logic is done to protect Gearbox from priceOracle attack * when potential attacker can get access to price oracle, change them to fraud ones * and then liquidate all funds * @param token Address of token * @param priceFeedToken Address of chainlink price feed token => Eth */ function addPriceFeed(address token, address priceFeedToken) external; /** * @dev Converts one asset into another using rate. Reverts if price feed doesn't exist * * @param amount Amount to convert * @param tokenFrom Token address converts from * @param tokenTo Token address - converts to * @return Amount converted to tokenTo asset */ function convert( uint256 amount, address tokenFrom, address tokenTo ) external view returns (uint256); /** * @dev Gets token rate with 18 decimals. Reverts if priceFeed doesn't exist * * @param tokenFrom Converts from token address * @param tokenTo Converts to token address * @return Rate in WAD format */ function getLastPrice(address tokenFrom, address tokenTo) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {IAppAddressProvider} from "../interfaces/app/IAppAddressProvider.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; /// @title AddressRepository /// @notice Stores addresses of deployed contracts contract AddressProvider is Ownable, IAppAddressProvider { // Mapping which keeps all addresses mapping(bytes32 => address) public addresses; // Emits each time when new address is set event AddressSet(bytes32 indexed service, address indexed newAddress); // This event is triggered when a call to ClaimTokens succeeds. event Claimed(uint256 user_id, address account, uint256 amount, bytes32 leaf); // Repositories & services bytes32 public constant CONTRACTS_REGISTER = "CONTRACTS_REGISTER"; bytes32 public constant ACL = "ACL"; bytes32 public constant PRICE_ORACLE = "PRICE_ORACLE"; bytes32 public constant ACCOUNT_FACTORY = "ACCOUNT_FACTORY"; bytes32 public constant DATA_COMPRESSOR = "DATA_COMPRESSOR"; bytes32 public constant TREASURY_CONTRACT = "TREASURY_CONTRACT"; bytes32 public constant GEAR_TOKEN = "GEAR_TOKEN"; bytes32 public constant WETH_TOKEN = "WETH_TOKEN"; bytes32 public constant WETH_GATEWAY = "WETH_GATEWAY"; bytes32 public constant LEVERAGED_ACTIONS = "LEVERAGED_ACTIONS"; // Contract version uint256 public constant version = 1; constructor() { // @dev Emits first event for contract discovery emit AddressSet("ADDRESS_PROVIDER", address(this)); } /// @return Address of ACL contract function getACL() external view returns (address) { return _getAddress(ACL); // T:[AP-3] } /// @dev Sets address of ACL contract /// @param _address Address of ACL contract function setACL(address _address) external onlyOwner // T:[AP-15] { _setAddress(ACL, _address); // T:[AP-3] } /// @return Address of ContractsRegister function getContractsRegister() external view returns (address) { return _getAddress(CONTRACTS_REGISTER); // T:[AP-4] } /// @dev Sets address of ContractsRegister /// @param _address Address of ContractsRegister function setContractsRegister(address _address) external onlyOwner // T:[AP-15] { _setAddress(CONTRACTS_REGISTER, _address); // T:[AP-4] } /// @return Address of PriceOracle function getPriceOracle() external view override returns (address) { return _getAddress(PRICE_ORACLE); // T:[AP-5] } /// @dev Sets address of PriceOracle /// @param _address Address of PriceOracle function setPriceOracle(address _address) external onlyOwner // T:[AP-15] { _setAddress(PRICE_ORACLE, _address); // T:[AP-5] } /// @return Address of AccountFactory function getAccountFactory() external view returns (address) { return _getAddress(ACCOUNT_FACTORY); // T:[AP-6] } /// @dev Sets address of AccountFactory /// @param _address Address of AccountFactory function setAccountFactory(address _address) external onlyOwner // T:[AP-15] { _setAddress(ACCOUNT_FACTORY, _address); // T:[AP-7] } /// @return Address of AccountFactory function getDataCompressor() external view override returns (address) { return _getAddress(DATA_COMPRESSOR); // T:[AP-8] } /// @dev Sets address of AccountFactory /// @param _address Address of AccountFactory function setDataCompressor(address _address) external onlyOwner // T:[AP-15] { _setAddress(DATA_COMPRESSOR, _address); // T:[AP-8] } /// @return Address of Treasury contract function getTreasuryContract() external view returns (address) { return _getAddress(TREASURY_CONTRACT); //T:[AP-11] } /// @dev Sets address of Treasury Contract /// @param _address Address of Treasury Contract function setTreasuryContract(address _address) external onlyOwner // T:[AP-15] { _setAddress(TREASURY_CONTRACT, _address); //T:[AP-11] } /// @return Address of GEAR token function getGearToken() external view override returns (address) { return _getAddress(GEAR_TOKEN); // T:[AP-12] } /// @dev Sets address of GEAR token /// @param _address Address of GEAR token function setGearToken(address _address) external onlyOwner // T:[AP-15] { _setAddress(GEAR_TOKEN, _address); // T:[AP-12] } /// @return Address of WETH token function getWethToken() external view override returns (address) { return _getAddress(WETH_TOKEN); // T:[AP-13] } /// @dev Sets address of WETH token /// @param _address Address of WETH token function setWethToken(address _address) external onlyOwner // T:[AP-15] { _setAddress(WETH_TOKEN, _address); // T:[AP-13] } /// @return Address of WETH token function getWETHGateway() external view override returns (address) { return _getAddress(WETH_GATEWAY); // T:[AP-14] } /// @dev Sets address of WETH token /// @param _address Address of WETH token function setWETHGateway(address _address) external onlyOwner // T:[AP-15] { _setAddress(WETH_GATEWAY, _address); // T:[AP-14] } /// @return Address of WETH token function getLeveragedActions() external view override returns (address) { return _getAddress(LEVERAGED_ACTIONS); // T:[AP-7] } /// @dev Sets address of WETH token /// @param _address Address of WETH token function setLeveragedActions(address _address) external onlyOwner // T:[AP-15] { _setAddress(LEVERAGED_ACTIONS, _address); // T:[AP-7] } /// @return Address of key, reverts if key doesn't exist function _getAddress(bytes32 key) internal view returns (address) { address result = addresses[key]; require(result != address(0), Errors.AS_ADDRESS_NOT_FOUND); // T:[AP-1] return result; // T:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] } /// @dev Sets address to map by its key /// @param key Key in string format /// @param value Address function _setAddress(bytes32 key, address value) internal { addresses[key] = value; // T:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] emit AddressSet(key, value); // T:[AP-2] } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {Errors} from "../libraries/helpers/Errors.sol"; import {ACLTrait} from "./ACLTrait.sol"; /// @title Pools & Contract managers registry /// @notice Keeps pools & contract manager addresses contract ContractsRegister is ACLTrait { // Pools list address[] public pools; mapping(address => bool) public isPool; // Credit Managers list address[] public creditManagers; mapping(address => bool) public isCreditManager; // Contract version uint256 public constant version = 1; // emits each time when new pool was added to register event NewPoolAdded(address indexed pool); // emits each time when new credit Manager was added to register event NewCreditManagerAdded(address indexed creditManager); constructor(address addressProvider) ACLTrait(addressProvider) {} /// @dev Adds pool to list /// @param newPoolAddress Address on new pool added function addPool(address newPoolAddress) external configuratorOnly // T:[CR-1] { require( newPoolAddress != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED ); require(!isPool[newPoolAddress], Errors.CR_POOL_ALREADY_ADDED); // T:[CR-2] pools.push(newPoolAddress); // T:[CR-3] isPool[newPoolAddress] = true; // T:[CR-3] emit NewPoolAdded(newPoolAddress); // T:[CR-4] } /// @dev Returns array of registered pool addresses function getPools() external view returns (address[] memory) { return pools; } /// @return Returns quantity of registered pools function getPoolsCount() external view returns (uint256) { return pools.length; // T:[CR-3] } /// @dev Adds credit accounts manager address to the registry /// @param newCreditManager Address on new pausableAdmin added function addCreditManager(address newCreditManager) external configuratorOnly // T:[CR-1] { require( newCreditManager != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED ); require( !isCreditManager[newCreditManager], Errors.CR_CREDIT_MANAGER_ALREADY_ADDED ); // T:[CR-5] creditManagers.push(newCreditManager); // T:[CR-6] isCreditManager[newCreditManager] = true; // T:[CR-6] emit NewCreditManagerAdded(newCreditManager); // T:[CR-7] } /// @dev Returns array of registered credit manager addresses function getCreditManagers() external view returns (address[] memory) { return creditManagers; } /// @return Returns quantity of registered credit managers function getCreditManagersCount() external view returns (uint256) { return creditManagers.length; // T:[CR-6] } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title DataType library /// @notice Contains data types used in data compressor. library DataTypes { struct Exchange { address[] path; uint256 amountOutMin; } struct TokenBalance { address token; uint256 balance; bool isAllowed; } struct ContractAdapter { address allowedContract; address adapter; } struct CreditAccountData { address addr; address borrower; bool inUse; address creditManager; address underlyingToken; uint256 borrowedAmountPlusInterest; uint256 totalValue; uint256 healthFactor; uint256 borrowRate; TokenBalance[] balances; } struct CreditAccountDataExtended { address addr; address borrower; bool inUse; address creditManager; address underlyingToken; uint256 borrowedAmountPlusInterest; uint256 totalValue; uint256 healthFactor; uint256 borrowRate; TokenBalance[] balances; uint256 repayAmount; uint256 liquidationAmount; bool canBeClosed; uint256 borrowedAmount; uint256 cumulativeIndexAtOpen; uint256 since; } struct CreditManagerData { address addr; bool hasAccount; address underlyingToken; bool isWETH; bool canBorrow; uint256 borrowRate; uint256 minAmount; uint256 maxAmount; uint256 maxLeverageFactor; uint256 availableLiquidity; address[] allowedTokens; ContractAdapter[] adapters; } struct PoolData { address addr; bool isWETH; address underlyingToken; address dieselToken; uint256 linearCumulativeIndex; uint256 availableLiquidity; uint256 expectedLiquidity; uint256 expectedLiquidityLimit; uint256 totalBorrowed; uint256 depositAPY_RAY; uint256 borrowAPY_RAY; uint256 dieselRate_RAY; uint256 withdrawFee; uint256 cumulativeIndex_RAY; uint256 timestampLU; } struct TokenInfo { address addr; string symbol; uint8 decimals; } struct AddressProviderData { address contractRegister; address acl; address priceOracle; address traderAccountFactory; address dataCompressor; address farmingFactory; address accountMiner; address treasuryContract; address gearToken; address wethToken; address wethGateway; } struct MiningApproval { address token; address swapContract; } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title Errors library library Errors { // // COMMON // string public constant ZERO_ADDRESS_IS_NOT_ALLOWED = "Z0"; string public constant NOT_IMPLEMENTED = "NI"; string public constant INCORRECT_PATH_LENGTH = "PL"; string public constant INCORRECT_ARRAY_LENGTH = "CR"; string public constant REGISTERED_CREDIT_ACCOUNT_MANAGERS_ONLY = "CP"; string public constant REGISTERED_POOLS_ONLY = "RP"; string public constant INCORRECT_PARAMETER = "IP"; // // MATH // string public constant MATH_MULTIPLICATION_OVERFLOW = "M1"; string public constant MATH_ADDITION_OVERFLOW = "M2"; string public constant MATH_DIVISION_BY_ZERO = "M3"; // // POOL // string public constant POOL_CONNECTED_CREDIT_MANAGERS_ONLY = "PS0"; string public constant POOL_INCOMPATIBLE_CREDIT_ACCOUNT_MANAGER = "PS1"; string public constant POOL_MORE_THAN_EXPECTED_LIQUIDITY_LIMIT = "PS2"; string public constant POOL_INCORRECT_WITHDRAW_FEE = "PS3"; string public constant POOL_CANT_ADD_CREDIT_MANAGER_TWICE = "PS4"; // // CREDIT MANAGER // string public constant CM_NO_OPEN_ACCOUNT = "CM1"; string public constant CM_ZERO_ADDRESS_OR_USER_HAVE_ALREADY_OPEN_CREDIT_ACCOUNT = "CM2"; string public constant CM_INCORRECT_AMOUNT = "CM3"; string public constant CM_CAN_LIQUIDATE_WITH_SUCH_HEALTH_FACTOR = "CM4"; string public constant CM_CAN_UPDATE_WITH_SUCH_HEALTH_FACTOR = "CM5"; string public constant CM_WETH_GATEWAY_ONLY = "CM6"; string public constant CM_INCORRECT_PARAMS = "CM7"; string public constant CM_INCORRECT_FEES = "CM8"; string public constant CM_MAX_LEVERAGE_IS_TOO_HIGH = "CM9"; string public constant CM_CANT_CLOSE_WITH_LOSS = "CMA"; string public constant CM_TARGET_CONTRACT_iS_NOT_ALLOWED = "CMB"; string public constant CM_TRANSFER_FAILED = "CMC"; string public constant CM_INCORRECT_NEW_OWNER = "CME"; // // ACCOUNT FACTORY // string public constant AF_CANT_CLOSE_CREDIT_ACCOUNT_IN_THE_SAME_BLOCK = "AF1"; string public constant AF_MINING_IS_FINISHED = "AF2"; string public constant AF_CREDIT_ACCOUNT_NOT_IN_STOCK = "AF3"; string public constant AF_EXTERNAL_ACCOUNTS_ARE_FORBIDDEN = "AF4"; // // ADDRESS PROVIDER // string public constant AS_ADDRESS_NOT_FOUND = "AP1"; // // CONTRACTS REGISTER // string public constant CR_POOL_ALREADY_ADDED = "CR1"; string public constant CR_CREDIT_MANAGER_ALREADY_ADDED = "CR2"; // // CREDIT_FILTER // string public constant CF_UNDERLYING_TOKEN_FILTER_CONFLICT = "CF0"; string public constant CF_INCORRECT_LIQUIDATION_THRESHOLD = "CF1"; string public constant CF_TOKEN_IS_NOT_ALLOWED = "CF2"; string public constant CF_CREDIT_MANAGERS_ONLY = "CF3"; string public constant CF_ADAPTERS_ONLY = "CF4"; string public constant CF_OPERATION_LOW_HEALTH_FACTOR = "CF5"; string public constant CF_TOO_MUCH_ALLOWED_TOKENS = "CF6"; string public constant CF_INCORRECT_CHI_THRESHOLD = "CF7"; string public constant CF_INCORRECT_FAST_CHECK = "CF8"; string public constant CF_NON_TOKEN_CONTRACT = "CF9"; string public constant CF_CONTRACT_IS_NOT_IN_ALLOWED_LIST = "CFA"; string public constant CF_FAST_CHECK_NOT_COVERED_COLLATERAL_DROP = "CFB"; string public constant CF_SOME_LIQUIDATION_THRESHOLD_MORE_THAN_NEW_ONE = "CFC"; string public constant CF_ADAPTER_CAN_BE_USED_ONLY_ONCE = "CFD"; string public constant CF_INCORRECT_PRICEFEED = "CFE"; string public constant CF_TRANSFER_IS_NOT_ALLOWED = "CFF"; string public constant CF_CREDIT_MANAGER_IS_ALREADY_SET = "CFG"; // // CREDIT ACCOUNT // string public constant CA_CONNECTED_CREDIT_MANAGER_ONLY = "CA1"; string public constant CA_FACTORY_ONLY = "CA2"; // // PRICE ORACLE // string public constant PO_PRICE_FEED_DOESNT_EXIST = "PO0"; string public constant PO_TOKENS_WITH_DECIMALS_MORE_18_ISNT_ALLOWED = "PO1"; string public constant PO_AGGREGATOR_DECIMALS_SHOULD_BE_18 = "PO2"; // // ACL // string public constant ACL_CALLER_NOT_PAUSABLE_ADMIN = "ACL1"; string public constant ACL_CALLER_NOT_CONFIGURATOR = "ACL2"; // // WETH GATEWAY // string public constant WG_DESTINATION_IS_NOT_WETH_COMPATIBLE = "WG1"; string public constant WG_RECEIVE_IS_NOT_ALLOWED = "WG2"; string public constant WG_NOT_ENOUGH_FUNDS = "WG3"; // // LEVERAGED ACTIONS // string public constant LA_INCORRECT_VALUE = "LA1"; string public constant LA_HAS_VALUE_WITH_TOKEN_TRANSFER = "LA2"; string public constant LA_UNKNOWN_SWAP_INTERFACE = "LA3"; string public constant LA_UNKNOWN_LP_INTERFACE = "LA4"; string public constant LA_LOWER_THAN_AMOUNT_MIN = "LA5"; string public constant LA_TOKEN_OUT_IS_NOT_COLLATERAL = "LA6"; // // YEARN PRICE FEED // string public constant YPF_PRICE_PER_SHARE_OUT_OF_RANGE = "YP1"; string public constant YPF_INCORRECT_LIMITER_PARAMETERS = "YP2"; // // TOKEN DISTRIBUTOR // string public constant TD_WALLET_IS_ALREADY_CONNECTED_TO_VC = "TD1"; string public constant TD_INCORRECT_WEIGHTS = "TD2"; string public constant TD_NON_ZERO_BALANCE_AFTER_DISTRIBUTION = "TD3"; string public constant TD_CONTRIBUTOR_IS_NOT_REGISTERED = "TD4"; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; pragma abicoder v2; import {DataTypes} from "../../libraries/data/Types.sol"; /// @title Optimised for front-end credit Manager interface /// @notice It's optimised for light-weight abi interface IAppCreditManager { function openCreditAccount( uint256 amount, address onBehalfOf, uint256 leverageFactor, uint256 referralCode ) external; function closeCreditAccount(address to, DataTypes.Exchange[] calldata paths) external; function repayCreditAccount(address to) external; function increaseBorrowedAmount(uint256 amount) external; function addCollateral( address onBehalfOf, address token, uint256 amount ) external; function calcRepayAmount(address borrower, bool isLiquidated) external view returns (uint256); function getCreditAccountOrRevert(address borrower) external view returns (address); function hasOpenedCreditAccount(address borrower) external view returns (bool); function defaultSwapContract() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; pragma abicoder v2; import {DataTypes} from "../libraries/data/Types.sol"; interface IAccountFactory { // emits if new account miner was changed event AccountMinerChanged(address indexed miner); // emits each time when creditManager takes credit account event NewCreditAccount(address indexed account); // emits each time when creditManager takes credit account event InitializeCreditAccount( address indexed account, address indexed creditManager ); // emits each time when pool returns credit account event ReturnCreditAccount(address indexed account); // emits each time when DAO takes account from account factory forever event TakeForever(address indexed creditAccount, address indexed to); /// @dev Provide new creditAccount to pool. Creates a new one, if needed /// @return Address of creditAccount function takeCreditAccount( uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external returns (address); /// @dev Takes credit account back and stay in tn the queue /// @param usedAccount Address of used credit account function returnCreditAccount(address usedAccount) external; /// @dev Returns address of next available creditAccount function getNext(address creditAccount) external view returns (address); /// @dev Returns head of list of unused credit accounts function head() external view returns (address); /// @dev Returns tail of list of unused credit accounts function tail() external view returns (address); /// @dev Returns quantity of unused credit accounts in the stock function countCreditAccountsInStock() external view returns (uint256); /// @dev Returns credit account address by its id function creditAccounts(uint256 id) external view returns (address); /// @dev Quantity of credit accounts function countCreditAccounts() external view returns (uint256); // function miningApprovals(uint i) external returns(DataTypes.MiningApproval calldata); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; interface IWETHGateway { /// @dev convert ETH to WETH and add liqudity to pool /// @param pool Address of PoolService contract which where user wants to add liquidity. This pool should has WETH as underlying asset /// @param onBehalfOf The address that will receive the diesel tokens, same as msg.sender if the user wants to receive them on his /// own wallet, or a different address if the beneficiary of diesel tokens is a different wallet /// @param referralCode Code used to register the integrator originating the operation, for potential rewards. /// 0 if the action is executed directly by the user, without any middle-man function addLiquidityETH( address pool, address onBehalfOf, uint16 referralCode ) external payable; /// @dev Removes liquidity from pool and convert WETH to ETH /// - burns lp's diesel (LP) tokens /// - returns underlying tokens to lp /// @param pool Address of PoolService contract which where user wants to withdraw liquidity. This pool should has WETH as underlying asset /// @param amount Amount of tokens to be transfer /// @param to Address to transfer liquidity function removeLiquidityETH( address pool, uint256 amount, address payable to ) external; /// @dev Opens credit account in ETH /// @param creditManager Address of credit Manager. Should used WETH as underlying asset /// @param onBehalfOf The address that we open credit account. Same as msg.sender if the user wants to open it for his own wallet, /// or a different address if the beneficiary is a different wallet /// @param leverageFactor Multiplier to borrowers own funds /// @param referralCode Code used to register the integrator originating the operation, for potential rewards. /// 0 if the action is executed directly by the user, without any middle-man function openCreditAccountETH( address creditManager, address payable onBehalfOf, uint256 leverageFactor, uint256 referralCode ) external payable; /// @dev Repays credit account in ETH /// - transfer borrowed money with interest + fee from borrower account to pool /// - transfer all assets to "to" account /// @param creditManager Address of credit Manager. Should used WETH as underlying asset /// @param to Address to send credit account assets function repayCreditAccountETH(address creditManager, address to) external payable; function addCollateralETH(address creditManager, address onBehalfOf) external payable; /// @dev Unwrap WETH => ETH /// @param to Address to send eth /// @param amount Amount of WETH was transferred function unwrapWETH(address to, uint256 amount) external; }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol"; import {AddressProvider} from "./AddressProvider.sol"; import {ACL} from "./ACL.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; /// @title ACL Trait /// @notice Trait which adds acl functions to contract abstract contract ACLTrait is Pausable { // ACL contract to check rights ACL private _acl; /// @dev constructor /// @param addressProvider Address of address repository constructor(address addressProvider) { require( addressProvider != address(0), Errors.ZERO_ADDRESS_IS_NOT_ALLOWED ); _acl = ACL(AddressProvider(addressProvider).getACL()); } /// @dev Reverts if msg.sender is not configurator modifier configuratorOnly() { require( _acl.isConfigurator(msg.sender), Errors.ACL_CALLER_NOT_CONFIGURATOR ); // T:[ACLT-8] _; } ///@dev Pause contract function pause() external { require( _acl.isPausableAdmin(msg.sender), Errors.ACL_CALLER_NOT_PAUSABLE_ADMIN ); // T:[ACLT-1] _pause(); } /// @dev Unpause contract function unpause() external { require( _acl.isUnpausableAdmin(msg.sender), Errors.ACL_CALLER_NOT_PAUSABLE_ADMIN ); // T:[ACLT-1],[ACLT-2] _unpause(); } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {PercentageMath} from "../math/PercentageMath.sol"; library Constants { uint256 constant MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; // 25% of MAX_INT uint256 constant MAX_INT_4 = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; // REWARD FOR LEAN DEPLOYMENT MINING uint256 constant ACCOUNT_CREATION_REWARD = 1e5; uint256 constant DEPLOYMENT_COST = 1e17; // FEE = 10% uint256 constant FEE_INTEREST = 1000; // 10% // FEE + LIQUIDATION_FEE 2% uint256 constant FEE_LIQUIDATION = 200; // Liquidation premium 5% uint256 constant LIQUIDATION_DISCOUNTED_SUM = 9500; // 100% - LIQUIDATION_FEE - LIQUIDATION_PREMIUM uint256 constant UNDERLYING_TOKEN_LIQUIDATION_THRESHOLD = LIQUIDATION_DISCOUNTED_SUM - FEE_LIQUIDATION; // Seconds in a year uint256 constant SECONDS_PER_YEAR = 365 days; uint256 constant SECONDS_PER_ONE_AND_HALF_YEAR = SECONDS_PER_YEAR * 3 /2; // 1e18 uint256 constant RAY = 1e27; uint256 constant WAD = 1e18; // OPERATIONS uint8 constant OPERATION_CLOSURE = 1; uint8 constant OPERATION_REPAY = 2; uint8 constant OPERATION_LIQUIDATION = 3; // Decimals for leverage, so x4 = 4*LEVERAGE_DECIMALS for openCreditAccount function uint8 constant LEVERAGE_DECIMALS = 100; // Maximum withdraw fee for pool in percentage math format. 100 = 1% uint8 constant MAX_WITHDRAW_FEE = 100; uint256 constant CHI_THRESHOLD = 9950; uint256 constant HF_CHECK_INTERVAL_DEFAULT = 4; uint256 constant NO_SWAP = 0; uint256 constant UNISWAP_V2 = 1; uint256 constant UNISWAP_V3 = 2; uint256 constant CURVE_V1 = 3; uint256 constant LP_YEARN = 4; uint256 constant EXACT_INPUT = 1; uint256 constant EXACT_OUTPUT = 2; }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title POptimised for front-end Pool Service Interface interface IAppPoolService { function addLiquidity( uint256 amount, address onBehalfOf, uint256 referralCode ) external; function removeLiquidity(uint256 amount, address to) external returns(uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; /// @title Optimised for front-end Address Provider interface interface IAppAddressProvider { function getDataCompressor() external view returns (address); function getGearToken() external view returns (address); function getWethToken() external view returns (address); function getWETHGateway() external view returns (address); function getPriceOracle() external view returns (address); function getLeveragedActions() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2021 pragma solidity ^0.7.4; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; /// @title ACL keeps admins addresses /// More info: https://dev.gearbox.fi/security/roles contract ACL is Ownable { mapping(address => bool) public pausableAdminSet; mapping(address => bool) public unpausableAdminSet; // Contract version uint256 public constant version = 1; // emits each time when new pausable admin added event PausableAdminAdded(address indexed newAdmin); // emits each time when pausable admin removed event PausableAdminRemoved(address indexed admin); // emits each time when new unpausable admin added event UnpausableAdminAdded(address indexed newAdmin); // emits each times when unpausable admin removed event UnpausableAdminRemoved(address indexed admin); /// @dev Adds pausable admin address /// @param newAdmin Address of new pausable admin function addPausableAdmin(address newAdmin) external onlyOwner // T:[ACL-1] { pausableAdminSet[newAdmin] = true; // T:[ACL-2] emit PausableAdminAdded(newAdmin); // T:[ACL-2] } /// @dev Removes pausable admin /// @param admin Address of admin which should be removed function removePausableAdmin(address admin) external onlyOwner // T:[ACL-1] { pausableAdminSet[admin] = false; // T:[ACL-3] emit PausableAdminRemoved(admin); // T:[ACL-3] } /// @dev Returns true if the address is pausable admin and false if not function isPausableAdmin(address addr) external view returns (bool) { return pausableAdminSet[addr]; // T:[ACL-2,3] } /// @dev Adds unpausable admin address to the list /// @param newAdmin Address of new unpausable admin function addUnpausableAdmin(address newAdmin) external onlyOwner // T:[ACL-1] { unpausableAdminSet[newAdmin] = true; // T:[ACL-4] emit UnpausableAdminAdded(newAdmin); // T:[ACL-4] } /// @dev Removes unpausable admin /// @param admin Address of admin to be removed function removeUnpausableAdmin(address admin) external onlyOwner // T:[ACL-1] { unpausableAdminSet[admin] = false; // T:[ACL-5] emit UnpausableAdminRemoved(admin); // T:[ACL-5] } /// @dev Returns true if the address is unpausable admin and false if not function isUnpausableAdmin(address addr) external view returns (bool) { return unpausableAdminSet[addr]; // T:[ACL-4,5] } /// @dev Returns true if addr has configurator rights function isConfigurator(address account) external view returns (bool) { return account == owner(); // T:[ACL-6] } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_addressProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETHToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressProvider","outputs":[{"internalType":"contract AddressProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"borrowedAmount","type":"uint256"}],"name":"calcExpectedAtOpenHf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"name":"calcExpectedHf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractsRegister","outputs":[{"internalType":"contract ContractsRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"_allowedContract","type":"address"}],"name":"getAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditAccountData","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"bool","name":"inUse","type":"bool"},{"internalType":"address","name":"creditManager","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint256","name":"borrowedAmountPlusInterest","type":"uint256"},{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"uint256","name":"healthFactor","type":"uint256"},{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"internalType":"struct DataTypes.TokenBalance[]","name":"balances","type":"tuple[]"}],"internalType":"struct DataTypes.CreditAccountData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditManager","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditAccountDataExtended","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"bool","name":"inUse","type":"bool"},{"internalType":"address","name":"creditManager","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint256","name":"borrowedAmountPlusInterest","type":"uint256"},{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"uint256","name":"healthFactor","type":"uint256"},{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"internalType":"struct DataTypes.TokenBalance[]","name":"balances","type":"tuple[]"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"liquidationAmount","type":"uint256"},{"internalType":"bool","name":"canBeClosed","type":"bool"},{"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"internalType":"uint256","name":"cumulativeIndexAtOpen","type":"uint256"},{"internalType":"uint256","name":"since","type":"uint256"}],"internalType":"struct DataTypes.CreditAccountDataExtended","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditAccountList","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"bool","name":"inUse","type":"bool"},{"internalType":"address","name":"creditManager","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint256","name":"borrowedAmountPlusInterest","type":"uint256"},{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"uint256","name":"healthFactor","type":"uint256"},{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"internalType":"struct DataTypes.TokenBalance[]","name":"balances","type":"tuple[]"}],"internalType":"struct DataTypes.CreditAccountData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditManagerData","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"hasAccount","type":"bool"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"isWETH","type":"bool"},{"internalType":"bool","name":"canBorrow","type":"bool"},{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"uint256","name":"maxLeverageFactor","type":"uint256"},{"internalType":"uint256","name":"availableLiquidity","type":"uint256"},{"internalType":"address[]","name":"allowedTokens","type":"address[]"},{"components":[{"internalType":"address","name":"allowedContract","type":"address"},{"internalType":"address","name":"adapter","type":"address"}],"internalType":"struct DataTypes.ContractAdapter[]","name":"adapters","type":"tuple[]"}],"internalType":"struct DataTypes.CreditManagerData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditManagersList","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"hasAccount","type":"bool"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"isWETH","type":"bool"},{"internalType":"bool","name":"canBorrow","type":"bool"},{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"uint256","name":"maxLeverageFactor","type":"uint256"},{"internalType":"uint256","name":"availableLiquidity","type":"uint256"},{"internalType":"address[]","name":"allowedTokens","type":"address[]"},{"components":[{"internalType":"address","name":"allowedContract","type":"address"},{"internalType":"address","name":"adapter","type":"address"}],"internalType":"struct DataTypes.ContractAdapter[]","name":"adapters","type":"tuple[]"}],"internalType":"struct DataTypes.CreditManagerData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"getPoolData","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"isWETH","type":"bool"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"dieselToken","type":"address"},{"internalType":"uint256","name":"linearCumulativeIndex","type":"uint256"},{"internalType":"uint256","name":"availableLiquidity","type":"uint256"},{"internalType":"uint256","name":"expectedLiquidity","type":"uint256"},{"internalType":"uint256","name":"expectedLiquidityLimit","type":"uint256"},{"internalType":"uint256","name":"totalBorrowed","type":"uint256"},{"internalType":"uint256","name":"depositAPY_RAY","type":"uint256"},{"internalType":"uint256","name":"borrowAPY_RAY","type":"uint256"},{"internalType":"uint256","name":"dieselRate_RAY","type":"uint256"},{"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"internalType":"uint256","name":"cumulativeIndex_RAY","type":"uint256"},{"internalType":"uint256","name":"timestampLU","type":"uint256"}],"internalType":"struct DataTypes.PoolData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolsList","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"isWETH","type":"bool"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"dieselToken","type":"address"},{"internalType":"uint256","name":"linearCumulativeIndex","type":"uint256"},{"internalType":"uint256","name":"availableLiquidity","type":"uint256"},{"internalType":"uint256","name":"expectedLiquidity","type":"uint256"},{"internalType":"uint256","name":"expectedLiquidityLimit","type":"uint256"},{"internalType":"uint256","name":"totalBorrowed","type":"uint256"},{"internalType":"uint256","name":"depositAPY_RAY","type":"uint256"},{"internalType":"uint256","name":"borrowAPY_RAY","type":"uint256"},{"internalType":"uint256","name":"dieselRate_RAY","type":"uint256"},{"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"internalType":"uint256","name":"cumulativeIndex_RAY","type":"uint256"},{"internalType":"uint256","name":"timestampLU","type":"uint256"}],"internalType":"struct DataTypes.PoolData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addr","type":"address[]"}],"name":"getTokenData","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"internalType":"struct DataTypes.TokenInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"hasOpenedCreditAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b506040516200639e3803806200639e8339818101604052810190620000379190620002f1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156040518060400160405280600281526020017f5a3000000000000000000000000000000000000000000000000000000000000081525090620000e2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620000d991906200035e565b60405180910390fd5b50806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c513c9bb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200018a57600080fd5b505afa1580156200019f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c59190620002f1565b73ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1660601b8152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634c252f916040518163ffffffff1660e01b815260040160206040518083038186803b1580156200026257600080fd5b505afa15801562000277573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029d9190620002f1565b73ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250505062000433565b600081519050620002eb8162000419565b92915050565b6000602082840312156200030457600080fd5b60006200031484828501620002da565b91505092915050565b60006200032a8262000382565b6200033681856200038d565b935062000348818560208601620003d2565b620003538162000408565b840191505092915050565b600060208201905081810360008301526200037a81846200031d565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000620003ab82620003b2565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60005b83811015620003f2578082015181840152602081019050620003d5565b8381111562000402576000848401525b50505050565b6000601f19601f8301169050919050565b62000424816200039e565b81146200043057600080fd5b50565b60805160601c60a05160601c615ef6620004a8600039806112a752806120a15280612948525080610b1352806115ba5280611c3b5280611d3e52806120c852806122fd528061232b52806123d25280612580528061262752806131db52806132de5280613b505280613d0d5250615ef66000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806354fd4d5011610097578063b816903911610066578063b8169039146102eb578063ba3b73451461031b578063bf2eb19e1461034b578063fc9914cb1461037b57610100565b806354fd4d501461024f5780637a0c7b211461026d578063a80deda31461028b578063b10b074e146102bb57610100565b80632954018c116100d35780632954018c146101b357806339595cf8146101d15780634b2f336d146102015780634c472fc91461021f57610100565b80630dbd616d1461010557806313d21cdf14610135578063191482d4146101655780631bcd8fc014610195575b600080fd5b61011f600480360381019061011a919061482f565b6103ab565b60405161012c9190615a10565b60405180910390f35b61014f600480360381019061014a91906147dd565b610b08565b60405161015c9190615a54565b60405180910390f35b61017f600480360381019061017a919061482f565b6115af565b60405161018c91906159ee565b60405180910390f35b61019d611c35565b6040516101aa9190615917565b60405180910390f35b6101bb611e1e565b6040516101c89190615976565b60405180910390f35b6101eb60048036038101906101e691906148d2565b611e42565b6040516101f89190615a70565b60405180910390f35b61020961209f565b604051610216919061582f565b60405180910390f35b6102396004803603810190610234919061482f565b6120c3565b604051610246919061582f565b60405180910390f35b6102576122f6565b6040516102649190615a70565b60405180910390f35b6102756122fb565b6040516102829190615991565b60405180910390f35b6102a560048036038101906102a091906147dd565b61231f565b6040516102b291906158d3565b60405180910390f35b6102d560048036038101906102d0919061482f565b6127a1565b6040516102e29190615a32565b60405180910390f35b610305600480360381019061030091906147dd565b6131d5565b60405161031291906158f5565b60405180910390f35b6103356004803603810190610330919061486b565b6133c1565b6040516103429190615a70565b60405180910390f35b61036560048036038101906103609190614998565b61394c565b6040516103729190615939565b60405180910390f35b6103956004803603810190610390919061482f565b613b4b565b6040516103a2919061595b565b60405180910390f35b6103b361422a565b6000806103bf85613d07565b9150915060008273ffffffffffffffffffffffffffffffffffffffff1663e958b704866040518263ffffffff1660e01b81526004016103fe919061582f565b60206040518083038186803b15801561041657600080fd5b505afa15801561042a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044e9190614806565b905061045861422a565b85816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505086816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b15801561054657600080fd5b505afa15801561055a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057e9190614806565b816080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1663c7de38a6836040518263ffffffff1660e01b81526004016105ee919061582f565b60206040518083038186803b15801561060657600080fd5b505afa15801561061a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063e9190614a6c565b8160c00181815250508273ffffffffffffffffffffffffffffffffffffffff1663dfd59465836040518263ffffffff1660e01b8152600401610680919061582f565b60206040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190614a6c565b8160e001818152505060008473ffffffffffffffffffffffffffffffffffffffff1663570a7af26040518163ffffffff1660e01b815260040160206040518083038186803b15801561072157600080fd5b505afa158015610735573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107599190614806565b90508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156107a157600080fd5b505afa1580156107b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d99190614a6c565b8261010001818152505060008473ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108639190614a6c565b90508067ffffffffffffffff8111801561087c57600080fd5b506040519080825280602002602001820160405280156108b657816020015b6108a36142d7565b81526020019060019003908161089b5790505b5083610120018190525060005b81811015610a66576108d36142d7565b8673ffffffffffffffffffffffffffffffffffffffff1663af0a650287846040518363ffffffff1660e01b815260040161090e929190615873565b60806040518083038186803b15801561092657600080fd5b505afa15801561093a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095e9190614935565b9050508260000183602001828152508273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050508673ffffffffffffffffffffffffffffffffffffffff1663f9eaee0d82600001516040518263ffffffff1660e01b81526004016109dc919061582f565b60206040518083038186803b1580156109f457600080fd5b505afa158015610a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2c91906149d9565b816040019015159081151581525050808561012001518381518110610a4d57fe5b60200260200101819052505080806001019150506108c3565b508473ffffffffffffffffffffffffffffffffffffffff16633192195c856040518263ffffffff1660e01b8152600401610aa0919061582f565b60206040518083038186803b158015610ab857600080fd5b505afa158015610acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af09190614a6c565b8360a001818152505082965050505050505092915050565b610b10614310565b817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635b16ebb7826040518263ffffffff1660e01b8152600401610b6a919061582f565b60206040518083038186803b158015610b8257600080fd5b505afa158015610b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bba91906149d9565b6040518060400160405280600281526020017f525000000000000000000000000000000000000000000000000000000000000081525090610c31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c2891906159ac565b60405180910390fd5b50610c3a614310565b600084905084826000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1663fe14112d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cbd57600080fd5b505afa158015610cd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf59190614a6c565b8260c00181815250508073ffffffffffffffffffffffffffffffffffffffff1663ef8d96036040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4457600080fd5b505afa158015610d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7c9190614a6c565b8260e00181815250508073ffffffffffffffffffffffffffffffffffffffff1663743753596040518163ffffffff1660e01b815260040160206040518083038186803b158015610dcb57600080fd5b505afa158015610ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e039190614a6c565b8260a00181815250508073ffffffffffffffffffffffffffffffffffffffff16634c19386c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5257600080fd5b505afa158015610e66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8a9190614a6c565b826101000181815250508073ffffffffffffffffffffffffffffffffffffffff1663788c6bfe6040518163ffffffff1660e01b815260040160206040518083038186803b158015610eda57600080fd5b505afa158015610eee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f129190614a6c565b826101600181815250508073ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f6257600080fd5b505afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a9190614a6c565b8260800181815250508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe957600080fd5b505afa158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110219190614a6c565b826101400181815250508073ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b15801561107157600080fd5b505afa158015611085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a99190614806565b826040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff166336dda7d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561112657600080fd5b505afa15801561113a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115e9190614806565b826060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1663788c6bfe6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111db57600080fd5b505afa1580156111ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112139190614a6c565b826101600181815250508073ffffffffffffffffffffffffffffffffffffffff1663e941fa786040518163ffffffff1660e01b815260040160206040518083038186803b15801561126357600080fd5b505afa158015611277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129b9190614a6c565b826101800181815250507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16148260200190151590811515815250508073ffffffffffffffffffffffffffffffffffffffff1663609ae3176040518163ffffffff1660e01b815260040160206040518083038186803b15801561134d57600080fd5b505afa158015611361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113859190614a6c565b826101c00181815250508073ffffffffffffffffffffffffffffffffffffffff1663dbcb313b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113d557600080fd5b505afa1580156113e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140d9190614a6c565b826101a00181815250506000826060015173ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b9190614a6c565b905060008273ffffffffffffffffffffffffffffffffffffffff16635427c938836040518263ffffffff1660e01b81526004016114d89190615a70565b60206040518083038186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115289190614a6c565b9050600081146115915761158c8161157e611553876101800151612710613eb590919063ffffffff16565b611570886101000151896101400151613f3890919063ffffffff16565b613fbe90919063ffffffff16565b61411990919063ffffffff16565b611598565b8361014001515b846101200181815250508395505050505050919050565b6115b76143ca565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401611611919061582f565b60206040518083038186803b15801561162957600080fd5b505afa15801561163d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166191906149d9565b6040518060400160405280600281526020017f4350000000000000000000000000000000000000000000000000000000000000815250906116d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116cf91906159ac565b60405180910390fd5b506116e16143ca565b60006116ed86866103ab565b90508060000151826000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060200151826020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060600151826060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060800151826080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060a001518260a00181815250508060c001518260c00181815250508060e001518260e00181815250508061010001518261010001818152505080610120015182610120018190525060008673ffffffffffffffffffffffffffffffffffffffff1663e958b704876040518263ffffffff1660e01b8152600401611863919061582f565b60206040518083038186803b15801561187b57600080fd5b505afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614806565b90508073ffffffffffffffffffffffffffffffffffffffff16631afbb7a46040518163ffffffff1660e01b815260040160206040518083038186803b1580156118fb57600080fd5b505afa15801561190f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119339190614a6c565b836101a00181815250508073ffffffffffffffffffffffffffffffffffffffff166317d11a156040518163ffffffff1660e01b815260040160206040518083038186803b15801561198357600080fd5b505afa158015611997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bb9190614a6c565b836101c00181815250508073ffffffffffffffffffffffffffffffffffffffff16633dc54b406040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0b57600080fd5b505afa158015611a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a439190614a6c565b836101e00181815250508673ffffffffffffffffffffffffffffffffffffffff16633ce073558760006040518363ffffffff1660e01b8152600401611a8992919061584a565b60206040518083038186803b158015611aa157600080fd5b505afa158015611ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad99190614a6c565b836101400181815250508673ffffffffffffffffffffffffffffffffffffffff16633ce073558760016040518363ffffffff1660e01b8152600401611b1f92919061584a565b60206040518083038186803b158015611b3757600080fd5b505afa158015611b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6f9190614a6c565b8361016001818152505060008773ffffffffffffffffffffffffffffffffffffffff1663996329f8838560c0015160006040518463ffffffff1660e01b8152600401611bbd9392919061589c565b60a06040518083038186803b158015611bd557600080fd5b505afa158015611be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0d9190614a95565b5050925050506000811184610180019015159081151581525050839550505050505092915050565b606060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b4ac68606040518163ffffffff1660e01b815260040160206040518083038186803b158015611c9f57600080fd5b505afa158015611cb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd79190614a6c565b905060008167ffffffffffffffff81118015611cf257600080fd5b50604051908082528060200260200182016040528015611d2c57816020015b611d19614310565b815260200190600190039081611d115790505b50905060005b82811015611e155760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ac4afa38836040518263ffffffff1660e01b8152600401611d959190615a70565b60206040518083038186803b158015611dad57600080fd5b505afa158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de59190614806565b9050611df081610b08565b838381518110611dfc57fe5b6020026020010181905250508080600101915050611d32565b50809250505090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000611e5087613d07565b9150915060008173ffffffffffffffffffffffffffffffffffffffff16632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9c57600080fd5b505afa158015611eb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed49190614806565b9050600061207c8373ffffffffffffffffffffffffffffffffffffffff1663783274388a6040518263ffffffff1660e01b8152600401611f14919061582f565b60206040518083038186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f649190614a6c565b8373ffffffffffffffffffffffffffffffffffffffff1663b66102df8a8c8973ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc857600080fd5b505afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120009190614806565b6040518463ffffffff1660e01b815260040161201e93929190615a8b565b60206040518083038186803b15801561203657600080fd5b505afa15801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190614a6c565b613f3890919063ffffffff16565b9050612091868261411990919063ffffffff16565b945050505050949350505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b815260040161211f919061582f565b60206040518083038186803b15801561213757600080fd5b505afa15801561214b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216f91906149d9565b6040518060400160405280600281526020017f4350000000000000000000000000000000000000000000000000000000000000815250906121e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121dd91906159ac565b60405180910390fd5b508373ffffffffffffffffffffffffffffffffffffffff1663f93f515b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122659190614a02565b73ffffffffffffffffffffffffffffffffffffffff1663fdd57645846040518263ffffffff1660e01b815260040161229d919061582f565b60206040518083038186803b1580156122b557600080fd5b505afa1580156122c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ed9190614806565b91505092915050565b600181565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060600080600090505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561238f57600080fd5b505afa1580156123a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c79190614a6c565b8110156125205760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b81526004016124299190615a70565b60206040518083038186803b15801561244157600080fd5b505afa158015612455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124799190614806565b90508073ffffffffffffffffffffffffffffffffffffffff1663256ac915866040518263ffffffff1660e01b81526004016124b4919061582f565b60206040518083038186803b1580156124cc57600080fd5b505afa1580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250491906149d9565b156125125782806001019350505b508080600101915050612329565b5060008167ffffffffffffffff8111801561253a57600080fd5b5060405190808252806020026020018201604052801561257457816020015b61256161422a565b8152602001906001900390816125595790505b5090506000915060005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125e457600080fd5b505afa1580156125f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261c9190614a6c565b8110156127965760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b815260040161267e9190615a70565b60206040518083038186803b15801561269657600080fd5b505afa1580156126aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ce9190614806565b90508073ffffffffffffffffffffffffffffffffffffffff1663256ac915876040518263ffffffff1660e01b8152600401612709919061582f565b60206040518083038186803b15801561272157600080fd5b505afa158015612735573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275991906149d9565b156127885761276881876103ab565b83858151811061277457fe5b602002602001018190525083806001019450505b50808060010191505061257e565b508092505050919050565b6127a96144a3565b6000806127b585613d07565b915091506127c16144a3565b85816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1663256ac915866040518263ffffffff1660e01b8152600401612832919061582f565b60206040518083038186803b15801561284a57600080fd5b505afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288291906149d9565b8160200190151590811515815250508173ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b1580156128d757600080fd5b505afa1580156128eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290f9190614806565b816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff161481606001901515908115158152505060008373ffffffffffffffffffffffffffffffffffffffff1663570a7af26040518163ffffffff1660e01b815260040160206040518083038186803b1580156129f057600080fd5b505afa158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a289190614806565b90508073ffffffffffffffffffffffffffffffffffffffff16632e97ca21886040518263ffffffff1660e01b8152600401612a63919061582f565b60206040518083038186803b158015612a7b57600080fd5b505afa158015612a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab391906149d9565b8260800190151590811515815250508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0857600080fd5b505afa158015612b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b409190614a6c565b8260a00181815250508073ffffffffffffffffffffffffffffffffffffffff1663743753596040518163ffffffff1660e01b815260040160206040518083038186803b158015612b8f57600080fd5b505afa158015612ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc79190614a6c565b826101200181815250508373ffffffffffffffffffffffffffffffffffffffff16639b2cb5d86040518163ffffffff1660e01b815260040160206040518083038186803b158015612c1757600080fd5b505afa158015612c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4f9190614a6c565b8260c00181815250508373ffffffffffffffffffffffffffffffffffffffff16635f48f3936040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9e57600080fd5b505afa158015612cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd69190614a6c565b8260e00181815250508373ffffffffffffffffffffffffffffffffffffffff1663b2c53a6c6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d2557600080fd5b505afa158015612d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5d9190614a6c565b8261010001818152505060008373ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b158015612daf57600080fd5b505afa158015612dc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de79190614a6c565b90508067ffffffffffffffff81118015612e0057600080fd5b50604051908082528060200260200182016040528015612e2f5781602001602082028036833780820191505090505b5083610140018190525060005b81811015612f25578473ffffffffffffffffffffffffffffffffffffffff16635e5f2e26826040518263ffffffff1660e01b8152600401612e7d9190615a70565b60206040518083038186803b158015612e9557600080fd5b505afa158015612ea9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecd9190614806565b8461014001518281518110612ede57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050612e3c565b5060008473ffffffffffffffffffffffffffffffffffffffff166350e036ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6e57600080fd5b505afa158015612f82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa69190614a6c565b90508067ffffffffffffffff81118015612fbf57600080fd5b50604051908082528060200260200182016040528015612ff957816020015b612fe6614536565b815260200190600190039081612fde5790505b5084610160018190525060005b818110156131c557613016614536565b8673ffffffffffffffffffffffffffffffffffffffff16635094cb4f836040518263ffffffff1660e01b815260040161304f9190615a70565b60206040518083038186803b15801561306757600080fd5b505afa15801561307b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061309f9190614806565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663fdd5764582600001516040518263ffffffff1660e01b8152600401613113919061582f565b60206040518083038186803b15801561312b57600080fd5b505afa15801561313f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131639190614806565b816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508086610160015183815181106131ac57fe5b6020026020010181905250508080600101915050613006565b5083965050505050505092915050565b606060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561323f57600080fd5b505afa158015613253573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132779190614a6c565b905060008167ffffffffffffffff8111801561329257600080fd5b506040519080825280602002602001820160405280156132cc57816020015b6132b96144a3565b8152602001906001900390816132b15790505b50905060005b828110156133b65760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b81526004016133359190615a70565b60206040518083038186803b15801561334d57600080fd5b505afa158015613361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133859190614806565b905061339181876127a1565b83838151811061339d57fe5b60200260200101819052505080806001019150506132d2565b508092505050919050565b60008060006133cf86613d07565b9150915060008273ffffffffffffffffffffffffffffffffffffffff1663e958b704876040518263ffffffff1660e01b815260040161340e919061582f565b60206040518083038186803b15801561342657600080fd5b505afa15801561343a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345e9190614806565b905060008273ffffffffffffffffffffffffffffffffffffffff16632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156134a857600080fd5b505afa1580156134bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e09190614806565b905060008373ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b15801561352a57600080fd5b505afa15801561353e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135629190614a6c565b9050808751146135a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161359e906159ce565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b1580156135f057600080fd5b505afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136289190614806565b905060005b838110156138a0576138916138828873ffffffffffffffffffffffffffffffffffffffff1663783274388a73ffffffffffffffffffffffffffffffffffffffff16635e5f2e26866040518263ffffffff1660e01b81526004016136909190615a70565b60206040518083038186803b1580156136a857600080fd5b505afa1580156136bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e09190614806565b6040518263ffffffff1660e01b81526004016136fc919061582f565b60206040518083038186803b15801561371457600080fd5b505afa158015613728573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374c9190614a6c565b8773ffffffffffffffffffffffffffffffffffffffff1663b66102df8e868151811061377457fe5b60200260200101518c73ffffffffffffffffffffffffffffffffffffffff16635e5f2e26886040518263ffffffff1660e01b81526004016137b59190615a70565b60206040518083038186803b1580156137cd57600080fd5b505afa1580156137e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138059190614806565b886040518463ffffffff1660e01b815260040161382493929190615a8b565b60206040518083038186803b15801561383c57600080fd5b505afa158015613850573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138749190614a6c565b613f3890919063ffffffff16565b846141a290919063ffffffff16565b9250808060010191505061362d565b5061393c8673ffffffffffffffffffffffffffffffffffffffff16633192195c876040518263ffffffff1660e01b81526004016138dd919061582f565b60206040518083038186803b1580156138f557600080fd5b505afa158015613909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392d9190614a6c565b8361411990919063ffffffff16565b9750505050505050509392505050565b60606000825167ffffffffffffffff8111801561396857600080fd5b506040519080825280602002602001820160405280156139a257816020015b61398f61457c565b8152602001906001900390816139875790505b50905060005b8351811015613b415760405180606001604052808583815181106139c857fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018583815181106139f757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015613a4457600080fd5b505afa158015613a58573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190613a819190614a2b565b8152602001858381518110613a9257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015613adf57600080fd5b505afa158015613af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b179190614b0c565b60ff16815250828281518110613b2957fe5b602002602001018190525080806001019150506139a8565b5080915050919050565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401613ba7919061582f565b60206040518083038186803b158015613bbf57600080fd5b505afa158015613bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf791906149d9565b6040518060400160405280600281526020017f435000000000000000000000000000000000000000000000000000000000000081525090613c6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c6591906159ac565b60405180910390fd5b5060008490508073ffffffffffffffffffffffffffffffffffffffff1663256ac915856040518263ffffffff1660e01b8152600401613cad919061582f565b60206040518083038186803b158015613cc557600080fd5b505afa158015613cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfd91906149d9565b9250505092915050565b600080827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401613d64919061582f565b60206040518083038186803b158015613d7c57600080fd5b505afa158015613d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db491906149d9565b6040518060400160405280600281526020017f435000000000000000000000000000000000000000000000000000000000000081525090613e2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613e2291906159ac565b60405180910390fd5b508392508273ffffffffffffffffffffffffffffffffffffffff1663f93f515b6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7557600080fd5b505afa158015613e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ead9190614a02565b915050915091565b600082821115613f2d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b600080831415613f4b5760009050613fb8565b6000828402905082848281613f5c57fe5b0414613fb3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615ea06021913960400191505060405180910390fd5b809150505b92915050565b600080831480613fce5750600082145b15613fdc5760009050614113565b81600261271081613fe957fe5b047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038161401357fe5b048311156040518060400160405280600281526020017f4d31000000000000000000000000000000000000000000000000000000000000815250906140f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156140b857808201518184015260208101905061409d565b50505050905090810190601f1680156140e55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5061271060026127108161410357fe5b04838502018161410f57fe5b0490505b92915050565b6000808211614190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b81838161419957fe5b04905092915050565b600080828401905083811015614220576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001606081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000151581525090565b604051806101e00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806102000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600060ff1681525090565b60006145c96145c484615af3565b615ac2565b905080838252602082019050828560208602820111156145e857600080fd5b60005b8581101561461857816145fe88826146cc565b8452602084019350602083019250506001810190506145eb565b5050509392505050565b600061463561463084615b1f565b615ac2565b9050808382526020820190508285602086028201111561465457600080fd5b60005b85811015614684578161466a888261479e565b845260208401935060208301925050600181019050614657565b5050509392505050565b60006146a161469c84615b4b565b615ac2565b9050828152602081018484840111156146b957600080fd5b6146c4848285615de6565b509392505050565b6000813590506146db81615e2c565b92915050565b6000815190506146f081615e2c565b92915050565b600082601f83011261470757600080fd5b81356147178482602086016145b6565b91505092915050565b600082601f83011261473157600080fd5b8135614741848260208601614622565b91505092915050565b60008151905061475981615e43565b92915050565b60008151905061476e81615e5a565b92915050565b600082601f83011261478557600080fd5b815161479584826020860161468e565b91505092915050565b6000813590506147ad81615e71565b92915050565b6000815190506147c281615e71565b92915050565b6000815190506147d781615e88565b92915050565b6000602082840312156147ef57600080fd5b60006147fd848285016146cc565b91505092915050565b60006020828403121561481857600080fd5b6000614826848285016146e1565b91505092915050565b6000806040838503121561484257600080fd5b6000614850858286016146cc565b9250506020614861858286016146cc565b9150509250929050565b60008060006060848603121561488057600080fd5b600061488e868287016146cc565b935050602061489f868287016146cc565b925050604084013567ffffffffffffffff8111156148bc57600080fd5b6148c886828701614720565b9150509250925092565b600080600080608085870312156148e857600080fd5b60006148f6878288016146cc565b9450506020614907878288016146cc565b93505060406149188782880161479e565b92505060606149298782880161479e565b91505092959194509250565b6000806000806080858703121561494b57600080fd5b6000614959878288016146e1565b945050602061496a878288016147b3565b935050604061497b878288016147b3565b925050606061498c878288016147b3565b91505092959194509250565b6000602082840312156149aa57600080fd5b600082013567ffffffffffffffff8111156149c457600080fd5b6149d0848285016146f6565b91505092915050565b6000602082840312156149eb57600080fd5b60006149f98482850161474a565b91505092915050565b600060208284031215614a1457600080fd5b6000614a228482850161475f565b91505092915050565b600060208284031215614a3d57600080fd5b600082015167ffffffffffffffff811115614a5757600080fd5b614a6384828501614774565b91505092915050565b600060208284031215614a7e57600080fd5b6000614a8c848285016147b3565b91505092915050565b600080600080600060a08688031215614aad57600080fd5b6000614abb888289016147b3565b9550506020614acc888289016147b3565b9450506040614add888289016147b3565b9350506060614aee888289016147b3565b9250506080614aff888289016147b3565b9150509295509295909350565b600060208284031215614b1e57600080fd5b6000614b2c848285016147c8565b91505092915050565b6000614b418383614bd2565b60208301905092915050565b6000614b598383614fb5565b60408301905092915050565b6000614b71838361513c565b905092915050565b6000614b8583836152f0565b905092915050565b6000614b998383615506565b6101e08301905092915050565b6000614bb28383615770565b60608301905092915050565b6000614bca83836157b2565b905092915050565b614bdb81615d37565b82525050565b614bea81615d37565b82525050565b6000614bfb82615beb565b614c058185615c9e565b9350614c1083615b7b565b8060005b83811015614c41578151614c288882614b35565b9750614c3383615c43565b925050600181019050614c14565b5085935050505092915050565b6000614c5982615bf6565b614c638185615caf565b9350614c6e83615b8b565b8060005b83811015614c9f578151614c868882614b4d565b9750614c9183615c50565b925050600181019050614c72565b5085935050505092915050565b6000614cb782615c01565b614cc18185615cc0565b935083602082028501614cd385615b9b565b8060005b85811015614d0f5784840389528151614cf08582614b65565b9450614cfb83615c5d565b925060208a01995050600181019050614cd7565b50829750879550505050505092915050565b6000614d2c82615c0c565b614d368185615cd1565b935083602082028501614d4885615bab565b8060005b85811015614d845784840389528151614d658582614b79565b9450614d7083615c6a565b925060208a01995050600181019050614d4c565b50829750879550505050505092915050565b6000614da182615c17565b614dab8185615ce2565b9350614db683615bbb565b8060005b83811015614de7578151614dce8882614b8d565b9750614dd983615c77565b925050600181019050614dba565b5085935050505092915050565b6000614dff82615c22565b614e098185615cf3565b9350614e1483615bcb565b8060005b83811015614e45578151614e2c8882614ba6565b9750614e3783615c84565b925050600181019050614e18565b5085935050505092915050565b6000614e5d82615c2d565b614e678185615d04565b935083602082028501614e7985615bdb565b8060005b85811015614eb55784840389528151614e968582614bbe565b9450614ea183615c91565b925060208a01995050600181019050614e7d565b50829750879550505050505092915050565b614ed081615d49565b82525050565b614edf81615d49565b82525050565b614eee81615d9e565b82525050565b614efd81615dc2565b82525050565b6000614f0e82615c38565b614f188185615d15565b9350614f28818560208601615de6565b614f3181615e1b565b840191505092915050565b6000614f4782615c38565b614f518185615d26565b9350614f61818560208601615de6565b614f6a81615e1b565b840191505092915050565b6000614f82601783615d26565b91507f496e636f72726563742062616c616e6365732073697a650000000000000000006000830152602082019050919050565b604082016000820151614fcb6000850182614bd2565b506020820151614fde6020850182614bd2565b50505050565b600061020083016000830151614ffd6000860182614bd2565b5060208301516150106020860182614bd2565b5060408301516150236040860182614ec7565b5060608301516150366060860182614bd2565b5060808301516150496080860182614bd2565b5060a083015161505c60a0860182615802565b5060c083015161506f60c0860182615802565b5060e083015161508260e0860182615802565b50610100830151615097610100860182615802565b506101208301518482036101208601526150b18282614df4565b9150506101408301516150c8610140860182615802565b506101608301516150dd610160860182615802565b506101808301516150f2610180860182614ec7565b506101a08301516151076101a0860182615802565b506101c083015161511c6101c0860182615802565b506101e08301516151316101e0860182615802565b508091505092915050565b6000610140830160008301516151556000860182614bd2565b5060208301516151686020860182614bd2565b50604083015161517b6040860182614ec7565b50606083015161518e6060860182614bd2565b5060808301516151a16080860182614bd2565b5060a08301516151b460a0860182615802565b5060c08301516151c760c0860182615802565b5060e08301516151da60e0860182615802565b506101008301516151ef610100860182615802565b506101208301518482036101208601526152098282614df4565b9150508091505092915050565b60006101408301600083015161522f6000860182614bd2565b5060208301516152426020860182614bd2565b5060408301516152556040860182614ec7565b5060608301516152686060860182614bd2565b50608083015161527b6080860182614bd2565b5060a083015161528e60a0860182615802565b5060c08301516152a160c0860182615802565b5060e08301516152b460e0860182615802565b506101008301516152c9610100860182615802565b506101208301518482036101208601526152e38282614df4565b9150508091505092915050565b6000610180830160008301516153096000860182614bd2565b50602083015161531c6020860182614ec7565b50604083015161532f6040860182614bd2565b5060608301516153426060860182614ec7565b5060808301516153556080860182614ec7565b5060a083015161536860a0860182615802565b5060c083015161537b60c0860182615802565b5060e083015161538e60e0860182615802565b506101008301516153a3610100860182615802565b506101208301516153b8610120860182615802565b506101408301518482036101408601526153d28282614bf0565b9150506101608301518482036101608601526153ee8282614c4e565b9150508091505092915050565b6000610180830160008301516154146000860182614bd2565b5060208301516154276020860182614ec7565b50604083015161543a6040860182614bd2565b50606083015161544d6060860182614ec7565b5060808301516154606080860182614ec7565b5060a083015161547360a0860182615802565b5060c083015161548660c0860182615802565b5060e083015161549960e0860182615802565b506101008301516154ae610100860182615802565b506101208301516154c3610120860182615802565b506101408301518482036101408601526154dd8282614bf0565b9150506101608301518482036101608601526154f98282614c4e565b9150508091505092915050565b6101e08201600082015161551d6000850182614bd2565b5060208201516155306020850182614ec7565b5060408201516155436040850182614bd2565b5060608201516155566060850182614bd2565b5060808201516155696080850182615802565b5060a082015161557c60a0850182615802565b5060c082015161558f60c0850182615802565b5060e08201516155a260e0850182615802565b506101008201516155b7610100850182615802565b506101208201516155cc610120850182615802565b506101408201516155e1610140850182615802565b506101608201516155f6610160850182615802565b5061018082015161560b610180850182615802565b506101a08201516156206101a0850182615802565b506101c08201516156356101c0850182615802565b50505050565b6101e0820160008201516156526000850182614bd2565b5060208201516156656020850182614ec7565b5060408201516156786040850182614bd2565b50606082015161568b6060850182614bd2565b50608082015161569e6080850182615802565b5060a08201516156b160a0850182615802565b5060c08201516156c460c0850182615802565b5060e08201516156d760e0850182615802565b506101008201516156ec610100850182615802565b50610120820151615701610120850182615802565b50610140820151615716610140850182615802565b5061016082015161572b610160850182615802565b50610180820151615740610180850182615802565b506101a08201516157556101a0850182615802565b506101c082015161576a6101c0850182615802565b50505050565b6060820160008201516157866000850182614bd2565b5060208201516157996020850182615802565b5060408201516157ac6040850182614ec7565b50505050565b60006060830160008301516157ca6000860182614bd2565b50602083015184820360208601526157e28282614f03565b91505060408301516157f76040860182615820565b508091505092915050565b61580b81615d87565b82525050565b61581a81615d87565b82525050565b61582981615d91565b82525050565b60006020820190506158446000830184614be1565b92915050565b600060408201905061585f6000830185614be1565b61586c6020830184614ed6565b9392505050565b60006040820190506158886000830185614be1565b6158956020830184615811565b9392505050565b60006060820190506158b16000830186614be1565b6158be6020830185615811565b6158cb6040830184614ed6565b949350505050565b600060208201905081810360008301526158ed8184614cac565b905092915050565b6000602082019050818103600083015261590f8184614d21565b905092915050565b600060208201905081810360008301526159318184614d96565b905092915050565b600060208201905081810360008301526159538184614e52565b905092915050565b60006020820190506159706000830184614ed6565b92915050565b600060208201905061598b6000830184614ee5565b92915050565b60006020820190506159a66000830184614ef4565b92915050565b600060208201905081810360008301526159c68184614f3c565b905092915050565b600060208201905081810360008301526159e781614f75565b9050919050565b60006020820190508181036000830152615a088184614fe4565b905092915050565b60006020820190508181036000830152615a2a8184615216565b905092915050565b60006020820190508181036000830152615a4c81846153fb565b905092915050565b60006101e082019050615a6a600083018461563b565b92915050565b6000602082019050615a856000830184615811565b92915050565b6000606082019050615aa06000830186615811565b615aad6020830185614be1565b615aba6040830184614be1565b949350505050565b6000604051905081810181811067ffffffffffffffff82111715615ae957615ae8615e19565b5b8060405250919050565b600067ffffffffffffffff821115615b0e57615b0d615e19565b5b602082029050602081019050919050565b600067ffffffffffffffff821115615b3a57615b39615e19565b5b602082029050602081019050919050565b600067ffffffffffffffff821115615b6657615b65615e19565b5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000615d4282615d67565b9050919050565b60008115159050919050565b6000615d6082615d37565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000615da982615db0565b9050919050565b6000615dbb82615d67565b9050919050565b6000615dcd82615dd4565b9050919050565b6000615ddf82615d67565b9050919050565b60005b83811015615e04578082015181840152602081019050615de9565b83811115615e13576000848401525b50505050565bfe5b6000601f19601f8301169050919050565b615e3581615d37565b8114615e4057600080fd5b50565b615e4c81615d49565b8114615e5757600080fd5b50565b615e6381615d55565b8114615e6e57600080fd5b50565b615e7a81615d87565b8114615e8557600080fd5b50565b615e9181615d91565b8114615e9c57600080fd5b5056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212203c4509bb3d04776bfe5321ef001951460cd3273dae5c42ed447bd5013057938264736f6c63430007060033000000000000000000000000cf64698aff7e5f27a11dff868af228653ba53be0
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c806354fd4d5011610097578063b816903911610066578063b8169039146102eb578063ba3b73451461031b578063bf2eb19e1461034b578063fc9914cb1461037b57610100565b806354fd4d501461024f5780637a0c7b211461026d578063a80deda31461028b578063b10b074e146102bb57610100565b80632954018c116100d35780632954018c146101b357806339595cf8146101d15780634b2f336d146102015780634c472fc91461021f57610100565b80630dbd616d1461010557806313d21cdf14610135578063191482d4146101655780631bcd8fc014610195575b600080fd5b61011f600480360381019061011a919061482f565b6103ab565b60405161012c9190615a10565b60405180910390f35b61014f600480360381019061014a91906147dd565b610b08565b60405161015c9190615a54565b60405180910390f35b61017f600480360381019061017a919061482f565b6115af565b60405161018c91906159ee565b60405180910390f35b61019d611c35565b6040516101aa9190615917565b60405180910390f35b6101bb611e1e565b6040516101c89190615976565b60405180910390f35b6101eb60048036038101906101e691906148d2565b611e42565b6040516101f89190615a70565b60405180910390f35b61020961209f565b604051610216919061582f565b60405180910390f35b6102396004803603810190610234919061482f565b6120c3565b604051610246919061582f565b60405180910390f35b6102576122f6565b6040516102649190615a70565b60405180910390f35b6102756122fb565b6040516102829190615991565b60405180910390f35b6102a560048036038101906102a091906147dd565b61231f565b6040516102b291906158d3565b60405180910390f35b6102d560048036038101906102d0919061482f565b6127a1565b6040516102e29190615a32565b60405180910390f35b610305600480360381019061030091906147dd565b6131d5565b60405161031291906158f5565b60405180910390f35b6103356004803603810190610330919061486b565b6133c1565b6040516103429190615a70565b60405180910390f35b61036560048036038101906103609190614998565b61394c565b6040516103729190615939565b60405180910390f35b6103956004803603810190610390919061482f565b613b4b565b6040516103a2919061595b565b60405180910390f35b6103b361422a565b6000806103bf85613d07565b9150915060008273ffffffffffffffffffffffffffffffffffffffff1663e958b704866040518263ffffffff1660e01b81526004016103fe919061582f565b60206040518083038186803b15801561041657600080fd5b505afa15801561042a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044e9190614806565b905061045861422a565b85816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505086816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b15801561054657600080fd5b505afa15801561055a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057e9190614806565b816080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1663c7de38a6836040518263ffffffff1660e01b81526004016105ee919061582f565b60206040518083038186803b15801561060657600080fd5b505afa15801561061a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063e9190614a6c565b8160c00181815250508273ffffffffffffffffffffffffffffffffffffffff1663dfd59465836040518263ffffffff1660e01b8152600401610680919061582f565b60206040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190614a6c565b8160e001818152505060008473ffffffffffffffffffffffffffffffffffffffff1663570a7af26040518163ffffffff1660e01b815260040160206040518083038186803b15801561072157600080fd5b505afa158015610735573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107599190614806565b90508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156107a157600080fd5b505afa1580156107b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d99190614a6c565b8261010001818152505060008473ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108639190614a6c565b90508067ffffffffffffffff8111801561087c57600080fd5b506040519080825280602002602001820160405280156108b657816020015b6108a36142d7565b81526020019060019003908161089b5790505b5083610120018190525060005b81811015610a66576108d36142d7565b8673ffffffffffffffffffffffffffffffffffffffff1663af0a650287846040518363ffffffff1660e01b815260040161090e929190615873565b60806040518083038186803b15801561092657600080fd5b505afa15801561093a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095e9190614935565b9050508260000183602001828152508273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050508673ffffffffffffffffffffffffffffffffffffffff1663f9eaee0d82600001516040518263ffffffff1660e01b81526004016109dc919061582f565b60206040518083038186803b1580156109f457600080fd5b505afa158015610a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2c91906149d9565b816040019015159081151581525050808561012001518381518110610a4d57fe5b60200260200101819052505080806001019150506108c3565b508473ffffffffffffffffffffffffffffffffffffffff16633192195c856040518263ffffffff1660e01b8152600401610aa0919061582f565b60206040518083038186803b158015610ab857600080fd5b505afa158015610acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af09190614a6c565b8360a001818152505082965050505050505092915050565b610b10614310565b817f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16635b16ebb7826040518263ffffffff1660e01b8152600401610b6a919061582f565b60206040518083038186803b158015610b8257600080fd5b505afa158015610b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bba91906149d9565b6040518060400160405280600281526020017f525000000000000000000000000000000000000000000000000000000000000081525090610c31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c2891906159ac565b60405180910390fd5b50610c3a614310565b600084905084826000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1663fe14112d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cbd57600080fd5b505afa158015610cd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf59190614a6c565b8260c00181815250508073ffffffffffffffffffffffffffffffffffffffff1663ef8d96036040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4457600080fd5b505afa158015610d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7c9190614a6c565b8260e00181815250508073ffffffffffffffffffffffffffffffffffffffff1663743753596040518163ffffffff1660e01b815260040160206040518083038186803b158015610dcb57600080fd5b505afa158015610ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e039190614a6c565b8260a00181815250508073ffffffffffffffffffffffffffffffffffffffff16634c19386c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5257600080fd5b505afa158015610e66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8a9190614a6c565b826101000181815250508073ffffffffffffffffffffffffffffffffffffffff1663788c6bfe6040518163ffffffff1660e01b815260040160206040518083038186803b158015610eda57600080fd5b505afa158015610eee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f129190614a6c565b826101600181815250508073ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f6257600080fd5b505afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a9190614a6c565b8260800181815250508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe957600080fd5b505afa158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110219190614a6c565b826101400181815250508073ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b15801561107157600080fd5b505afa158015611085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a99190614806565b826040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff166336dda7d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561112657600080fd5b505afa15801561113a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115e9190614806565b826060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1663788c6bfe6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111db57600080fd5b505afa1580156111ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112139190614a6c565b826101600181815250508073ffffffffffffffffffffffffffffffffffffffff1663e941fa786040518163ffffffff1660e01b815260040160206040518083038186803b15801561126357600080fd5b505afa158015611277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129b9190614a6c565b826101800181815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16148260200190151590811515815250508073ffffffffffffffffffffffffffffffffffffffff1663609ae3176040518163ffffffff1660e01b815260040160206040518083038186803b15801561134d57600080fd5b505afa158015611361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113859190614a6c565b826101c00181815250508073ffffffffffffffffffffffffffffffffffffffff1663dbcb313b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113d557600080fd5b505afa1580156113e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140d9190614a6c565b826101a00181815250506000826060015173ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b9190614a6c565b905060008273ffffffffffffffffffffffffffffffffffffffff16635427c938836040518263ffffffff1660e01b81526004016114d89190615a70565b60206040518083038186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115289190614a6c565b9050600081146115915761158c8161157e611553876101800151612710613eb590919063ffffffff16565b611570886101000151896101400151613f3890919063ffffffff16565b613fbe90919063ffffffff16565b61411990919063ffffffff16565b611598565b8361014001515b846101200181815250508395505050505050919050565b6115b76143ca565b827f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401611611919061582f565b60206040518083038186803b15801561162957600080fd5b505afa15801561163d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166191906149d9565b6040518060400160405280600281526020017f4350000000000000000000000000000000000000000000000000000000000000815250906116d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116cf91906159ac565b60405180910390fd5b506116e16143ca565b60006116ed86866103ab565b90508060000151826000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060200151826020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060600151826060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060800151826080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060a001518260a00181815250508060c001518260c00181815250508060e001518260e00181815250508061010001518261010001818152505080610120015182610120018190525060008673ffffffffffffffffffffffffffffffffffffffff1663e958b704876040518263ffffffff1660e01b8152600401611863919061582f565b60206040518083038186803b15801561187b57600080fd5b505afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614806565b90508073ffffffffffffffffffffffffffffffffffffffff16631afbb7a46040518163ffffffff1660e01b815260040160206040518083038186803b1580156118fb57600080fd5b505afa15801561190f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119339190614a6c565b836101a00181815250508073ffffffffffffffffffffffffffffffffffffffff166317d11a156040518163ffffffff1660e01b815260040160206040518083038186803b15801561198357600080fd5b505afa158015611997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bb9190614a6c565b836101c00181815250508073ffffffffffffffffffffffffffffffffffffffff16633dc54b406040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0b57600080fd5b505afa158015611a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a439190614a6c565b836101e00181815250508673ffffffffffffffffffffffffffffffffffffffff16633ce073558760006040518363ffffffff1660e01b8152600401611a8992919061584a565b60206040518083038186803b158015611aa157600080fd5b505afa158015611ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad99190614a6c565b836101400181815250508673ffffffffffffffffffffffffffffffffffffffff16633ce073558760016040518363ffffffff1660e01b8152600401611b1f92919061584a565b60206040518083038186803b158015611b3757600080fd5b505afa158015611b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6f9190614a6c565b8361016001818152505060008773ffffffffffffffffffffffffffffffffffffffff1663996329f8838560c0015160006040518463ffffffff1660e01b8152600401611bbd9392919061589c565b60a06040518083038186803b158015611bd557600080fd5b505afa158015611be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0d9190614a95565b5050925050506000811184610180019015159081151581525050839550505050505092915050565b606060007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff1663b4ac68606040518163ffffffff1660e01b815260040160206040518083038186803b158015611c9f57600080fd5b505afa158015611cb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd79190614a6c565b905060008167ffffffffffffffff81118015611cf257600080fd5b50604051908082528060200260200182016040528015611d2c57816020015b611d19614310565b815260200190600190039081611d115790505b50905060005b82811015611e155760007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff1663ac4afa38836040518263ffffffff1660e01b8152600401611d959190615a70565b60206040518083038186803b158015611dad57600080fd5b505afa158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de59190614806565b9050611df081610b08565b838381518110611dfc57fe5b6020026020010181905250508080600101915050611d32565b50809250505090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000611e5087613d07565b9150915060008173ffffffffffffffffffffffffffffffffffffffff16632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9c57600080fd5b505afa158015611eb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed49190614806565b9050600061207c8373ffffffffffffffffffffffffffffffffffffffff1663783274388a6040518263ffffffff1660e01b8152600401611f14919061582f565b60206040518083038186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f649190614a6c565b8373ffffffffffffffffffffffffffffffffffffffff1663b66102df8a8c8973ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc857600080fd5b505afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120009190614806565b6040518463ffffffff1660e01b815260040161201e93929190615a8b565b60206040518083038186803b15801561203657600080fd5b505afa15801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190614a6c565b613f3890919063ffffffff16565b9050612091868261411990919063ffffffff16565b945050505050949350505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000827f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b815260040161211f919061582f565b60206040518083038186803b15801561213757600080fd5b505afa15801561214b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216f91906149d9565b6040518060400160405280600281526020017f4350000000000000000000000000000000000000000000000000000000000000815250906121e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121dd91906159ac565b60405180910390fd5b508373ffffffffffffffffffffffffffffffffffffffff1663f93f515b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122659190614a02565b73ffffffffffffffffffffffffffffffffffffffff1663fdd57645846040518263ffffffff1660e01b815260040161229d919061582f565b60206040518083038186803b1580156122b557600080fd5b505afa1580156122c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ed9190614806565b91505092915050565b600181565b7f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9981565b6060600080600090505b7f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561238f57600080fd5b505afa1580156123a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c79190614a6c565b8110156125205760007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b81526004016124299190615a70565b60206040518083038186803b15801561244157600080fd5b505afa158015612455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124799190614806565b90508073ffffffffffffffffffffffffffffffffffffffff1663256ac915866040518263ffffffff1660e01b81526004016124b4919061582f565b60206040518083038186803b1580156124cc57600080fd5b505afa1580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250491906149d9565b156125125782806001019350505b508080600101915050612329565b5060008167ffffffffffffffff8111801561253a57600080fd5b5060405190808252806020026020018201604052801561257457816020015b61256161422a565b8152602001906001900390816125595790505b5090506000915060005b7f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125e457600080fd5b505afa1580156125f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261c9190614a6c565b8110156127965760007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b815260040161267e9190615a70565b60206040518083038186803b15801561269657600080fd5b505afa1580156126aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ce9190614806565b90508073ffffffffffffffffffffffffffffffffffffffff1663256ac915876040518263ffffffff1660e01b8152600401612709919061582f565b60206040518083038186803b15801561272157600080fd5b505afa158015612735573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275991906149d9565b156127885761276881876103ab565b83858151811061277457fe5b602002602001018190525083806001019450505b50808060010191505061257e565b508092505050919050565b6127a96144a3565b6000806127b585613d07565b915091506127c16144a3565b85816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1663256ac915866040518263ffffffff1660e01b8152600401612832919061582f565b60206040518083038186803b15801561284a57600080fd5b505afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288291906149d9565b8160200190151590811515815250508173ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b1580156128d757600080fd5b505afa1580156128eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290f9190614806565b816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff161481606001901515908115158152505060008373ffffffffffffffffffffffffffffffffffffffff1663570a7af26040518163ffffffff1660e01b815260040160206040518083038186803b1580156129f057600080fd5b505afa158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a289190614806565b90508073ffffffffffffffffffffffffffffffffffffffff16632e97ca21886040518263ffffffff1660e01b8152600401612a63919061582f565b60206040518083038186803b158015612a7b57600080fd5b505afa158015612a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab391906149d9565b8260800190151590811515815250508073ffffffffffffffffffffffffffffffffffffffff166345d31f9d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0857600080fd5b505afa158015612b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b409190614a6c565b8260a00181815250508073ffffffffffffffffffffffffffffffffffffffff1663743753596040518163ffffffff1660e01b815260040160206040518083038186803b158015612b8f57600080fd5b505afa158015612ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc79190614a6c565b826101200181815250508373ffffffffffffffffffffffffffffffffffffffff16639b2cb5d86040518163ffffffff1660e01b815260040160206040518083038186803b158015612c1757600080fd5b505afa158015612c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4f9190614a6c565b8260c00181815250508373ffffffffffffffffffffffffffffffffffffffff16635f48f3936040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9e57600080fd5b505afa158015612cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd69190614a6c565b8260e00181815250508373ffffffffffffffffffffffffffffffffffffffff1663b2c53a6c6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d2557600080fd5b505afa158015612d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5d9190614a6c565b8261010001818152505060008373ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b158015612daf57600080fd5b505afa158015612dc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de79190614a6c565b90508067ffffffffffffffff81118015612e0057600080fd5b50604051908082528060200260200182016040528015612e2f5781602001602082028036833780820191505090505b5083610140018190525060005b81811015612f25578473ffffffffffffffffffffffffffffffffffffffff16635e5f2e26826040518263ffffffff1660e01b8152600401612e7d9190615a70565b60206040518083038186803b158015612e9557600080fd5b505afa158015612ea9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecd9190614806565b8461014001518281518110612ede57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050612e3c565b5060008473ffffffffffffffffffffffffffffffffffffffff166350e036ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6e57600080fd5b505afa158015612f82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa69190614a6c565b90508067ffffffffffffffff81118015612fbf57600080fd5b50604051908082528060200260200182016040528015612ff957816020015b612fe6614536565b815260200190600190039081612fde5790505b5084610160018190525060005b818110156131c557613016614536565b8673ffffffffffffffffffffffffffffffffffffffff16635094cb4f836040518263ffffffff1660e01b815260040161304f9190615a70565b60206040518083038186803b15801561306757600080fd5b505afa15801561307b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061309f9190614806565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663fdd5764582600001516040518263ffffffff1660e01b8152600401613113919061582f565b60206040518083038186803b15801561312b57600080fd5b505afa15801561313f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131639190614806565b816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508086610160015183815181106131ac57fe5b6020026020010181905250508080600101915050613006565b5083965050505050505092915050565b606060007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff1663c29277cd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561323f57600080fd5b505afa158015613253573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132779190614a6c565b905060008167ffffffffffffffff8111801561329257600080fd5b506040519080825280602002602001820160405280156132cc57816020015b6132b96144a3565b8152602001906001900390816132b15790505b50905060005b828110156133b65760007f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16631e16e4fc836040518263ffffffff1660e01b81526004016133359190615a70565b60206040518083038186803b15801561334d57600080fd5b505afa158015613361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133859190614806565b905061339181876127a1565b83838151811061339d57fe5b60200260200101819052505080806001019150506132d2565b508092505050919050565b60008060006133cf86613d07565b9150915060008273ffffffffffffffffffffffffffffffffffffffff1663e958b704876040518263ffffffff1660e01b815260040161340e919061582f565b60206040518083038186803b15801561342657600080fd5b505afa15801561343a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345e9190614806565b905060008273ffffffffffffffffffffffffffffffffffffffff16632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156134a857600080fd5b505afa1580156134bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e09190614806565b905060008373ffffffffffffffffffffffffffffffffffffffff166320a05ff76040518163ffffffff1660e01b815260040160206040518083038186803b15801561352a57600080fd5b505afa15801561353e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135629190614a6c565b9050808751146135a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161359e906159ce565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16632495a5996040518163ffffffff1660e01b815260040160206040518083038186803b1580156135f057600080fd5b505afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136289190614806565b905060005b838110156138a0576138916138828873ffffffffffffffffffffffffffffffffffffffff1663783274388a73ffffffffffffffffffffffffffffffffffffffff16635e5f2e26866040518263ffffffff1660e01b81526004016136909190615a70565b60206040518083038186803b1580156136a857600080fd5b505afa1580156136bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e09190614806565b6040518263ffffffff1660e01b81526004016136fc919061582f565b60206040518083038186803b15801561371457600080fd5b505afa158015613728573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374c9190614a6c565b8773ffffffffffffffffffffffffffffffffffffffff1663b66102df8e868151811061377457fe5b60200260200101518c73ffffffffffffffffffffffffffffffffffffffff16635e5f2e26886040518263ffffffff1660e01b81526004016137b59190615a70565b60206040518083038186803b1580156137cd57600080fd5b505afa1580156137e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138059190614806565b886040518463ffffffff1660e01b815260040161382493929190615a8b565b60206040518083038186803b15801561383c57600080fd5b505afa158015613850573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138749190614a6c565b613f3890919063ffffffff16565b846141a290919063ffffffff16565b9250808060010191505061362d565b5061393c8673ffffffffffffffffffffffffffffffffffffffff16633192195c876040518263ffffffff1660e01b81526004016138dd919061582f565b60206040518083038186803b1580156138f557600080fd5b505afa158015613909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392d9190614a6c565b8361411990919063ffffffff16565b9750505050505050509392505050565b60606000825167ffffffffffffffff8111801561396857600080fd5b506040519080825280602002602001820160405280156139a257816020015b61398f61457c565b8152602001906001900390816139875790505b50905060005b8351811015613b415760405180606001604052808583815181106139c857fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018583815181106139f757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015613a4457600080fd5b505afa158015613a58573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190613a819190614a2b565b8152602001858381518110613a9257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015613adf57600080fd5b505afa158015613af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b179190614b0c565b60ff16815250828281518110613b2957fe5b602002602001018190525080806001019150506139a8565b5080915050919050565b6000827f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401613ba7919061582f565b60206040518083038186803b158015613bbf57600080fd5b505afa158015613bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf791906149d9565b6040518060400160405280600281526020017f435000000000000000000000000000000000000000000000000000000000000081525090613c6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c6591906159ac565b60405180910390fd5b5060008490508073ffffffffffffffffffffffffffffffffffffffff1663256ac915856040518263ffffffff1660e01b8152600401613cad919061582f565b60206040518083038186803b158015613cc557600080fd5b505afa158015613cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfd91906149d9565b9250505092915050565b600080827f000000000000000000000000a50d4e7d8946a7c90652339cdbd262c375d54d9973ffffffffffffffffffffffffffffffffffffffff16636fbc6f6b826040518263ffffffff1660e01b8152600401613d64919061582f565b60206040518083038186803b158015613d7c57600080fd5b505afa158015613d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db491906149d9565b6040518060400160405280600281526020017f435000000000000000000000000000000000000000000000000000000000000081525090613e2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613e2291906159ac565b60405180910390fd5b508392508273ffffffffffffffffffffffffffffffffffffffff1663f93f515b6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7557600080fd5b505afa158015613e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ead9190614a02565b915050915091565b600082821115613f2d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b600080831415613f4b5760009050613fb8565b6000828402905082848281613f5c57fe5b0414613fb3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615ea06021913960400191505060405180910390fd5b809150505b92915050565b600080831480613fce5750600082145b15613fdc5760009050614113565b81600261271081613fe957fe5b047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038161401357fe5b048311156040518060400160405280600281526020017f4d31000000000000000000000000000000000000000000000000000000000000815250906140f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156140b857808201518184015260208101905061409d565b50505050905090810190601f1680156140e55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5061271060026127108161410357fe5b04838502018161410f57fe5b0490505b92915050565b6000808211614190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b81838161419957fe5b04905092915050565b600080828401905083811015614220576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001606081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000151581525090565b604051806101e00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806102000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600060ff1681525090565b60006145c96145c484615af3565b615ac2565b905080838252602082019050828560208602820111156145e857600080fd5b60005b8581101561461857816145fe88826146cc565b8452602084019350602083019250506001810190506145eb565b5050509392505050565b600061463561463084615b1f565b615ac2565b9050808382526020820190508285602086028201111561465457600080fd5b60005b85811015614684578161466a888261479e565b845260208401935060208301925050600181019050614657565b5050509392505050565b60006146a161469c84615b4b565b615ac2565b9050828152602081018484840111156146b957600080fd5b6146c4848285615de6565b509392505050565b6000813590506146db81615e2c565b92915050565b6000815190506146f081615e2c565b92915050565b600082601f83011261470757600080fd5b81356147178482602086016145b6565b91505092915050565b600082601f83011261473157600080fd5b8135614741848260208601614622565b91505092915050565b60008151905061475981615e43565b92915050565b60008151905061476e81615e5a565b92915050565b600082601f83011261478557600080fd5b815161479584826020860161468e565b91505092915050565b6000813590506147ad81615e71565b92915050565b6000815190506147c281615e71565b92915050565b6000815190506147d781615e88565b92915050565b6000602082840312156147ef57600080fd5b60006147fd848285016146cc565b91505092915050565b60006020828403121561481857600080fd5b6000614826848285016146e1565b91505092915050565b6000806040838503121561484257600080fd5b6000614850858286016146cc565b9250506020614861858286016146cc565b9150509250929050565b60008060006060848603121561488057600080fd5b600061488e868287016146cc565b935050602061489f868287016146cc565b925050604084013567ffffffffffffffff8111156148bc57600080fd5b6148c886828701614720565b9150509250925092565b600080600080608085870312156148e857600080fd5b60006148f6878288016146cc565b9450506020614907878288016146cc565b93505060406149188782880161479e565b92505060606149298782880161479e565b91505092959194509250565b6000806000806080858703121561494b57600080fd5b6000614959878288016146e1565b945050602061496a878288016147b3565b935050604061497b878288016147b3565b925050606061498c878288016147b3565b91505092959194509250565b6000602082840312156149aa57600080fd5b600082013567ffffffffffffffff8111156149c457600080fd5b6149d0848285016146f6565b91505092915050565b6000602082840312156149eb57600080fd5b60006149f98482850161474a565b91505092915050565b600060208284031215614a1457600080fd5b6000614a228482850161475f565b91505092915050565b600060208284031215614a3d57600080fd5b600082015167ffffffffffffffff811115614a5757600080fd5b614a6384828501614774565b91505092915050565b600060208284031215614a7e57600080fd5b6000614a8c848285016147b3565b91505092915050565b600080600080600060a08688031215614aad57600080fd5b6000614abb888289016147b3565b9550506020614acc888289016147b3565b9450506040614add888289016147b3565b9350506060614aee888289016147b3565b9250506080614aff888289016147b3565b9150509295509295909350565b600060208284031215614b1e57600080fd5b6000614b2c848285016147c8565b91505092915050565b6000614b418383614bd2565b60208301905092915050565b6000614b598383614fb5565b60408301905092915050565b6000614b71838361513c565b905092915050565b6000614b8583836152f0565b905092915050565b6000614b998383615506565b6101e08301905092915050565b6000614bb28383615770565b60608301905092915050565b6000614bca83836157b2565b905092915050565b614bdb81615d37565b82525050565b614bea81615d37565b82525050565b6000614bfb82615beb565b614c058185615c9e565b9350614c1083615b7b565b8060005b83811015614c41578151614c288882614b35565b9750614c3383615c43565b925050600181019050614c14565b5085935050505092915050565b6000614c5982615bf6565b614c638185615caf565b9350614c6e83615b8b565b8060005b83811015614c9f578151614c868882614b4d565b9750614c9183615c50565b925050600181019050614c72565b5085935050505092915050565b6000614cb782615c01565b614cc18185615cc0565b935083602082028501614cd385615b9b565b8060005b85811015614d0f5784840389528151614cf08582614b65565b9450614cfb83615c5d565b925060208a01995050600181019050614cd7565b50829750879550505050505092915050565b6000614d2c82615c0c565b614d368185615cd1565b935083602082028501614d4885615bab565b8060005b85811015614d845784840389528151614d658582614b79565b9450614d7083615c6a565b925060208a01995050600181019050614d4c565b50829750879550505050505092915050565b6000614da182615c17565b614dab8185615ce2565b9350614db683615bbb565b8060005b83811015614de7578151614dce8882614b8d565b9750614dd983615c77565b925050600181019050614dba565b5085935050505092915050565b6000614dff82615c22565b614e098185615cf3565b9350614e1483615bcb565b8060005b83811015614e45578151614e2c8882614ba6565b9750614e3783615c84565b925050600181019050614e18565b5085935050505092915050565b6000614e5d82615c2d565b614e678185615d04565b935083602082028501614e7985615bdb565b8060005b85811015614eb55784840389528151614e968582614bbe565b9450614ea183615c91565b925060208a01995050600181019050614e7d565b50829750879550505050505092915050565b614ed081615d49565b82525050565b614edf81615d49565b82525050565b614eee81615d9e565b82525050565b614efd81615dc2565b82525050565b6000614f0e82615c38565b614f188185615d15565b9350614f28818560208601615de6565b614f3181615e1b565b840191505092915050565b6000614f4782615c38565b614f518185615d26565b9350614f61818560208601615de6565b614f6a81615e1b565b840191505092915050565b6000614f82601783615d26565b91507f496e636f72726563742062616c616e6365732073697a650000000000000000006000830152602082019050919050565b604082016000820151614fcb6000850182614bd2565b506020820151614fde6020850182614bd2565b50505050565b600061020083016000830151614ffd6000860182614bd2565b5060208301516150106020860182614bd2565b5060408301516150236040860182614ec7565b5060608301516150366060860182614bd2565b5060808301516150496080860182614bd2565b5060a083015161505c60a0860182615802565b5060c083015161506f60c0860182615802565b5060e083015161508260e0860182615802565b50610100830151615097610100860182615802565b506101208301518482036101208601526150b18282614df4565b9150506101408301516150c8610140860182615802565b506101608301516150dd610160860182615802565b506101808301516150f2610180860182614ec7565b506101a08301516151076101a0860182615802565b506101c083015161511c6101c0860182615802565b506101e08301516151316101e0860182615802565b508091505092915050565b6000610140830160008301516151556000860182614bd2565b5060208301516151686020860182614bd2565b50604083015161517b6040860182614ec7565b50606083015161518e6060860182614bd2565b5060808301516151a16080860182614bd2565b5060a08301516151b460a0860182615802565b5060c08301516151c760c0860182615802565b5060e08301516151da60e0860182615802565b506101008301516151ef610100860182615802565b506101208301518482036101208601526152098282614df4565b9150508091505092915050565b60006101408301600083015161522f6000860182614bd2565b5060208301516152426020860182614bd2565b5060408301516152556040860182614ec7565b5060608301516152686060860182614bd2565b50608083015161527b6080860182614bd2565b5060a083015161528e60a0860182615802565b5060c08301516152a160c0860182615802565b5060e08301516152b460e0860182615802565b506101008301516152c9610100860182615802565b506101208301518482036101208601526152e38282614df4565b9150508091505092915050565b6000610180830160008301516153096000860182614bd2565b50602083015161531c6020860182614ec7565b50604083015161532f6040860182614bd2565b5060608301516153426060860182614ec7565b5060808301516153556080860182614ec7565b5060a083015161536860a0860182615802565b5060c083015161537b60c0860182615802565b5060e083015161538e60e0860182615802565b506101008301516153a3610100860182615802565b506101208301516153b8610120860182615802565b506101408301518482036101408601526153d28282614bf0565b9150506101608301518482036101608601526153ee8282614c4e565b9150508091505092915050565b6000610180830160008301516154146000860182614bd2565b5060208301516154276020860182614ec7565b50604083015161543a6040860182614bd2565b50606083015161544d6060860182614ec7565b5060808301516154606080860182614ec7565b5060a083015161547360a0860182615802565b5060c083015161548660c0860182615802565b5060e083015161549960e0860182615802565b506101008301516154ae610100860182615802565b506101208301516154c3610120860182615802565b506101408301518482036101408601526154dd8282614bf0565b9150506101608301518482036101608601526154f98282614c4e565b9150508091505092915050565b6101e08201600082015161551d6000850182614bd2565b5060208201516155306020850182614ec7565b5060408201516155436040850182614bd2565b5060608201516155566060850182614bd2565b5060808201516155696080850182615802565b5060a082015161557c60a0850182615802565b5060c082015161558f60c0850182615802565b5060e08201516155a260e0850182615802565b506101008201516155b7610100850182615802565b506101208201516155cc610120850182615802565b506101408201516155e1610140850182615802565b506101608201516155f6610160850182615802565b5061018082015161560b610180850182615802565b506101a08201516156206101a0850182615802565b506101c08201516156356101c0850182615802565b50505050565b6101e0820160008201516156526000850182614bd2565b5060208201516156656020850182614ec7565b5060408201516156786040850182614bd2565b50606082015161568b6060850182614bd2565b50608082015161569e6080850182615802565b5060a08201516156b160a0850182615802565b5060c08201516156c460c0850182615802565b5060e08201516156d760e0850182615802565b506101008201516156ec610100850182615802565b50610120820151615701610120850182615802565b50610140820151615716610140850182615802565b5061016082015161572b610160850182615802565b50610180820151615740610180850182615802565b506101a08201516157556101a0850182615802565b506101c082015161576a6101c0850182615802565b50505050565b6060820160008201516157866000850182614bd2565b5060208201516157996020850182615802565b5060408201516157ac6040850182614ec7565b50505050565b60006060830160008301516157ca6000860182614bd2565b50602083015184820360208601526157e28282614f03565b91505060408301516157f76040860182615820565b508091505092915050565b61580b81615d87565b82525050565b61581a81615d87565b82525050565b61582981615d91565b82525050565b60006020820190506158446000830184614be1565b92915050565b600060408201905061585f6000830185614be1565b61586c6020830184614ed6565b9392505050565b60006040820190506158886000830185614be1565b6158956020830184615811565b9392505050565b60006060820190506158b16000830186614be1565b6158be6020830185615811565b6158cb6040830184614ed6565b949350505050565b600060208201905081810360008301526158ed8184614cac565b905092915050565b6000602082019050818103600083015261590f8184614d21565b905092915050565b600060208201905081810360008301526159318184614d96565b905092915050565b600060208201905081810360008301526159538184614e52565b905092915050565b60006020820190506159706000830184614ed6565b92915050565b600060208201905061598b6000830184614ee5565b92915050565b60006020820190506159a66000830184614ef4565b92915050565b600060208201905081810360008301526159c68184614f3c565b905092915050565b600060208201905081810360008301526159e781614f75565b9050919050565b60006020820190508181036000830152615a088184614fe4565b905092915050565b60006020820190508181036000830152615a2a8184615216565b905092915050565b60006020820190508181036000830152615a4c81846153fb565b905092915050565b60006101e082019050615a6a600083018461563b565b92915050565b6000602082019050615a856000830184615811565b92915050565b6000606082019050615aa06000830186615811565b615aad6020830185614be1565b615aba6040830184614be1565b949350505050565b6000604051905081810181811067ffffffffffffffff82111715615ae957615ae8615e19565b5b8060405250919050565b600067ffffffffffffffff821115615b0e57615b0d615e19565b5b602082029050602081019050919050565b600067ffffffffffffffff821115615b3a57615b39615e19565b5b602082029050602081019050919050565b600067ffffffffffffffff821115615b6657615b65615e19565b5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000615d4282615d67565b9050919050565b60008115159050919050565b6000615d6082615d37565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000615da982615db0565b9050919050565b6000615dbb82615d67565b9050919050565b6000615dcd82615dd4565b9050919050565b6000615ddf82615d67565b9050919050565b60005b83811015615e04578082015181840152602081019050615de9565b83811115615e13576000848401525b50505050565bfe5b6000601f19601f8301169050919050565b615e3581615d37565b8114615e4057600080fd5b50565b615e4c81615d49565b8114615e5757600080fd5b50565b615e6381615d55565b8114615e6e57600080fd5b50565b615e7a81615d87565b8114615e8557600080fd5b50565b615e9181615d91565b8114615e9c57600080fd5b5056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212203c4509bb3d04776bfe5321ef001951460cd3273dae5c42ed447bd5013057938264736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000cf64698aff7e5f27a11dff868af228653ba53be0
-----Decoded View---------------
Arg [0] : _addressProvider (address): 0xcF64698AFF7E5f27A11dff868AF228653ba53be0
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000cf64698aff7e5f27a11dff868af228653ba53be0
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.