Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x61016060 | 15833599 | 897 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
CreditManager
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 1000000 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, 2022 pragma solidity ^0.8.10; // LIBRARIES import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { ACLTrait } from "../core/ACLTrait.sol"; // INTERFACES 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 { ICreditManagerV2, ClosureAction } from "../interfaces/ICreditManagerV2.sol"; import { IAddressProvider } from "../interfaces/IAddressProvider.sol"; import { IPriceOracleV2 } from "../interfaces/IPriceOracle.sol"; // CONSTANTS import { RAY } from "../libraries/Constants.sol"; import { PERCENTAGE_FACTOR } from "../libraries/PercentageMath.sol"; import { DEFAULT_FEE_INTEREST, DEFAULT_FEE_LIQUIDATION, DEFAULT_LIQUIDATION_PREMIUM, LEVERAGE_DECIMALS, ALLOWANCE_THRESHOLD, UNIVERSAL_CONTRACT } from "../libraries/Constants.sol"; uint256 constant ADDR_BIT_SIZE = 160; uint256 constant INDEX_PRECISION = 10**9; struct Slot1 { /// @dev Interest fee charged by the protocol: fee = interest accrued * feeInterest uint16 feeInterest; /// @dev Liquidation fee charged by the protocol: fee = totalValue * feeLiquidation uint16 feeLiquidation; /// @dev Multiplier used to compute the total value of funds during liquidation. /// At liquidation, the borrower's funds are discounted, and the pool is paid out of discounted value /// The liquidator takes the difference between the discounted and actual values as premium. uint16 liquidationDiscount; /// @dev Liquidation fee charged by the protocol during liquidation by expiry. Typically lower than feeLiquidation. uint16 feeLiquidationExpired; /// @dev Multiplier used to compute the total value of funds during liquidation by expiry. Typically higher than /// liquidationDiscount (meaning lower premium). uint16 liquidationDiscountExpired; /// @dev Price oracle used to evaluate assets on Credit Accounts. IPriceOracleV2 priceOracle; /// @dev Liquidation threshold for the underlying token. uint16 ltUnderlying; } /// @title Credit Manager /// @notice Encapsulates the business logic for managing Credit Accounts /// /// More info: https://dev.gearbox.fi/developers/credit/credit_manager contract CreditManager is ICreditManagerV2, ACLTrait { using SafeERC20 for IERC20; using Address for address payable; using SafeCast for uint256; /// @dev used to protect against reentrancy. Bool is gas-optimal, /// since there are other non-zero values packed into the same slot bool private entered; bool public emergencyLiquidation; /// @dev The maximal number of enabled tokens on a single Credit Account uint8 public override maxAllowedEnabledTokenLength = 12; /// @dev Address of the connected Credit Facade address public override creditFacade; /// @dev Stores fees & parameters commonly used together for gas savings Slot1 internal slot1; /// @dev A map from borrower addresses to Credit Account addresses mapping(address => address) public override creditAccounts; /// @dev Factory contract for Credit Accounts IAccountFactory public immutable _accountFactory; /// @dev Address of the underlying asset address public immutable override underlying; /// @dev Address of the connected pool /// @notice [DEPRECATED]: use pool() instead. address public immutable override poolService; /// @dev Address of the connected pool address public immutable override pool; /// @dev Address of WETH address public immutable override wethAddress; /// @dev Address of WETH Gateway address public immutable wethGateway; /// @dev Address of the connected Credit Configurator address public creditConfigurator; /// @dev Map of token's bit mask to its address and LT compressed into a single uint256 /// @notice Use collateralTokens(uint256 i) to get uncompressed values. mapping(uint256 => uint256) internal collateralTokensCompressed; /// @dev Total number of known collateral tokens. uint256 public collateralTokensCount; /// @dev Internal map of token addresses to their indidivual masks. /// @notice A mask is a uint256 that has only 1 non-zero bit in the position correspondingto /// the token's index (i.e., tokenMask = 2 ** index) /// Masks are used to efficiently check set inclusion, since it only involves /// a single AND and comparison to zero mapping(address => uint256) internal tokenMasksMapInternal; /// @dev Bit mask encoding a set of forbidden tokens uint256 public override forbiddenTokenMask; /// @dev Maps Credit Accounts to bit masks encoding their enabled token sets /// Only enabled tokens are counted as collateral for the Credit Account /// @notice An enabled token mask encodes an enabled token by setting /// the bit at the position equal to token's index to 1 mapping(address => uint256) public override enabledTokensMap; /// @dev Maps Credit Accounts to their current cumulative drops in value during fast checks /// See more details in fastCollateralCheck() mapping(address => uint256) public cumulativeDropAtFastCheckRAY; /// @dev Maps allowed adapters to their respective target contracts. mapping(address => address) public override adapterToContract; /// @dev Maps 3rd party contracts to their respective adapters mapping(address => address) public override contractToAdapter; /// @dev Maps addresses to their status as emergency liquidator. /// @notice Emergency liquidators are trusted addresses /// that are able to liquidate positions while the contracts are paused, /// e.g. when there is a risk of bad debt while an exploit is being patched. /// In the interest of fairness, emergency liquidators do not receive a premium /// And are compensated by the Gearbox DAO separately. mapping(address => bool) public override canLiquidateWhilePaused; /// @dev Stores address of the Universal adapter /// @notice See more at https://dev.gearbox.fi/docs/documentation/integrations/universal address public universalAdapter; /// @dev contract version uint256 public constant override version = 2; // // MODIFIERS // /// @dev Protects against reentrancy. /// @notice Custom ReentrancyGuard implementation is used to optimize storage reads. modifier nonReentrant() { if (entered) { revert ReentrancyLockException(); } entered = true; _; entered = false; } /// @dev Restricts calls to Credit Facade or allowed adapters modifier adaptersOrCreditFacadeOnly() { if ( adapterToContract[msg.sender] == address(0) && msg.sender != creditFacade ) revert AdaptersOrCreditFacadeOnlyException(); // _; } /// @dev Restricts calls to Credit Facade only modifier creditFacadeOnly() { if (msg.sender != creditFacade) revert CreditFacadeOnlyException(); _; } /// @dev Restricts calls to Credit Configurator only modifier creditConfiguratorOnly() { if (msg.sender != creditConfigurator) revert CreditConfiguratorOnlyException(); _; } modifier whenNotPausedOrEmergency() { require(!paused() || emergencyLiquidation, "Pausable: paused"); _; } /// @dev Constructor /// @param _pool Address of the pool to borrow funds from constructor(address _pool) ACLTrait(address(IPoolService(_pool).addressProvider())) { IAddressProvider addressProvider = IPoolService(_pool) .addressProvider(); pool = _pool; // F:[CM-1] poolService = _pool; // F:[CM-1] address _underlying = IPoolService(pool).underlyingToken(); // F:[CM-1] underlying = _underlying; // F:[CM-1] // The underlying is the first token added as collateral _addToken(_underlying); // F:[CM-1] wethAddress = addressProvider.getWethToken(); // F:[CM-1] wethGateway = addressProvider.getWETHGateway(); // F:[CM-1] // Price oracle is stored in Slot1, as it is accessed frequently with fees slot1.priceOracle = IPriceOracleV2(addressProvider.getPriceOracle()); // F:[CM-1] _accountFactory = IAccountFactory(addressProvider.getAccountFactory()); // F:[CM-1] creditConfigurator = msg.sender; // F:[CM-1] } // // CREDIT ACCOUNT MANAGEMENT // /// @dev Opens credit account and borrows funds from the pool. /// - Takes Credit Account from the factory; /// - Requests the pool to lend underlying to the Credit Account /// /// @param borrowedAmount Amount to be borrowed by the Credit Account /// @param onBehalfOf The owner of the newly opened Credit Account function openCreditAccount(uint256 borrowedAmount, address onBehalfOf) external override whenNotPaused // F:[CM-5] nonReentrant creditFacadeOnly // F:[CM-2] returns (address) { // Takes a Credit Account from the factory and sets initial parameters // The Credit Account will be connected to this Credit Manager until closing address creditAccount = _accountFactory.takeCreditAccount( borrowedAmount, IPoolService(pool).calcLinearCumulative_RAY() ); // F:[CM-8] // Requests the pool to transfer tokens the Credit Account IPoolService(pool).lendCreditAccount(borrowedAmount, creditAccount); // F:[CM-8] // Checks that the onBehalfOf does not already have an account, and records it as owner _safeCreditAccountSet(onBehalfOf, creditAccount); // F:[CM-7] // Initializes the enabled token mask for Credit Account to 1 (only the underlying is enabled) enabledTokensMap[creditAccount] = 1; // F:[CM-8] // Returns the address of the opened Credit Account return creditAccount; // F:[CM-8] } /// @dev Closes a Credit Account - covers both normal closure and liquidation /// - Checks whether the contract is paused, and, if so, if the payer is an emergency liquidator. /// Only emergency liquidators are able to liquidate account while the CM is paused. /// Emergency liquidations do not pay a liquidator premium or liquidation fees. /// - Calculates payments to various recipients on closure: /// + Computes amountToPool, which is the amount to be sent back to the pool. /// This includes the principal, interest and fees, but can't be more than /// total position value /// + Computes remainingFunds during liquidations - these are leftover funds /// after paying the pool and the liquidator, and are sent to the borrower /// + Computes protocol profit, which includes interest and liquidation fees /// + Computes loss if the totalValue is less than borrow amount + interest /// - Checks the underlying token balance: /// + if it is larger than amountToPool, then the pool is paid fully from funds on the Credit Account /// + else tries to transfer the shortfall from the payer - either the borrower during closure, or liquidator during liquidation /// - Send assets to the "to" address, as long as they are not included into skipTokenMask /// - If convertWETH is true, the function converts WETH into ETH before sending /// - Returns the Credit Account back to factory /// /// @param borrower Borrower address /// @param closureActionType Whether the account is closed, liquidated or liquidated due to expiry /// @param totalValue Portfolio value for liqution, 0 for ordinary closure /// @param payer Address which would be charged if credit account has not enough funds to cover amountToPool /// @param to Address to which the leftover funds will be sent /// @param skipTokenMask Tokenmask contains 1 for tokens which needed to be skipped for sending /// @param convertWETH If true converts WETH to ETH function closeCreditAccount( address borrower, ClosureAction closureActionType, uint256 totalValue, address payer, address to, uint256 skipTokenMask, bool convertWETH ) external override nonReentrant creditFacadeOnly // F:[CM-2] returns (uint256 remainingFunds) { // If the contract is paused and the payer is the emergency liquidator, // changes closure action to LIQUIDATE_PAUSED, so that the premium is nullified // If the payer is not an emergency liquidator, reverts if (paused()) { if ( canLiquidateWhilePaused[payer] && (closureActionType == ClosureAction.LIQUIDATE_ACCOUNT || closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT) ) { closureActionType = ClosureAction.LIQUIDATE_PAUSED; // F: [CM-12, 13] } else revert("Pausable: paused"); // F:[CM-5] } // Checks that the Credit Account exists for the borrower address creditAccount = getCreditAccountOrRevert(borrower); // F:[CM-6, 9, 10] // Sets borrower's Credit Account to zero address in the map // This needs to be done before other actions, to prevent inconsistent state // in the middle of closing transaction - e.g., _transferAssetsTo can be used to report a lower // value of a CA to third parties before the end of the function execution, since it // gives up control flow when some assets are already removed from the account delete creditAccounts[borrower]; // F:[CM-9] // Makes all computations needed to close credit account uint256 amountToPool; uint256 borrowedAmount; { uint256 profit; uint256 loss; uint256 borrowedAmountWithInterest; ( borrowedAmount, borrowedAmountWithInterest, ) = calcCreditAccountAccruedInterest(creditAccount); // F: (amountToPool, remainingFunds, profit, loss) = calcClosePayments( totalValue, closureActionType, borrowedAmount, borrowedAmountWithInterest ); // F:[CM-10,11,12] uint256 underlyingBalance = IERC20(underlying).balanceOf( creditAccount ); // If there is an underlying surplus, transfers it to the "to" address if (underlyingBalance > amountToPool + remainingFunds + 1) { unchecked { _safeTokenTransfer( creditAccount, underlying, to, underlyingBalance - amountToPool - remainingFunds - 1, convertWETH ); // F:[CM-10,12,16] } // If there is an underlying shortfall, attempts to transfer it from the payer } else { unchecked { IERC20(underlying).safeTransferFrom( payer, creditAccount, amountToPool + remainingFunds - underlyingBalance + 1 ); // F:[CM-11,13] } } // Transfers the due funds to the pool _safeTokenTransfer( creditAccount, underlying, pool, amountToPool, false ); // F:[CM-10,11,12,13] // Signals to the pool that debt has been repaid. The pool relies // on the Credit Manager to repay the debt correctly, and does not // check internally whether the underlying was actually transferred IPoolService(pool).repayCreditAccount(borrowedAmount, profit, loss); // F:[CM-10,11,12,13] } // transfer remaining funds to the borrower [liquidations only] if (remainingFunds > 1) { _safeTokenTransfer( creditAccount, underlying, borrower, remainingFunds, false ); // F:[CM-13,18] } // Tokens in skipTokenMask are disabled before transferring all assets uint256 enabledTokensMask = enabledTokensMap[creditAccount] & ~skipTokenMask; // F:[CM-14] _transferAssetsTo(creditAccount, to, convertWETH, enabledTokensMask); // F:[CM-14,17,19] // Returns Credit Account to the factory _accountFactory.returnCreditAccount(creditAccount); // F:[CM-9] } /// @dev Manages debt size for borrower: /// /// - Increase debt: /// + Increases debt by transferring funds from the pool to the credit account /// + Updates the cumulative index to keep interest the same. Since interest /// is always computed dynamically as borrowedAmount * (cumulativeIndexNew / cumulativeIndexOpen - 1), /// cumulativeIndexOpen needs to be updated, as the borrow amount has changed /// /// - Decrease debt: /// + Repays debt partially + all interest and fees accrued thus far /// + Updates cunulativeIndex to cumulativeIndex now /// /// @param creditAccount Address of the Credit Account to change debt for /// @param amount Amount to increase / decrease the principal by /// @param increase True to increase principal, false to decrease /// @return newBorrowedAmount The new debt principal function manageDebt( address creditAccount, uint256 amount, bool increase ) external whenNotPaused // F:[CM-5] nonReentrant creditFacadeOnly // F:[CM-2] returns (uint256 newBorrowedAmount) { ( uint256 borrowedAmount, uint256 cumulativeIndexAtOpen_RAY, uint256 cumulativeIndexNow_RAY ) = _getCreditAccountParameters(creditAccount); uint256 newCumulativeIndex; if (increase) { newBorrowedAmount = borrowedAmount + amount; // Computes the new cumulative index to keep the interest // unchanged with different principal newCumulativeIndex = _calcNewCumulativeIndex( borrowedAmount, amount, cumulativeIndexNow_RAY, cumulativeIndexAtOpen_RAY, true ); // Requests the pool to lend additional funds to the Credit Account IPoolService(pool).lendCreditAccount(amount, creditAccount); // F:[CM-20] } else { // Computes the interest accrued thus far uint256 interestAccrued = (borrowedAmount * cumulativeIndexNow_RAY) / cumulativeIndexAtOpen_RAY - borrowedAmount; // F:[CM-21] // Computes profit, taken as a percentage of the interest rate uint256 profit = (interestAccrued * slot1.feeInterest) / PERCENTAGE_FACTOR; // F:[CM-21] if (amount >= interestAccrued + profit) { // If the amount covers all of the interest and fees, they are // paid first, and the remainder is used to pay the principal newBorrowedAmount = borrowedAmount + interestAccrued + profit - amount; // Pays the amount back to the pool ICreditAccount(creditAccount).safeTransfer( underlying, pool, amount ); // F:[CM-21] // Signals the pool that the debt was partially repaid IPoolService(pool).repayCreditAccount( amount - interestAccrued - profit, profit, 0 ); // F:[CM-21] // Since interest is fully repaid, the Credit Account's cumulativeIndexAtOpen // is set to the current cumulative index - which means interest starts accruing // on the new principal from zero newCumulativeIndex = IPoolService(pool) .calcLinearCumulative_RAY(); // F:[CM-21] } else { // If the amount is not enough to cover interest and fees, // it is split between the two pro-rata. Since the fee is the percentage // of interest, this ensures that the new fee is consistent with the // new pending interest uint256 amountToInterest = (amount * PERCENTAGE_FACTOR) / (PERCENTAGE_FACTOR + slot1.feeInterest); uint256 amountToFees = amount - amountToInterest; // Since interest and fees are paid out first, the principal // remains unchanged newBorrowedAmount = borrowedAmount; // Pays the amount back to the pool ICreditAccount(creditAccount).safeTransfer( underlying, pool, amount ); // F:[CM-21] // Signals the pool that the debt was partially repaid IPoolService(pool).repayCreditAccount(0, amountToFees, 0); // F:[CM-21] // Since the interest was only repaid partially, we need to recompute the // cumulativeIndexAtOpen, so that "borrowAmount * (indexNow / indexAtOpenNew - 1)" // is equal to interestAccrued - amountToInterest newCumulativeIndex = _calcNewCumulativeIndex( borrowedAmount, amountToInterest, cumulativeIndexNow_RAY, cumulativeIndexAtOpen_RAY, false ); } } // // Sets new parameters on the Credit Account ICreditAccount(creditAccount).updateParameters( newBorrowedAmount, newCumulativeIndex ); // F:[CM-20. 21] } /// @dev Calculates the new cumulative index when debt is updated /// @param borrowedAmount Current debt principal /// @param delta Absolute value of total debt amount change /// @param cumulativeIndexNow Current cumulative index of the pool /// @param cumulativeIndexOpen Last updated cumulative index recorded for the corresponding debt position /// @param isIncrease Whether the debt is increased or decreased /// @notice Handles two potential cases: /// * Debt principal is increased by delta - in this case, the principal is changed /// but the interest / fees have to stay the same /// * Interest is decreased by delta - in this case, the principal stays the same, /// but the interest changes. The delta is assumed to have fee repayment excluded. /// The debt decrease case where delta > interest + fees is trivial and should be handled outside /// this function. function _calcNewCumulativeIndex( uint256 borrowedAmount, uint256 delta, uint256 cumulativeIndexNow, uint256 cumulativeIndexOpen, bool isIncrease ) internal pure returns (uint256 newCumulativeIndex) { if (isIncrease) { // In case of debt increase, the principal increases by exactly delta, but interest has to be kept unchanged // newCumulativeIndex is proven to be the solution to // borrowedAmount * (cumulativeIndexNow / cumulativeIndexOpen - 1) == // == (borrowedAmount + delta) * (cumulativeIndexNow / newCumulativeIndex - 1) uint256 newBorrowedAmount = borrowedAmount + delta; newCumulativeIndex = ((cumulativeIndexNow * newBorrowedAmount * INDEX_PRECISION) / ((INDEX_PRECISION * cumulativeIndexNow * borrowedAmount) / cumulativeIndexOpen + INDEX_PRECISION * delta)); } else { // In case of debt decrease, the principal is the same, but the interest is reduced exactly by delta // newCumulativeIndex is proven to be the solution to // borrowedAmount * (cumulativeIndexNow / cumulativeIndexOpen - 1) - delta == // == borrowedAmount * (cumulativeIndexNow / newCumulativeIndex - 1) newCumulativeIndex = (INDEX_PRECISION * cumulativeIndexNow * cumulativeIndexOpen) / (INDEX_PRECISION * cumulativeIndexNow - (INDEX_PRECISION * delta * cumulativeIndexOpen) / borrowedAmount); } } /// @dev Adds collateral to borrower's credit account /// @param payer Address of the account which will be charged to provide additional collateral /// @param creditAccount Address of the Credit Account /// @param token Collateral token to add /// @param amount Amount to add function addCollateral( address payer, address creditAccount, address token, uint256 amount ) external whenNotPaused // F:[CM-5] nonReentrant creditFacadeOnly // F:[CM-2] { // Checks that the token is not forbidden // And enables it so that it is counted in collateral _checkAndEnableToken(creditAccount, token); // F:[CM-22] IERC20(token).safeTransferFrom(payer, creditAccount, amount); // F:[CM-22] } /// @dev Transfers Credit Account ownership to another address /// @param from Address of previous owner /// @param to Address of new owner function transferAccountOwnership(address from, address to) external override whenNotPausedOrEmergency // F:[CM-5] nonReentrant creditFacadeOnly // F:[CM-2] { address creditAccount = getCreditAccountOrRevert(from); // F:[CM-6] delete creditAccounts[from]; // F:[CM-24] _safeCreditAccountSet(to, creditAccount); // F:[CM-23, 24] } /// @dev Requests the Credit Account to approve a collateral token to another contract. /// @param borrower Borrower's address /// @param targetContract Spender to change allowance for /// @param token Collateral token to approve /// @param amount New allowance amount function approveCreditAccount( address borrower, address targetContract, address token, uint256 amount ) external override whenNotPausedOrEmergency // F:[CM-5] nonReentrant { // This function can only be called by connected adapters (must be a correct adapter/contract pair), // Credit Facade or Universal Adapter if ( (adapterToContract[msg.sender] != targetContract && msg.sender != creditFacade && msg.sender != universalAdapter) || targetContract == address(0) ) { revert AdaptersOrCreditFacadeOnlyException(); // F:[CM-3,25] } // Checks that the token is a collateral token // Forbidden tokens can be approved, since users need that to // sell them off if (tokenMasksMap(token) == 0) revert TokenNotAllowedException(); // F: address creditAccount = getCreditAccountOrRevert(borrower); // F:[CM-6] // Attempts to set allowance directly to the required amount // If unsuccessful, assumes that the token requires setting allowance to zero first if (!_approve(token, targetContract, creditAccount, amount, false)) { _approve(token, targetContract, creditAccount, 0, true); // F: _approve(token, targetContract, creditAccount, amount, true); } } /// @dev Internal function used to approve token from a Credit Account /// Uses Credit Account's execute to properly handle both ERC20-compliant and /// non-compliant (no returned value from "approve") tokens function _approve( address token, address targetContract, address creditAccount, uint256 amount, bool revertIfFailed ) internal returns (bool) { // Makes a low-level call to approve from the Credit Account // and parses the value. If nothing or true was returned, // assumes that the call succeeded try ICreditAccount(creditAccount).execute( token, abi.encodeWithSelector( IERC20.approve.selector, targetContract, amount ) ) returns (bytes memory result) { if (result.length == 0 || abi.decode(result, (bool)) == true) return true; } catch {} // On the first try, failure is allowed to handle tokens // that prohibit changing allowance from non-zero value; // After that, failure results in a revert if (revertIfFailed) revert AllowanceFailedException(); return false; } /// @dev Requests a Credit Account to make a low-level call with provided data /// This is the intended pathway for state-changing interactions with 3rd-party protocols /// @param borrower Borrower's address /// @param targetContract Contract to be called /// @param data Data to pass with the call function executeOrder( address borrower, address targetContract, bytes memory data ) external override whenNotPausedOrEmergency // F:[CM-5] nonReentrant returns (bytes memory) { // Checks that msg.sender is the adapter associated with the passed // target contract. The exception is the Universal Adapter, which // can potentially call any target. if ( adapterToContract[msg.sender] != targetContract || targetContract == address(0) ) { if (msg.sender != universalAdapter) revert TargetContractNotAllowedException(); // F:[CM-28] } address creditAccount = getCreditAccountOrRevert(borrower); // F:[CM-6] // Emits an event emit ExecuteOrder(borrower, targetContract); // F:[CM-29] // Returned data is provided as-is to the caller; // It is expected that is is parsed and returned as a correct type // by the adapter itself. return ICreditAccount(creditAccount).execute(targetContract, data); // F:[CM-29] } // // COLLATERAL VALIDITY AND ACCOUNT HEALTH CHECKS // /// @dev Enables a token on a Credit Account, including it /// into account health and total value calculations /// @param creditAccount Address of a Credit Account to enable the token for /// @param token Address of the token to be enabled function checkAndEnableToken(address creditAccount, address token) external override whenNotPausedOrEmergency adaptersOrCreditFacadeOnly // F:[CM-3] nonReentrant { _checkAndEnableToken(creditAccount, token); // F:[CM-30] } /// @dev IMPLEMENTATION: checkAndEnableToken /// @param creditAccount Address of a Credit Account to enable the token for /// @param token Address of the token to be enabled function _checkAndEnableToken(address creditAccount, address token) internal { uint256 tokenMask = tokenMasksMap(token); // F:[CM-30,31] // Checks that the token is valid collateral recognized by the system // and that it is not forbidden if (tokenMask == 0 || forbiddenTokenMask & tokenMask != 0) revert TokenNotAllowedException(); // F:[CM-30] // Performs an inclusion check using token masks, // to avoid accidentally disabling the token if (enabledTokensMap[creditAccount] & tokenMask == 0) enabledTokensMap[creditAccount] |= tokenMask; // F:[CM-31] } /// @dev Optimized health check for individual swap-like operations. /// @notice Fast health check assumes that only two tokens (input and output) /// participate in the operation and computes a % change in weighted value between /// inbound and outbound collateral. The cumulative negative change across several /// swaps in sequence cannot be larger than feeLiquidation (a fee that the /// protocol is ready to waive if needed). Since this records a % change /// between just two tokens, the corresponding % change in TWV will always be smaller, /// which makes this check safe. /// More details at https://dev.gearbox.fi/docs/documentation/risk/fast-collateral-check#fast-check-protection /// @param creditAccount Address of the Credit Account /// @param tokenIn Address of the token spent by the swap /// @param tokenOut Address of the token received from the swap /// @param balanceInBefore Balance of tokenIn before the operation /// @param balanceOutBefore Balance of tokenOut before the operation function fastCollateralCheck( address creditAccount, address tokenIn, address tokenOut, uint256 balanceInBefore, uint256 balanceOutBefore ) external override adaptersOrCreditFacadeOnly // F:[CM-3] nonReentrant { // Checks that inbound collateral is known and not forbidden // Enables it if disabled, to include it into TWV _checkAndEnableToken(creditAccount, tokenOut); // [CM-32] uint256 balanceInAfter = IERC20(tokenIn).balanceOf(creditAccount); // F: [CM-34] uint256 balanceOutAfter = IERC20(tokenOut).balanceOf(creditAccount); // F: [CM-34] (uint256 amountInCollateral, uint256 amountOutCollateral) = slot1 .priceOracle .fastCheck( balanceInBefore - balanceInAfter, tokenIn, balanceOutAfter - balanceOutBefore, tokenOut ); // F:[CM-34] // Disables tokenIn if the entire balance was spent by the operation if (balanceInAfter <= 1) _disableToken(creditAccount, tokenIn); // F:[CM-33] // Collateral values must be compared weighted by respective LTs, // as otherwise a high-LT (e.g., underlying) token can be swapped // to an equivalent amount of a low-LT asset. Without weighting, this would // pass the check (since inbound and outbound values are equal), // while the health factor of the account would be reduced severely. amountOutCollateral *= liquidationThresholds(tokenOut); // F:[CM-34] amountInCollateral *= liquidationThresholds(tokenIn); // F:[CM-34] // If the value of inbound collateral is larger than inbound collateral // a health check does not need to be performed; // However, the number of enabled tokens needs to be checked against the limit, // as a new collateral token was potentially enabled if (amountOutCollateral >= amountInCollateral) { _checkAndOptimizeEnabledTokens(creditAccount); // F:[CM-35] return; // F:[CM-34] } // The new cumulative drop in value is computed in RAY format, for precision uint256 cumulativeDropRAY = RAY - ((amountOutCollateral * RAY) / amountInCollateral) + cumulativeDropAtFastCheckRAY[creditAccount]; // F:[CM-36] // If then new cumulative drop is less than feeLiquidation, the check is successful, // otherwise, a full collateral check is required if ( cumulativeDropRAY <= (slot1.feeLiquidation * RAY) / PERCENTAGE_FACTOR ) { cumulativeDropAtFastCheckRAY[creditAccount] = cumulativeDropRAY; // F:[CM-36] _checkAndOptimizeEnabledTokens(creditAccount); // F:[CM-37] return; } // If a fast collateral check didn't pass, a full check is performed and // the cumulative drop is reset back to 0 (1 for gas-efficiency). _fullCollateralCheck(creditAccount); // F:[CM-34,36] cumulativeDropAtFastCheckRAY[creditAccount] = 1; // F:[CM-36] } /// @dev Performs a full health check on an account, summing up /// value of all enabled collateral tokens /// @param creditAccount Address of the Credit Account to check function fullCollateralCheck(address creditAccount) external override adaptersOrCreditFacadeOnly // F:[CM-3] nonReentrant { _fullCollateralCheck(creditAccount); } /// @dev IMPLEMENTATION: fullCollateralCheck /// @param creditAccount Address of the Credit Account to check function _fullCollateralCheck(address creditAccount) internal { IPriceOracleV2 _priceOracle = slot1.priceOracle; uint256 enabledTokenMask = enabledTokensMap[creditAccount]; uint256 borrowAmountPlusInterestRateUSD; uint256 len; unchecked { // The total weighted value of a Credit Account has to be compared // with the entire debt sum, including interest and fees ( , , uint256 borrowedAmountWithInterestAndFees ) = calcCreditAccountAccruedInterest(creditAccount); borrowAmountPlusInterestRateUSD = _priceOracle.convertToUSD( borrowedAmountWithInterestAndFees * PERCENTAGE_FACTOR, underlying ); len = _getMaxIndex(enabledTokenMask) + 1; } uint256 tokenMask; uint256 twvUSD; bool atLeastOneTokenWasDisabled; for (uint256 i; i < len; ) { // The order of evaluation is adjusted to optimize for // farming, as it is the largest expected use case // Since farming positions are at the end of the collateral token list // the loop moves through token masks in descending order (except underlying, which is // checked first) unchecked { tokenMask = i == 0 ? 1 : 1 << (len - i); } // CASE enabledTokenMask & tokenMask == 0 F:[CM-38] if (enabledTokenMask & tokenMask != 0) { ( address token, uint16 liquidationThreshold ) = collateralTokensByMask(tokenMask); uint256 balance = IERC20(token).balanceOf(creditAccount); // Collateral calculations are only done if there is a non-zero balance if (balance > 1) { twvUSD += _priceOracle.convertToUSD(balance, token) * liquidationThreshold; // Full collateral check evaluates a Credit Account's health factor lazily; // Once the TWV computed thus far exceeds the debt, the check is considered // successful, and the function returns without evaluating any further collateral if (twvUSD >= borrowAmountPlusInterestRateUSD) { // Since a full collateral check is usually called after an operation or MultiCall // involving many tokens, potentially many new tokens can be enabled. As such, // the function needs to check whether the enabled token limit is violated, // and disable any unused tokens, if so. Note that the number of enabled tokens // is calculated from the updated enabledTokenMask, so some of the unused tokens may have already // been disabled uint256 totalTokensEnabled = _calcEnabledTokens( enabledTokenMask ); if (totalTokensEnabled > maxAllowedEnabledTokenLength) { unchecked { _optimizeEnabledTokens( creditAccount, enabledTokenMask, totalTokensEnabled, // At this stage in the function, at least underlying // must have been processed, so it can be skipped 1, // Since the function disables all unused tokens it finds // and iterates in descending order, // _optimizeEnabledTokens only needs to check up to len - i len - i ); // F:[CM-41] where i=0 } } else { // Saves enabledTokensMask if at least one token was disabled if (atLeastOneTokenWasDisabled) { enabledTokensMap[ creditAccount ] = enabledTokenMask; // F:[CM-39] } } return; // F:[CM-40] } // Zero-balance tokens are disabled; this is done by flipping the // bit in enabledTokenMask, which is then written into storage at the // very end, to avoid redundant storage writes } else { enabledTokenMask ^= tokenMask; // F:[CM-39] atLeastOneTokenWasDisabled = true; // F:[CM-39] } } unchecked { ++i; } } revert NotEnoughCollateralException(); } /// @dev Checks that the number of enabled tokens on a Credit Account /// does not violate the maximal enabled token limit and tries /// to disable unused tokens if it does /// @param creditAccount Account to check enabled tokens for function checkAndOptimizeEnabledTokens(address creditAccount) external override adaptersOrCreditFacadeOnly // F: [CM-2] { _checkAndOptimizeEnabledTokens(creditAccount); } /// @dev IMPLEMENTATION: checkAndOptimizeEnabledTokens function _checkAndOptimizeEnabledTokens(address creditAccount) internal { uint256 enabledTokenMask = enabledTokensMap[creditAccount]; uint256 totalTokensEnabled = _calcEnabledTokens(enabledTokenMask); if (totalTokensEnabled > maxAllowedEnabledTokenLength) { uint256 maxIndex = _getMaxIndex(enabledTokenMask) + 1; _optimizeEnabledTokens( creditAccount, enabledTokenMask, totalTokensEnabled, 0, maxIndex ); } } /// @dev Calculates the number of enabled tokens, based on the /// provided token mask /// @param enabledTokenMask Bit mask encoding a set of enabled tokens function _calcEnabledTokens(uint256 enabledTokenMask) internal pure returns (uint256 totalTokensEnabled) { // Bit mask is a number encoding enabled tokens as 1's; // Therefore, to count the number of enabled tokens, we simply // need to keep shifting the mask by one bit and checking if the rightmost bit is 1, // until the whole mask is 0; // Since bit shifting is overflow-safe and the loop has at most 256 steps, // the whole function can be marked as unsafe to optimize gas unchecked { while (enabledTokenMask > 0) { totalTokensEnabled += enabledTokenMask & 1; enabledTokenMask = enabledTokenMask >> 1; } } } /// @dev Searches for tokens with zero balance among enabled tokens /// on a Credit Account and disables them, until the total number /// of enabled tokens is at maxAllowedEnabledTokenLength /// @param creditAccount The Credit Account to optimize /// @param enabledTokenMask Mask encoding the set of currentl enabled tokens /// @param totalTokensEnabled The current number of enabled tokens /// @param minIndex Inclusive lower bound of search range /// @param maxIndex Non-inclusive upper bound of search range function _optimizeEnabledTokens( address creditAccount, uint256 enabledTokenMask, uint256 totalTokensEnabled, uint256 minIndex, uint256 maxIndex ) internal { // The whole block can be marked unchecked, since: // - maxIndex < 256 at all times (i.e., tokenMask < 2 ** 256); // - totalTokensEnabled does not go lower than maxAllowedEnabledTokenLength // (the function returns at that point) unchecked { for (uint256 i = minIndex; i < maxIndex; ) { uint256 tokenMask = 1 << i; if (enabledTokenMask & tokenMask != 0) { (address token, ) = collateralTokensByMask(tokenMask); uint256 balance = IERC20(token).balanceOf(creditAccount); if (balance <= 1) { enabledTokenMask ^= tokenMask; --totalTokensEnabled; if ( totalTokensEnabled <= maxAllowedEnabledTokenLength ) { enabledTokensMap[creditAccount] = enabledTokenMask; return; } } } ++i; } } revert TooManyEnabledTokensException(); } /// @dev Disables a token on a credit account /// @notice Usually called by adapters to disable spent tokens during a multicall, /// but can also be called separately from the Credit Facade to remove /// unwanted tokens function disableToken(address creditAccount, address token) external override whenNotPausedOrEmergency // F:[CM-5] adaptersOrCreditFacadeOnly // F:[CM-3] nonReentrant returns (bool) { return _disableToken(creditAccount, token); } /// @dev IMPLEMENTATION: disableToken function _disableToken(address creditAccount, address token) internal returns (bool wasChanged) { // The enabled token mask encodes all enabled tokens as 1, // therefore the corresponding bit is set to 0 to disable it uint256 tokenMask = tokenMasksMap(token); if (enabledTokensMap[creditAccount] & tokenMask != 0) { enabledTokensMap[creditAccount] &= ~tokenMask; // F:[CM-46] wasChanged = true; } } /// @dev Checks if the contract is paused; if true, checks that the caller is emergency liquidator /// and temporarily enables a special emergencyLiquidator mode to allow liquidation. /// @notice Some whenNotPausedOrEmergency functions in CreditManager need to be executable to perform /// multicalls during liquidations. emergencyLiquidation mode is enabled temporarily /// (for the span of a single multicall) to override /// the paused state and allow a special privileged role to liquidate unhealthy positions, if the /// contracts are paused due to an emergency. /// @notice To save gas, emergency liquidation setting is skipped when the CM is not paused. /// /// /// @param caller Address of CreditFacade caller /// @param state True to enable and false to disable emergencyLiqudation mde /// @return True if contract paused otherwise false. If the contract is not paused, there is no need /// to call this function to disable the emergencyLiquidation mode. function checkEmergencyPausable(address caller, bool state) external creditFacadeOnly // F:[CM-2] returns (bool) { bool pausable = paused(); // F: [CM-67] if (pausable && canLiquidateWhilePaused[caller]) { emergencyLiquidation = state; // F: [CM-67] } return pausable; // F: [CM-67] } // // INTERNAL HELPERS // /// @dev Transfers all enabled assets from a Credit Account to the "to" address /// @param creditAccount Credit Account to transfer assets from /// @param to Recipient address /// @param convertWETH Whether WETH must be converted to ETH before sending /// @param enabledTokensMask A bit mask encoding enabled tokens. All of the tokens included /// in the mask will be transferred. If any tokens need to be skipped, they must be /// excluded from the mask beforehand. function _transferAssetsTo( address creditAccount, address to, bool convertWETH, uint256 enabledTokensMask ) internal { // Since underlying should have been transferred to "to" before this function is called // (if there is a surplus), its tokenMask of 1 is skipped uint256 tokenMask = 2; // Since enabledTokensMask encodes all enabled tokens as 1, // tokenMask > enabledTokensMask is equivalent to the last 1 bit being passed // The loop can be ended at this point while (tokenMask <= enabledTokensMask) { // enabledTokensMask & tokenMask == tokenMask when the token is enabled, // and 0 otherwise if (enabledTokensMask & tokenMask != 0) { (address token, ) = collateralTokensByMask(tokenMask); // F:[CM-44] uint256 amount = IERC20(token).balanceOf(creditAccount); // F:[CM-44] if (amount > 1) { // 1 is subtracted from amount to leave a non-zero value // in the balance mapping, optimizing future writes // Since the amount is checked to be more than 1, // the block can be marked as unchecked // F:[CM-44] unchecked { _safeTokenTransfer( creditAccount, token, to, amount - 1, convertWETH ); // F:[CM-44] } } } // The loop iterates by moving 1 bit to the left, // which corresponds to moving on to the next token tokenMask = tokenMask << 1; // F:[CM-44] } } /// @dev Requests the Credit Account to transfer a token to another address /// Able to unwrap WETH before sending, if requested /// @param creditAccount Address of the sender Credit Account /// @param token Address of the token /// @param to Recipient address /// @param amount Amount to transfer function _safeTokenTransfer( address creditAccount, address token, address to, uint256 amount, bool convertToETH ) internal { if (convertToETH && token == wethAddress) { ICreditAccount(creditAccount).safeTransfer( token, wethGateway, amount ); // F:[CM-45] IWETHGateway(wethGateway).unwrapWETH(to, amount); // F:[CM-45] } else { ICreditAccount(creditAccount).safeTransfer(token, to, amount); // F:[CM-45] } } /// @dev Sets the Credit Account owner while checking that they do not /// have an account already /// @param borrower The new owner of the Credit Account /// @param creditAccount The Credit Account address function _safeCreditAccountSet(address borrower, address creditAccount) internal { if (borrower == address(0) || creditAccounts[borrower] != address(0)) revert ZeroAddressOrUserAlreadyHasAccountException(); // F:[CM-7] creditAccounts[borrower] = creditAccount; // F:[CM-7] } // // GETTERS // /// @dev Computes amounts that must be sent to various addresses before closing an account /// @param totalValue Credit Accounts total value in underlying /// @param closureActionType Type of account closure /// * CLOSE_ACCOUNT: The account is healthy and is closed normally /// * LIQUIDATE_ACCOUNT: The account is unhealthy and is being liquidated to avoid bad debt /// * LIQUIDATE_EXPIRED_ACCOUNT: The account has expired and is being liquidated (lowered liquidation premium) /// * LIQUIDATE_PAUSED: The account is liquidated while the system is paused due to emergency (no liquidation premium) /// @param borrowedAmount Credit Account's debt principal /// @param borrowedAmountWithInterest Credit Account's debt principal + interest /// @return amountToPool Amount of underlying to be sent to the pool /// @return remainingFunds Amount of underlying to be sent to the borrower (only applicable to liquidations) /// @return profit Protocol's profit from fees (if any) /// @return loss Protocol's loss from bad debt (if any) function calcClosePayments( uint256 totalValue, ClosureAction closureActionType, uint256 borrowedAmount, uint256 borrowedAmountWithInterest ) public view override returns ( uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss ) { // The amount to be paid to pool is computed with fees included // The pool will compute the amount of Diesel tokens to treasury // based on profit amountToPool = borrowedAmountWithInterest + ((borrowedAmountWithInterest - borrowedAmount) * slot1.feeInterest) / PERCENTAGE_FACTOR; // F:[CM-43] if ( closureActionType == ClosureAction.LIQUIDATE_ACCOUNT || closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT || closureActionType == ClosureAction.LIQUIDATE_PAUSED ) { // LIQUIDATION CASE uint256 totalFunds; // During liquidation, totalValue of the account is discounted // by (1 - liquidationPremium). This means that totalValue * liquidationPremium // is removed from all calculations and can be claimed by the liquidator at the end of transaction // The liquidation premium depends on liquidation type: // * For normal unhealthy account liquidations, usual premium applies // * For expiry liquidations, the premium is typically reduced, // since the account does not risk bad debt, so the liquidation // is not as urgent // * For emergency (paused) liquidations, there is not premium. // This is done in order to preserve fairness, as emergency liquidator // is a priviledged role. Any compensation to the emergency liquidator must // be coordinated with the DAO out of band. if (closureActionType == ClosureAction.LIQUIDATE_ACCOUNT) { // UNHEALTHY ACCOUNT CASE totalFunds = (totalValue * slot1.liquidationDiscount) / PERCENTAGE_FACTOR; // F:[CM-43] amountToPool += (totalValue * slot1.feeLiquidation) / PERCENTAGE_FACTOR; // F:[CM-43] } else if ( closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT ) { // EXPIRED ACCOUNT CASE totalFunds = (totalValue * slot1.liquidationDiscountExpired) / PERCENTAGE_FACTOR; // F:[CM-43] amountToPool += (totalValue * slot1.feeLiquidationExpired) / PERCENTAGE_FACTOR; // F:[CM-43] } else { // PAUSED CASE totalFunds = totalValue; // F: [CM-43] amountToPool += (totalValue * slot1.feeLiquidation) / PERCENTAGE_FACTOR; // F:[CM-43] } // If there are any funds left after all respective payments (this // includes the liquidation premium, since totalFunds is already // discounted from totalValue), they are recorded to remainingFunds // and will later be sent to the borrower. // If totalFunds is not sufficient to cover the entire payment to pool, // the Credit Manager will repay what it can. When totalFunds >= debt + interest, // this simply means that part of protocol fees will be waived (profit is reduced). Otherwise, // there is bad debt (loss > 0). // Since values are compared to each other before subtracting, // this can be marked as unchecked to optimize gas unchecked { if (totalFunds > amountToPool) { remainingFunds = totalFunds - amountToPool - 1; // F:[CM-43] } else { amountToPool = totalFunds; // F:[CM-43] } if (totalFunds >= borrowedAmountWithInterest) { profit = amountToPool - borrowedAmountWithInterest; // F:[CM-43] } else { loss = borrowedAmountWithInterest - amountToPool; // F:[CM-43] } } } else { // CLOSURE CASE // During closure, it is assumed that the user has enough to cover // the principal + interest + fees. closeCreditAccount, thus, will // attempt to charge them the entire amount. // Since in this case amountToPool + borrowedAmountWithInterest + fee, // this block can be marked as unchecked unchecked { profit = amountToPool - borrowedAmountWithInterest; // F:[CM-43] } } } /// @dev Returns the collateral token at requested index and its liquidation threshold /// @param id The index of token to return function collateralTokens(uint256 id) public view returns (address token, uint16 liquidationThreshold) { // Collateral tokens are stored under their masks rather than // indicies, so this is simply a convenience function that wraps // the getter by mask return collateralTokensByMask(1 << id); } /// @dev Returns the collateral token with requested mask and its liquidationThreshold /// @param tokenMask Token mask corresponding to the token function collateralTokensByMask(uint256 tokenMask) public view override returns (address token, uint16 liquidationThreshold) { // The underlying is a special case and its mask is always 1 if (tokenMask == 1) { token = underlying; // F:[CM-47] liquidationThreshold = slot1.ltUnderlying; } else { // The address and LT of a collateral token are compressed into a single uint256 // The first 160 bits of the number is the address, and any bits after that are interpreted as LT uint256 collateralTokenCompressed = collateralTokensCompressed[ tokenMask ]; // F:[CM-47] // Unsafe downcasting is justified, since the right 160 bits of collateralTokenCompressed // always stores the uint160 encoded address and the extra bits need to be cut token = address(uint160(collateralTokenCompressed)); // F:[CM-47] liquidationThreshold = (collateralTokenCompressed >> ADDR_BIT_SIZE) .toUint16(); // F:[CM-47] } } /// @dev Returns the address of a borrower's Credit Account, or reverts if there is none. /// @param borrower Borrower's address function getCreditAccountOrRevert(address borrower) public view override returns (address result) { result = creditAccounts[borrower]; // F:[CM-48] if (result == address(0)) revert HasNoOpenedAccountException(); // F:[CM-48] } /// @dev Calculates the debt accrued by a Credit Account /// @param creditAccount Address of the Credit Account /// @return borrowedAmount The debt principal /// @return borrowedAmountWithInterest The debt principal + accrued interest /// @return borrowedAmountWithInterestAndFees The debt principal + accrued interest and protocol fees function calcCreditAccountAccruedInterest(address creditAccount) public view override returns ( uint256 borrowedAmount, uint256 borrowedAmountWithInterest, uint256 borrowedAmountWithInterestAndFees ) { uint256 cumulativeIndexAtOpen_RAY; uint256 cumulativeIndexNow_RAY; ( borrowedAmount, cumulativeIndexAtOpen_RAY, cumulativeIndexNow_RAY ) = _getCreditAccountParameters(creditAccount); // F:[CM-49] // Interest is never stored and is always computed dynamically // as the difference between the current cumulative index of the pool // and the cumulative index recorded in the Credit Account borrowedAmountWithInterest = (borrowedAmount * cumulativeIndexNow_RAY) / cumulativeIndexAtOpen_RAY; // F:[CM-49] // Fees are computed as a percentage of interest borrowedAmountWithInterestAndFees = borrowedAmountWithInterest + ((borrowedAmountWithInterest - borrowedAmount) * slot1.feeInterest) / PERCENTAGE_FACTOR; // F: [CM-49] } /// @dev Returns the parameters of the Credit Account required to calculate debt /// @param creditAccount Address of the Credit Account /// @return borrowedAmount Debt principal amount /// @return cumulativeIndexAtOpen_RAY The cumulative index value used to calculate /// interest in conjunction with current pool index. Not necessarily the index /// value at the time of account opening, since it can be updated by manageDebt. /// @return cumulativeIndexNow_RAY Current cumulative index of the pool function _getCreditAccountParameters(address creditAccount) internal view returns ( uint256 borrowedAmount, uint256 cumulativeIndexAtOpen_RAY, uint256 cumulativeIndexNow_RAY ) { borrowedAmount = ICreditAccount(creditAccount).borrowedAmount(); // F:[CM-49,50] cumulativeIndexAtOpen_RAY = ICreditAccount(creditAccount) .cumulativeIndexAtOpen(); // F:[CM-49,50] cumulativeIndexNow_RAY = IPoolService(pool).calcLinearCumulative_RAY(); // F:[CM-49,50] } /// @dev Returns the liquidation threshold for the provided token /// @param token Token to retrieve the LT for function liquidationThresholds(address token) public view override returns (uint16 lt) { // Underlying is a special case and its LT is stored separately if (token == underlying) return slot1.ltUnderlying; // F:[CM-47] uint256 tokenMask = tokenMasksMap(token); if (tokenMask == 0) revert TokenNotAllowedException(); (, lt) = collateralTokensByMask(tokenMask); // F:[CM-47] } /// @dev Returns the mask for the provided token /// @param token Token to returns the mask for function tokenMasksMap(address token) public view override returns (uint256 mask) { mask = (token == underlying) ? 1 : tokenMasksMapInternal[token]; } /// @dev Returns the largest token index out of enabled tokens, based on a mask /// @param mask Bit mask encoding enabled tokens /// @return index Largest index out of the set of enabled tokens function _getMaxIndex(uint256 mask) internal pure returns (uint256 index) { if (mask == 1) return 0; // Performs a binary search within the range of all token indices // If right-shifting a mask by n turns it into 1, then n is the largest index uint256 high = 256; uint256 low = 1; while (true) { index = (high + low) >> 1; uint256 testMask = 1 << index; if (testMask & mask != 0 && (mask >> index == 1)) break; if (testMask >= mask) { high = index; } else { low = index; } } } /// @dev Returns the fee parameters of the Credit Manager /// @return feeInterest Percentage of interest taken by the protocol as profit /// @return feeLiquidation Percentage of account value taken by the protocol as profit /// during unhealthy account liquidations /// @return liquidationDiscount Multiplier that reduces the effective totalValue during unhealthy account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremium) /// @return feeLiquidationExpired Percentage of account value taken by the protocol as profit /// during expired account liquidations /// @return liquidationDiscountExpired Multiplier that reduces the effective totalValue during expired account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremiumExpired) function fees() external view override returns ( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationDiscount, uint16 feeLiquidationExpired, uint16 liquidationDiscountExpired ) { feeInterest = slot1.feeInterest; // F:[CM-51] feeLiquidation = slot1.feeLiquidation; // F:[CM-51] liquidationDiscount = slot1.liquidationDiscount; // F:[CM-51] feeLiquidationExpired = slot1.feeLiquidationExpired; // F:[CM-51] liquidationDiscountExpired = slot1.liquidationDiscountExpired; // F:[CM-51] } /// @dev Returns the price oracle used to evaluate collateral tokens function priceOracle() external view override returns (IPriceOracleV2) { return slot1.priceOracle; } // // CONFIGURATION // // The following function change vital Credit Manager parameters // and can only be called by the Credit Configurator // /// @dev Adds a token to the list of collateral tokens /// @param token Address of the token to add function addToken(address token) external creditConfiguratorOnly // F:[CM-4] { _addToken(token); // F:[CM-52] } /// @dev IMPLEMENTATION: addToken /// @param token Address of the token to add function _addToken(address token) internal { // Checks that the token is not already known (has an associated token mask) if (tokenMasksMapInternal[token] > 0) revert TokenAlreadyAddedException(); // F:[CM-52] // Checks that there aren't too many tokens // Since token masks are 256 bit numbers with each bit corresponding to 1 token, // only at most 256 are supported if (collateralTokensCount >= 256) revert TooManyTokensException(); // F:[CM-52] // The tokenMask of a token is a bit mask with 1 at position corresponding to its index // (i.e. 2 ** index or 1 << index) uint256 tokenMask = 1 << collateralTokensCount; tokenMasksMapInternal[token] = tokenMask; // F:[CM-53] collateralTokensCompressed[tokenMask] = uint256(uint160(token)); // F:[CM-47] collateralTokensCount++; // F:[CM-47] } /// @dev Sets fees and premiums /// @param _feeInterest Percentage of interest taken by the protocol as profit /// @param _feeLiquidation Percentage of account value taken by the protocol as profit /// during unhealthy account liquidations /// @param _liquidationDiscount Multiplier that reduces the effective totalValue during unhealthy account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremium) /// @param _feeLiquidationExpired Percentage of account value taken by the protocol as profit /// during expired account liquidations /// @param _liquidationDiscountExpired Multiplier that reduces the effective totalValue during expired account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremiumExpired) function setParams( uint16 _feeInterest, uint16 _feeLiquidation, uint16 _liquidationDiscount, uint16 _feeLiquidationExpired, uint16 _liquidationDiscountExpired ) external creditConfiguratorOnly // F:[CM-4] { slot1.feeInterest = _feeInterest; // F:[CM-51] slot1.feeLiquidation = _feeLiquidation; // F:[CM-51] slot1.liquidationDiscount = _liquidationDiscount; // F:[CM-51] slot1.feeLiquidationExpired = _feeLiquidationExpired; // F:[CM-51] slot1.liquidationDiscountExpired = _liquidationDiscountExpired; // F:[CM-51] } // // CONFIGURATION // /// @dev Sets the liquidation threshold for a collateral token /// @notice Liquidation thresholds are weights used to compute /// TWV with. They denote the risk of the token, with /// more volatile and unpredictable tokens having lower LTs. /// @param token The collateral token to set the LT for /// @param liquidationThreshold The new LT function setLiquidationThreshold(address token, uint16 liquidationThreshold) external creditConfiguratorOnly // F:[CM-4] { // Underlying is a special case and its LT is stored in Slot1, // to be accessed frequently if (token == underlying) { // F:[CM-47] slot1.ltUnderlying = liquidationThreshold; // F:[CM-47] } else { uint256 tokenMask = tokenMasksMap(token); // F:[CM-47, 54] if (tokenMask == 0) revert TokenNotAllowedException(); // Token address and liquidation threshold are encoded into a single uint256 collateralTokensCompressed[tokenMask] = (collateralTokensCompressed[tokenMask] & type(uint160).max) | (uint256(liquidationThreshold) << 160); // F:[CM-47] } } /// @dev Sets the forbidden token mask /// @param _forbidMask The new bit mask encoding the tokens that are forbidden /// @notice Forbidden tokens are counted as collateral during health checks, however, they cannot be enabled /// or received as a result of adapter operation anymore. This means that a token can never be /// acquired through adapter operations after being forbidden. Accounts that have enabled forbidden tokens /// also can't borrow any additional funds until they disable those tokens. function setForbidMask(uint256 _forbidMask) external creditConfiguratorOnly // F:[CM-4] { forbiddenTokenMask = _forbidMask; // F:[CM-55] } /// @dev Sets the maximal number of enabled tokens on a single Credit Account. /// @param newMaxEnabledTokens The new enabled token limit. function setMaxEnabledTokens(uint8 newMaxEnabledTokens) external creditConfiguratorOnly // F: [CM-4] { maxAllowedEnabledTokenLength = newMaxEnabledTokens; // F: [CC-37] } /// @dev Sets the link between an adapter and its corresponding targetContract /// @param adapter Address of the adapter to be used to access the target contract /// @param targetContract A 3rd-party contract for which the adapter is set /// @notice The function can be called with (adapter, address(0)) and (address(0), targetContract) /// to disallow a particular target or adapter, since this would set values in respective /// mappings to address(0). function changeContractAllowance(address adapter, address targetContract) external creditConfiguratorOnly { if (adapter != address(0)) { adapterToContract[adapter] = targetContract; // F:[CM-56] } if (targetContract != address(0)) { contractToAdapter[targetContract] = adapter; // F:[CM-56] } // The universal adapter can potentially target multiple contracts, // so it is set using a special vanity address if (targetContract == UNIVERSAL_CONTRACT) { universalAdapter = adapter; // F:[CM-56] } } /// @dev Sets the Credit Facade /// @param _creditFacade Address of the new Credit Facade function upgradeCreditFacade(address _creditFacade) external creditConfiguratorOnly // F:[CM-4] { creditFacade = _creditFacade; } /// @dev Sets the Price Oracle /// @param _priceOracle Address of the new Price Oracle function upgradePriceOracle(address _priceOracle) external creditConfiguratorOnly // F:[CM-4] { slot1.priceOracle = IPriceOracleV2(_priceOracle); } /// @dev Adds an address to the list of emergency liquidators /// @param liquidator Address to add to the list function addEmergencyLiquidator(address liquidator) external creditConfiguratorOnly // F:[CM-4] { canLiquidateWhilePaused[liquidator] = true; } /// @dev Removes an address from the list of emergency liquidators /// @param liquidator Address to remove from the list function removeEmergencyLiquidator(address liquidator) external creditConfiguratorOnly // F: [CM-4] { canLiquidateWhilePaused[liquidator] = false; } /// @dev Sets a new Credit Configurator /// @param _creditConfigurator Address of the new Credit Configurator function setConfigurator(address _creditConfigurator) external creditConfiguratorOnly // F:[CM-4] { creditConfigurator = _creditConfigurator; // F:[CM-58] emit NewConfigurator(_creditConfigurator); // F:[CM-58] } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^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; 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"); (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"); (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"); (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"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IVersion } from "./IVersion.sol"; interface IAccountFactoryEvents { /// @dev Emits when the account mining contract is changed /// @notice Not applicable to factories deployed after V2 event AccountMinerChanged(address indexed miner); /// @dev Emits when a new Credit Account is created event NewCreditAccount(address indexed account); /// @dev Emits when a Credit Manager takes an account from the factory event InitializeCreditAccount( address indexed account, address indexed creditManager ); /// @dev Emits when a Credit Manager returns an account to the factory event ReturnCreditAccount(address indexed account); /// @dev Emits when a Credit Account is taking out of the factory forever /// by root event TakeForever(address indexed creditAccount, address indexed to); } interface IAccountFactoryGetters { /// @dev Gets the next available credit account after the passed one, or address(0) if the passed account is the tail /// @param creditAccount Credit Account previous to the one to retrieve function getNext(address creditAccount) external view returns (address); /// @dev Head of CA linked list function head() external view returns (address); /// @dev Tail of CA linked list function tail() external view returns (address); /// @dev Returns the number of unused credit accounts in stock function countCreditAccountsInStock() external view returns (uint256); /// @dev Returns the credit account address under the passed id /// @param id The index of the requested CA function creditAccounts(uint256 id) external view returns (address); /// @dev Returns the number of deployed credit accounts function countCreditAccounts() external view returns (uint256); } interface IAccountFactory is IAccountFactoryGetters, IAccountFactoryEvents, IVersion { /// @dev Provides a new credit account to a Credit Manager function takeCreditAccount( uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external returns (address); /// @dev Retrieves the Credit Account from the Credit Manager and adds it to the stock /// @param usedAccount Address of returned credit account function returnCreditAccount(address usedAccount) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol) pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such 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. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IVersion } from "./IVersion.sol"; /// @title Credit Account /// @notice Implements generic credit account logic: /// - Holds collateral assets /// - Stores general parameters: borrowed amount, cumulative index at open and block when it was initialized /// - Transfers assets /// - Executes financial orders by calling connected protocols on its behalf /// /// More: https://dev.gearbox.fi/developers/credit/credit_account interface ICrediAccountExceptions { /// @dev throws if the caller is not the connected Credit Manager error CallerNotCreditManagerException(); /// @dev throws if the caller is not the factory error CallerNotFactoryException(); } interface ICreditAccount is ICrediAccountExceptions, IVersion { /// @dev Called on new Credit Account creation. /// @notice Initialize is used instead of constructor, since the contract is cloned. function initialize() external; /// @dev Connects this credit account to a Credit Manager. Restricted to the account factory (owner) only. /// @param _creditManager Credit manager address /// @param _borrowedAmount The amount borrowed at Credit Account opening /// @param _cumulativeIndexAtOpen The interest index at Credit Account opening function connectTo( address _creditManager, uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external; /// @dev Updates borrowed amount and cumulative index. Restricted to the currently connected Credit Manager. /// @param _borrowedAmount The amount currently lent to the Credit Account /// @param _cumulativeIndexAtOpen New cumulative index to calculate interest from function updateParameters( uint256 _borrowedAmount, uint256 _cumulativeIndexAtOpen ) external; /// @dev Removes allowance for a token to a 3rd-party contract. Restricted to factory only. /// @param token ERC20 token to remove allowance for. /// @param targetContract Target contract to revoke allowance to. function cancelAllowance(address token, address targetContract) external; /// @dev Transfers tokens from the credit account to a provided address. Restricted to the current Credit Manager only. /// @param token Token to be transferred from the Credit Account. /// @param to Address of the recipient. /// @param amount Amount to be transferred. function safeTransfer( address token, address to, uint256 amount ) external; /// @dev Returns the principal amount borrowed from the pool function borrowedAmount() external view returns (uint256); /// @dev Returns the cumulative interest index since the last Credit Account's debt update function cumulativeIndexAtOpen() external view returns (uint256); /// @dev Returns the block at which the contract was last taken from the factory function since() external view returns (uint256); /// @dev Returns the address of the currently connected Credit Manager function creditManager() external view returns (address); /// @dev Address of the Credit Account factory function factory() external view returns (address); /// @dev Executes a call to a 3rd party contract with provided data. Restricted to the current Credit Manager only. /// @param destination Contract address to be called. /// @param data Data to call the contract with. function execute(address destination, bytes memory data) external returns (bytes memory); }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IVersion } from "./IVersion.sol"; interface IPriceOracleV2Events { /// @dev Emits when a new price feed is added event NewPriceFeed(address indexed token, address indexed priceFeed); } interface IPriceOracleV2Exceptions { /// @dev Thrown if a price feed returns 0 error ZeroPriceException(); /// @dev Thrown if the last recorded result was not updated in the last round error ChainPriceStaleException(); /// @dev Thrown on attempting to get a result for a token that does not have a price feed error PriceOracleNotExistsException(); } /// @title Price oracle interface interface IPriceOracleV2 is IPriceOracleV2Events, IPriceOracleV2Exceptions, IVersion { /// @dev Converts a quantity of an asset to USD (decimals = 8). /// @param amount Amount to convert /// @param token Address of the token to be converted function convertToUSD(uint256 amount, address token) external view returns (uint256); /// @dev Converts a quantity of USD (decimals = 8) to an equivalent amount of an asset /// @param amount Amount to convert /// @param token Address of the token converted to function convertFromUSD(uint256 amount, address token) external view returns (uint256); /// @dev Converts one asset into another /// /// @param amount Amount to convert /// @param tokenFrom Address of the token to convert from /// @param tokenTo Address of the token to convert to function convert( uint256 amount, address tokenFrom, address tokenTo ) external view returns (uint256); /// @dev Returns collateral values for two tokens, required for a fast check /// @param amountFrom Amount of the outbound token /// @param tokenFrom Address of the outbound token /// @param amountTo Amount of the inbound token /// @param tokenTo Address of the inbound token /// @return collateralFrom Value of the outbound token amount in USD /// @return collateralTo Value of the inbound token amount in USD function fastCheck( uint256 amountFrom, address tokenFrom, uint256 amountTo, address tokenTo ) external view returns (uint256 collateralFrom, uint256 collateralTo); /// @dev Returns token's price in USD (8 decimals) /// @param token The token to compute the price for function getPrice(address token) external view returns (uint256); /// @dev Returns the price feed address for the passed token /// @param token Token to get the price feed for function priceFeeds(address token) external view returns (address priceFeed); /// @dev Returns the price feed for the passed token, /// with additional parameters /// @param token Token to get the price feed for function priceFeedsWithFlags(address token) external view returns ( address priceFeed, bool skipCheck, uint256 decimals ); } interface IPriceOracleV2Ext is IPriceOracleV2 { /// @dev Sets a price feed if it doesn't exist, or updates an existing one /// @param token Address of the token to set the price feed for /// @param priceFeed Address of a USD price feed adhering to Chainlink's interface function addPriceFeed(address token, address priceFeed) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IPriceOracleV2 } from "./IPriceOracle.sol"; import { IVersion } from "./IVersion.sol"; enum ClosureAction { CLOSE_ACCOUNT, LIQUIDATE_ACCOUNT, LIQUIDATE_EXPIRED_ACCOUNT, LIQUIDATE_PAUSED } interface ICreditManagerV2Events { /// @dev Emits when a call to an external contract is made through the Credit Manager event ExecuteOrder(address indexed borrower, address indexed target); /// @dev Emits when a configurator is upgraded event NewConfigurator(address indexed newConfigurator); } interface ICreditManagerV2Exceptions { /// @dev Thrown if an access-restricted function is called by an address that is not /// the connected Credit Facade, or an allowed adapter error AdaptersOrCreditFacadeOnlyException(); /// @dev Thrown if an access-restricted function is called by an address that is not /// the connected Credit Facade error CreditFacadeOnlyException(); /// @dev Thrown if an access-restricted function is called by an address that is not /// the connected Credit Configurator error CreditConfiguratorOnlyException(); /// @dev Thrown on attempting to open a Credit Account for or transfer a Credit Account /// to the zero address or an address that already owns a Credit Account error ZeroAddressOrUserAlreadyHasAccountException(); /// @dev Thrown on attempting to execute an order to an address that is not an allowed /// target contract error TargetContractNotAllowedException(); /// @dev Thrown on failing a full collateral check after an operation error NotEnoughCollateralException(); /// @dev Thrown on attempting to receive a token that is not a collateral token /// or was forbidden error TokenNotAllowedException(); /// @dev Thrown if an attempt to approve a collateral token to a target contract failed error AllowanceFailedException(); /// @dev Thrown on attempting to perform an action for an address that owns no Credit Account error HasNoOpenedAccountException(); /// @dev Thrown on attempting to add a token that is already in a collateral list error TokenAlreadyAddedException(); /// @dev Thrown on configurator attempting to add more than 256 collateral tokens error TooManyTokensException(); /// @dev Thrown if more than the maximal number of tokens were enabled on a Credit Account, /// and there are not enough unused token to disable error TooManyEnabledTokensException(); /// @dev Thrown when a reentrancy into the contract is attempted error ReentrancyLockException(); } /// @notice All Credit Manager functions are access-restricted and can only be called /// by the Credit Facade or allowed adapters. Users are not allowed to /// interact with the Credit Manager directly interface ICreditManagerV2 is ICreditManagerV2Events, ICreditManagerV2Exceptions, IVersion { // // CREDIT ACCOUNT MANAGEMENT // /// @dev Opens credit account and borrows funds from the pool. /// - Takes Credit Account from the factory; /// - Requests the pool to lend underlying to the Credit Account /// /// @param borrowedAmount Amount to be borrowed by the Credit Account /// @param onBehalfOf The owner of the newly opened Credit Account function openCreditAccount(uint256 borrowedAmount, address onBehalfOf) external returns (address); /// @dev Closes a Credit Account - covers both normal closure and liquidation /// - Checks whether the contract is paused, and, if so, if the payer is an emergency liquidator. /// Only emergency liquidators are able to liquidate account while the CM is paused. /// Emergency liquidations do not pay a liquidator premium or liquidation fees. /// - Calculates payments to various recipients on closure: /// + Computes amountToPool, which is the amount to be sent back to the pool. /// This includes the principal, interest and fees, but can't be more than /// total position value /// + Computes remainingFunds during liquidations - these are leftover funds /// after paying the pool and the liquidator, and are sent to the borrower /// + Computes protocol profit, which includes interest and liquidation fees /// + Computes loss if the totalValue is less than borrow amount + interest /// - Checks the underlying token balance: /// + if it is larger than amountToPool, then the pool is paid fully from funds on the Credit Account /// + else tries to transfer the shortfall from the payer - either the borrower during closure, or liquidator during liquidation /// - Send assets to the "to" address, as long as they are not included into skipTokenMask /// - If convertWETH is true, the function converts WETH into ETH before sending /// - Returns the Credit Account back to factory /// /// @param borrower Borrower address /// @param closureActionType Whether the account is closed, liquidated or liquidated due to expiry /// @param totalValue Portfolio value for liqution, 0 for ordinary closure /// @param payer Address which would be charged if credit account has not enough funds to cover amountToPool /// @param to Address to which the leftover funds will be sent /// @param skipTokenMask Tokenmask contains 1 for tokens which needed to be skipped for sending /// @param convertWETH If true converts WETH to ETH function closeCreditAccount( address borrower, ClosureAction closureActionType, uint256 totalValue, address payer, address to, uint256 skipTokenMask, bool convertWETH ) external returns (uint256 remainingFunds); /// @dev Manages debt size for borrower: /// /// - Increase debt: /// + Increases debt by transferring funds from the pool to the credit account /// + Updates the cumulative index to keep interest the same. Since interest /// is always computed dynamically as borrowedAmount * (cumulativeIndexNew / cumulativeIndexOpen - 1), /// cumulativeIndexOpen needs to be updated, as the borrow amount has changed /// /// - Decrease debt: /// + Repays debt partially + all interest and fees accrued thus far /// + Updates cunulativeIndex to cumulativeIndex now /// /// @param creditAccount Address of the Credit Account to change debt for /// @param amount Amount to increase / decrease the principal by /// @param increase True to increase principal, false to decrease /// @return newBorrowedAmount The new debt principal function manageDebt( address creditAccount, uint256 amount, bool increase ) external returns (uint256 newBorrowedAmount); /// @dev Adds collateral to borrower's credit account /// @param payer Address of the account which will be charged to provide additional collateral /// @param creditAccount Address of the Credit Account /// @param token Collateral token to add /// @param amount Amount to add function addCollateral( address payer, address creditAccount, address token, uint256 amount ) external; /// @dev Transfers Credit Account ownership to another address /// @param from Address of previous owner /// @param to Address of new owner function transferAccountOwnership(address from, address to) external; /// @dev Requests the Credit Account to approve a collateral token to another contract. /// @param borrower Borrower's address /// @param targetContract Spender to change allowance for /// @param token Collateral token to approve /// @param amount New allowance amount function approveCreditAccount( address borrower, address targetContract, address token, uint256 amount ) external; /// @dev Requests a Credit Account to make a low-level call with provided data /// This is the intended pathway for state-changing interactions with 3rd-party protocols /// @param borrower Borrower's address /// @param targetContract Contract to be called /// @param data Data to pass with the call function executeOrder( address borrower, address targetContract, bytes memory data ) external returns (bytes memory); // // COLLATERAL VALIDITY AND ACCOUNT HEALTH CHECKS // /// @dev Enables a token on a Credit Account, including it /// into account health and total value calculations /// @param creditAccount Address of a Credit Account to enable the token for /// @param token Address of the token to be enabled function checkAndEnableToken(address creditAccount, address token) external; /// @dev Optimized health check for individual swap-like operations. /// @notice Fast health check assumes that only two tokens (input and output) /// participate in the operation and computes a % change in weighted value between /// inbound and outbound collateral. The cumulative negative change across several /// swaps in sequence cannot be larger than feeLiquidation (a fee that the /// protocol is ready to waive if needed). Since this records a % change /// between just two tokens, the corresponding % change in TWV will always be smaller, /// which makes this check safe. /// More details at https://dev.gearbox.fi/docs/documentation/risk/fast-collateral-check#fast-check-protection /// @param creditAccount Address of the Credit Account /// @param tokenIn Address of the token spent by the swap /// @param tokenOut Address of the token received from the swap /// @param balanceInBefore Balance of tokenIn before the operation /// @param balanceOutBefore Balance of tokenOut before the operation function fastCollateralCheck( address creditAccount, address tokenIn, address tokenOut, uint256 balanceInBefore, uint256 balanceOutBefore ) external; /// @dev Performs a full health check on an account, summing up /// value of all enabled collateral tokens /// @param creditAccount Address of the Credit Account to check function fullCollateralCheck(address creditAccount) external; /// @dev Checks that the number of enabled tokens on a Credit Account /// does not violate the maximal enabled token limit and tries /// to disable unused tokens if it does /// @param creditAccount Account to check enabled tokens for function checkAndOptimizeEnabledTokens(address creditAccount) external; /// @dev Disables a token on a credit account /// @notice Usually called by adapters to disable spent tokens during a multicall, /// but can also be called separately from the Credit Facade to remove /// unwanted tokens /// @return True if token mask was change otherwise False function disableToken(address creditAccount, address token) external returns (bool); // // GETTERS // /// @dev Returns the address of a borrower's Credit Account, or reverts if there is none. /// @param borrower Borrower's address function getCreditAccountOrRevert(address borrower) external view returns (address); /// @dev Computes amounts that must be sent to various addresses before closing an account /// @param totalValue Credit Accounts total value in underlying /// @param closureActionType Type of account closure /// * CLOSE_ACCOUNT: The account is healthy and is closed normally /// * LIQUIDATE_ACCOUNT: The account is unhealthy and is being liquidated to avoid bad debt /// * LIQUIDATE_EXPIRED_ACCOUNT: The account has expired and is being liquidated (lowered liquidation premium) /// * LIQUIDATE_PAUSED: The account is liquidated while the system is paused due to emergency (no liquidation premium) /// @param borrowedAmount Credit Account's debt principal /// @param borrowedAmountWithInterest Credit Account's debt principal + interest /// @return amountToPool Amount of underlying to be sent to the pool /// @return remainingFunds Amount of underlying to be sent to the borrower (only applicable to liquidations) /// @return profit Protocol's profit from fees (if any) /// @return loss Protocol's loss from bad debt (if any) function calcClosePayments( uint256 totalValue, ClosureAction closureActionType, uint256 borrowedAmount, uint256 borrowedAmountWithInterest ) external view returns ( uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss ); /// @dev Calculates the debt accrued by a Credit Account /// @param creditAccount Address of the Credit Account /// @return borrowedAmount The debt principal /// @return borrowedAmountWithInterest The debt principal + accrued interest /// @return borrowedAmountWithInterestAndFees The debt principal + accrued interest and protocol fees function calcCreditAccountAccruedInterest(address creditAccount) external view returns ( uint256 borrowedAmount, uint256 borrowedAmountWithInterest, uint256 borrowedAmountWithInterestAndFees ); /// @dev Maps Credit Accounts to bit masks encoding their enabled token sets /// Only enabled tokens are counted as collateral for the Credit Account /// @notice An enabled token mask encodes an enabled token by setting /// the bit at the position equal to token's index to 1 function enabledTokensMap(address creditAccount) external view returns (uint256); /// @dev Maps the Credit Account to its current percentage drop across all swaps since /// the last full check, in RAY format function cumulativeDropAtFastCheckRAY(address creditAccount) external view returns (uint256); /// @dev Returns the collateral token at requested index and its liquidation threshold /// @param id The index of token to return function collateralTokens(uint256 id) external view returns (address token, uint16 liquidationThreshold); /// @dev Returns the collateral token with requested mask and its liquidationThreshold /// @param tokenMask Token mask corresponding to the token function collateralTokensByMask(uint256 tokenMask) external view returns (address token, uint16 liquidationThreshold); /// @dev Total number of known collateral tokens. function collateralTokensCount() external view returns (uint256); /// @dev Returns the mask for the provided token /// @param token Token to returns the mask for function tokenMasksMap(address token) external view returns (uint256); /// @dev Bit mask encoding a set of forbidden tokens function forbiddenTokenMask() external view returns (uint256); /// @dev Maps allowed adapters to their respective target contracts. function adapterToContract(address adapter) external view returns (address); /// @dev Maps 3rd party contracts to their respective adapters function contractToAdapter(address targetContract) external view returns (address); /// @dev Address of the underlying asset function underlying() external view returns (address); /// @dev Address of the connected pool function pool() external view returns (address); /// @dev Address of the connected pool /// @notice [DEPRECATED]: use pool() instead. function poolService() external view returns (address); /// @dev A map from borrower addresses to Credit Account addresses function creditAccounts(address borrower) external view returns (address); /// @dev Address of the connected Credit Configurator function creditConfigurator() external view returns (address); /// @dev Address of WETH function wethAddress() external view returns (address); /// @dev Returns the liquidation threshold for the provided token /// @param token Token to retrieve the LT for function liquidationThresholds(address token) external view returns (uint16); /// @dev The maximal number of enabled tokens on a single Credit Account function maxAllowedEnabledTokenLength() external view returns (uint8); /// @dev Maps addresses to their status as emergency liquidator. /// @notice Emergency liquidators are trusted addresses /// that are able to liquidate positions while the contracts are paused, /// e.g. when there is a risk of bad debt while an exploit is being patched. /// In the interest of fairness, emergency liquidators do not receive a premium /// And are compensated by the Gearbox DAO separately. function canLiquidateWhilePaused(address) external view returns (bool); /// @dev Returns the fee parameters of the Credit Manager /// @return feeInterest Percentage of interest taken by the protocol as profit /// @return feeLiquidation Percentage of account value taken by the protocol as profit /// during unhealthy account liquidations /// @return liquidationDiscount Multiplier that reduces the effective totalValue during unhealthy account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremium) /// @return feeLiquidationExpired Percentage of account value taken by the protocol as profit /// during expired account liquidations /// @return liquidationDiscountExpired Multiplier that reduces the effective totalValue during expired account liquidations, /// allowing the liquidator to take the unaccounted for remainder as premium. Equal to (1 - liquidationPremiumExpired) function fees() external view returns ( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationDiscount, uint16 feeLiquidationExpired, uint16 liquidationDiscountExpired ); /// @dev Address of the connected Credit Facade function creditFacade() external view returns (address); /// @dev Address of the connected Price Oracle function priceOracle() external view returns (IPriceOracleV2); /// @dev Address of the universal adapter function universalAdapter() external view returns (address); /// @dev Contract's version function version() external view returns (uint256); /// @dev Paused() state function checkEmergencyPausable(address caller, bool state) external returns (bool); }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import "../core/AddressProvider.sol"; import { IVersion } from "./IVersion.sol"; interface IPoolServiceEvents { /// @dev Emits on new liquidity being added to the pool event AddLiquidity( address indexed sender, address indexed onBehalfOf, uint256 amount, uint256 referralCode ); /// @dev Emits on liquidity being removed to the pool event RemoveLiquidity( address indexed sender, address indexed to, uint256 amount ); /// @dev Emits on a Credit Manager borrowing funds for a Credit Account event Borrow( address indexed creditManager, address indexed creditAccount, uint256 amount ); /// @dev Emits on repayment of a Credit Account's debt event Repay( address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss ); /// @dev Emits on updating the interest rate model event NewInterestRateModel(address indexed newInterestRateModel); /// @dev Emits on connecting a new Credit Manager event NewCreditManagerConnected(address indexed creditManager); /// @dev Emits when a Credit Manager is forbidden to borrow event BorrowForbidden(address indexed creditManager); /// @dev Emitted when loss is incurred that can't be covered by treasury funds event UncoveredLoss(address indexed creditManager, uint256 loss); /// @dev Emits when the liquidity limit is changed event NewExpectedLiquidityLimit(uint256 newLimit); /// @dev Emits when the withdrawal fee is changed event NewWithdrawFee(uint256 fee); } /// @title Pool Service Interface /// @notice Implements business logic: /// - Adding/removing pool liquidity /// - Managing diesel tokens & diesel rates /// - Taking/repaying Credit Manager debt /// More: https://dev.gearbox.fi/developers/pool/abstractpoolservice interface IPoolService is IPoolServiceEvents, IVersion { // // LIQUIDITY MANAGEMENT // /** * @dev Adds liquidity to pool * - transfers the underlying to the pool * - mints Diesel (LP) tokens to onBehalfOf * @param amount Amount of tokens to be deposited * @param onBehalfOf The address that will receive the dToken * @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 a facilitator. */ function addLiquidity( uint256 amount, address onBehalfOf, uint256 referralCode ) external; /** * @dev Removes liquidity from pool * - burns LP's Diesel (LP) tokens * - returns the equivalent amount of underlying to 'to' * @param amount Amount of Diesel tokens to burn * @param to Address to transfer the underlying to */ function removeLiquidity(uint256 amount, address to) external returns (uint256); /** * @dev Lends pool funds to a Credit Account * @param borrowedAmount Credit Account's debt principal * @param creditAccount Credit Account's address */ function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external; /** * @dev Repays the Credit Account's debt * @param borrowedAmount Amount of principal ro repay * @param profit The treasury profit from repayment * @param loss Amount of underlying that the CA wan't able to repay * @notice Assumes that the underlying (including principal + interest + fees) * was already transferred */ function repayCreditAccount( uint256 borrowedAmount, uint256 profit, uint256 loss ) external; // // GETTERS // /** * @dev Returns the total amount of liquidity in the pool, including borrowed and available funds */ function expectedLiquidity() external view returns (uint256); /** * @dev Returns the limit on total liquidity */ function expectedLiquidityLimit() external view returns (uint256); /** * @dev Returns the available liquidity, which is expectedLiquidity - totalBorrowed */ function availableLiquidity() external view returns (uint256); /** * @dev Calculates the current interest index, RAY format */ function calcLinearCumulative_RAY() external view returns (uint256); /** * @dev Calculates the current borrow rate, RAY format */ function borrowAPY_RAY() external view returns (uint256); /** * @dev Returns the total borrowed amount (includes principal only) */ function totalBorrowed() external view returns (uint256); /** * ç **/ function getDieselRate_RAY() external view returns (uint256); /** * @dev Returns the address of the underlying */ function underlyingToken() external view returns (address); /** * @dev Returns the address of the diesel token */ function dieselToken() external view returns (address); /** * @dev Returns the address of a Credit Manager by its id */ function creditManagers(uint256 id) external view returns (address); /** * @dev Returns the number of known Credit Managers */ function creditManagersCount() external view returns (uint256); /** * @dev Maps Credit Manager addresses to their status as a borrower. * Returns false if borrowing is not allowed. */ function creditManagersCanBorrow(address id) external view returns (bool); /// @dev Converts a quantity of the underlying to Diesel tokens function toDiesel(uint256 amount) external view returns (uint256); /// @dev Converts a quantity of Diesel tokens to the underlying function fromDiesel(uint256 amount) external view returns (uint256); /// @dev Returns the withdrawal fee function withdrawFee() external view returns (uint256); /// @dev Returns the timestamp of the pool's last update function _timestampLU() external view returns (uint256); /// @dev Returns the interest index at the last pool update function _cumulativeIndex_RAY() external view returns (uint256); /// @dev Returns the address provider function addressProvider() external view returns (AddressProvider); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^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: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IVersion } from "./IVersion.sol"; interface IAddressProviderEvents { /// @dev Emits when an address is set for a contract role event AddressSet(bytes32 indexed service, address indexed newAddress); } /// @title Optimised for front-end Address Provider interface interface IAddressProvider is IAddressProviderEvents, IVersion { /// @return Address of ACL contract function getACL() external view returns (address); /// @return Address of ContractsRegister function getContractsRegister() external view returns (address); /// @return Address of AccountFactory function getAccountFactory() external view returns (address); /// @return Address of DataCompressor function getDataCompressor() external view returns (address); /// @return Address of GEAR token function getGearToken() external view returns (address); /// @return Address of WETH token function getWethToken() external view returns (address); /// @return Address of WETH Gateway function getWETHGateway() external view returns (address); /// @return Address of PriceOracle function getPriceOracle() external view returns (address); /// @return Address of DAO Treasury Multisig function getTreasuryContract() external view returns (address); /// @return Address of PathFinder function getLeveragedActions() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { AddressProvider } from "./AddressProvider.sol"; import { IACL } from "../interfaces/IACL.sol"; import { ZeroAddressException, CallerNotConfiguratorException, CallerNotPausableAdminException, CallerNotUnPausableAdminException } from "../interfaces/IErrors.sol"; /// @title ACL Trait /// @notice Utility class for ACL consumers abstract contract ACLTrait is Pausable { // ACL contract to check rights IACL public immutable _acl; /// @dev constructor /// @param addressProvider Address of address repository constructor(address addressProvider) { if (addressProvider == address(0)) revert ZeroAddressException(); // F:[AA-2] _acl = IACL(AddressProvider(addressProvider).getACL()); } /// @dev Reverts if msg.sender is not configurator modifier configuratorOnly() { if (!_acl.isConfigurator(msg.sender)) revert CallerNotConfiguratorException(); _; } ///@dev Pause contract function pause() external { if (!_acl.isPausableAdmin(msg.sender)) revert CallerNotPausableAdminException(); _pause(); } /// @dev Unpause contract function unpause() external { if (!_acl.isUnpausableAdmin(msg.sender)) revert CallerNotUnPausableAdminException(); _unpause(); } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; interface IWETHGateway { /// @dev Converts ETH to WETH and add liqudity to the pool /// @param pool Address of PoolService contract to add liquidity to. This pool must have WETH as an underlying. /// @param onBehalfOf The address that will receive the diesel token. /// @param referralCode Code used to log the transaction facilitator, for potential rewards. 0 if non-applicable. function addLiquidityETH( address pool, address onBehalfOf, uint16 referralCode ) external payable; /// @dev Removes liquidity from the pool and converts WETH to ETH /// - burns lp's diesel (LP) tokens /// - unwraps WETH to ETH and sends to the LP /// @param pool Address of PoolService contract to withdraw liquidity from. This pool must have WETH as an underlying. /// @param amount Amount of Diesel tokens to send. /// @param to Address to transfer ETH to. function removeLiquidityETH( address pool, uint256 amount, address payable to ) external; /// @dev Converts WETH to ETH, and sends to the passed address /// @param to Address to send ETH to /// @param amount Amount of WETH to unwrap function unwrapWETH(address to, uint256 amount) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.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 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' 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) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _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 require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.8.10; import { Errors } from "./Errors.sol"; uint16 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2; /** * @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 { /** * @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: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; // Denominations uint256 constant WAD = 1e18; uint256 constant RAY = 1e27; // 25% of type(uint256).max uint256 constant ALLOWANCE_THRESHOLD = type(uint96).max >> 3; // FEE = 50% uint16 constant DEFAULT_FEE_INTEREST = 50_00; // 50% // LIQUIDATION_FEE 1.5% uint16 constant DEFAULT_FEE_LIQUIDATION = 1_50; // 1.5% // LIQUIDATION PREMIUM 4% uint16 constant DEFAULT_LIQUIDATION_PREMIUM = 4_00; // 4% // LIQUIDATION_FEE_EXPIRED 2% uint16 constant DEFAULT_FEE_LIQUIDATION_EXPIRED = 1_00; // 2% // LIQUIDATION PREMIUM EXPIRED 2% uint16 constant DEFAULT_LIQUIDATION_PREMIUM_EXPIRED = 2_00; // 2% // DEFAULT PROPORTION OF MAX BORROWED PER BLOCK TO MAX BORROWED PER ACCOUNT uint16 constant DEFAULT_LIMIT_PER_BLOCK_MULTIPLIER = 2; // Seconds in a year uint256 constant SECONDS_PER_YEAR = 365 days; uint256 constant SECONDS_PER_ONE_AND_HALF_YEAR = (SECONDS_PER_YEAR * 3) / 2; // OPERATIONS // Leverage decimals - 100 is equal to 2x leverage (100% * collateral amount + 100% * borrowed amount) uint8 constant LEVERAGE_DECIMALS = 100; // Maximum withdraw fee for pool in PERCENTAGE_FACTOR format uint8 constant MAX_WITHDRAW_FEE = 100; uint256 constant EXACT_INPUT = 1; uint256 constant EXACT_OUTPUT = 2; address constant UNIVERSAL_CONTRACT = 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC;
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; /// @title IVersion /// @dev Declares a version function which returns the contract's version interface IVersion { /// @dev Returns contract version function version() external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IAddressProvider } from "../interfaces/IAddressProvider.sol"; import { Claimable } from "./access/Claimable.sol"; import { Errors } from "../libraries/Errors.sol"; // Repositories & services bytes32 constant CONTRACTS_REGISTER = "CONTRACTS_REGISTER"; bytes32 constant ACL = "ACL"; bytes32 constant PRICE_ORACLE = "PRICE_ORACLE"; bytes32 constant ACCOUNT_FACTORY = "ACCOUNT_FACTORY"; bytes32 constant DATA_COMPRESSOR = "DATA_COMPRESSOR"; bytes32 constant TREASURY_CONTRACT = "TREASURY_CONTRACT"; bytes32 constant GEAR_TOKEN = "GEAR_TOKEN"; bytes32 constant WETH_TOKEN = "WETH_TOKEN"; bytes32 constant WETH_GATEWAY = "WETH_GATEWAY"; bytes32 constant LEVERAGED_ACTIONS = "LEVERAGED_ACTIONS"; /// @title AddressRepository /// @notice Stores addresses of deployed contracts contract AddressProvider is Claimable, IAddressProvider { // Mapping from contract keys to respective addresses mapping(bytes32 => address) public addresses; // Contract version uint256 public constant version = 2; 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); // F:[AP-3] } /// @dev Sets address of ACL contract /// @param _address Address of ACL contract function setACL(address _address) external onlyOwner // F:[AP-12] { _setAddress(ACL, _address); // F:[AP-3] } /// @return Address of ContractsRegister function getContractsRegister() external view returns (address) { return _getAddress(CONTRACTS_REGISTER); // F:[AP-4] } /// @dev Sets address of ContractsRegister /// @param _address Address of ContractsRegister function setContractsRegister(address _address) external onlyOwner // F:[AP-12] { _setAddress(CONTRACTS_REGISTER, _address); // F:[AP-4] } /// @return Address of PriceOracle function getPriceOracle() external view override returns (address) { return _getAddress(PRICE_ORACLE); // F:[AP-5] } /// @dev Sets address of PriceOracle /// @param _address Address of PriceOracle function setPriceOracle(address _address) external onlyOwner // F:[AP-12] { _setAddress(PRICE_ORACLE, _address); // F:[AP-5] } /// @return Address of AccountFactory function getAccountFactory() external view returns (address) { return _getAddress(ACCOUNT_FACTORY); // F:[AP-6] } /// @dev Sets address of AccountFactory /// @param _address Address of AccountFactory function setAccountFactory(address _address) external onlyOwner // F:[AP-12] { _setAddress(ACCOUNT_FACTORY, _address); // F:[AP-6] } /// @return Address of DataCompressor function getDataCompressor() external view override returns (address) { return _getAddress(DATA_COMPRESSOR); // F:[AP-7] } /// @dev Sets address of AccountFactory /// @param _address Address of AccountFactory function setDataCompressor(address _address) external onlyOwner // F:[AP-12] { _setAddress(DATA_COMPRESSOR, _address); // F:[AP-7] } /// @return Address of Treasury contract function getTreasuryContract() external view returns (address) { return _getAddress(TREASURY_CONTRACT); // F:[AP-8] } /// @dev Sets address of Treasury Contract /// @param _address Address of Treasury Contract function setTreasuryContract(address _address) external onlyOwner // F:[AP-12] { _setAddress(TREASURY_CONTRACT, _address); // F:[AP-8] } /// @return Address of GEAR token function getGearToken() external view override returns (address) { return _getAddress(GEAR_TOKEN); // F:[AP-9] } /// @dev Sets address of GEAR token /// @param _address Address of GEAR token function setGearToken(address _address) external onlyOwner // F:[AP-12] { _setAddress(GEAR_TOKEN, _address); // F:[AP-9] } /// @return Address of WETH token function getWethToken() external view override returns (address) { return _getAddress(WETH_TOKEN); // F:[AP-10] } /// @dev Sets address of WETH token /// @param _address Address of WETH token function setWethToken(address _address) external onlyOwner // F:[AP-12] { _setAddress(WETH_TOKEN, _address); // F:[AP-10] } /// @return Address of WETH token function getWETHGateway() external view override returns (address) { return _getAddress(WETH_GATEWAY); // F:[AP-11] } /// @dev Sets address of WETH token /// @param _address Address of WETH token function setWETHGateway(address _address) external onlyOwner // F:[AP-12] { _setAddress(WETH_GATEWAY, _address); // F:[AP-11] } /// @return Address of PathFinder function getLeveragedActions() external view returns (address) { return _getAddress(LEVERAGED_ACTIONS); // T:[AP-7] } /// @dev Sets address of PathFinder /// @param _address Address of PathFinder function setLeveragedActions(address _address) external onlyOwner // T:[AP-15] { _setAddress(LEVERAGED_ACTIONS, _address); // T:[AP-7] } /// @return Address of key, reverts if the 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); // F:[AP-1] return result; // F:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11] } /// @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; // F:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11] emit AddressSet(key, value); // F:[AP-2] } }
// SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; /// @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"; // // 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 ACCOUNT // string public constant CA_CONNECTED_CREDIT_MANAGER_ONLY = "CA1"; string public constant CA_FACTORY_ONLY = "CA2"; // // 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"; // // 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: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; /// @title Claimable /// @dev Implements logic for a two-step ownership transfer on top of Ownable contract Claimable is Ownable { /// @dev The new owner that has not claimed ownership yet address public pendingOwner; /// @dev A modifier that restricts the function to the pending owner only modifier onlyPendingOwner() { if (msg.sender != pendingOwner) { revert("Claimable: Sender is not pending owner"); } _; } /// @dev Sets pending owner to the new owner, but does not /// transfer ownership yet /// @param newOwner The address to become the future owner function transferOwnership(address newOwner) public override onlyOwner { require( newOwner != address(0), "Claimable: new owner is the zero address" ); pendingOwner = newOwner; } /// @dev Used by the pending owner to claim ownership after transferOwnership function claimOwnership() external onlyPendingOwner { _transferOwnership(pendingOwner); pendingOwner = address(0); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^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() { _transferOwnership(_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 { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^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 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) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/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() { _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: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; /// @dev Common contract exceptions /// @dev Thrown on attempting to set an important address to zero address error ZeroAddressException(); /// @dev Thrown on attempting to call a non-implemented function error NotImplementedException(); /// @dev Thrown on attempting to set an EOA as an important contract in the system error AddressIsNotContractException(address); /// @dev Thrown on attempting to use a non-ERC20 contract or an EOA as a token error IncorrectTokenContractException(); /// @dev Thrown on attempting to set a token price feed to an address that is not a /// correct price feed error IncorrectPriceFeedException(); /// @dev Thrown on attempting to call an access restricted function as a non-Configurator error CallerNotConfiguratorException(); /// @dev Thrown on attempting to pause a contract as a non-Pausable admin error CallerNotPausableAdminException(); /// @dev Thrown on attempting to pause a contract as a non-Unpausable admin error CallerNotUnPausableAdminException(); error TokenIsNotAddedToCreditManagerException(address token);
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; import { IVersion } from "./IVersion.sol"; interface IACLExceptions { /// @dev Thrown when attempting to delete an address from a set that is not a pausable admin error AddressNotPausableAdminException(address addr); /// @dev Thrown when attempting to delete an address from a set that is not a unpausable admin error AddressNotUnpausableAdminException(address addr); } interface IACLEvents { /// @dev Emits when a new admin is added that can pause contracts event PausableAdminAdded(address indexed newAdmin); /// @dev Emits when a Pausable admin is removed event PausableAdminRemoved(address indexed admin); /// @dev Emits when a new admin is added that can unpause contracts event UnpausableAdminAdded(address indexed newAdmin); /// @dev Emits when an Unpausable admin is removed event UnpausableAdminRemoved(address indexed admin); } /// @title ACL interface interface IACL is IACLEvents, IACLExceptions, IVersion { /// @dev Returns true if the address is a pausable admin and false if not /// @param addr Address to check function isPausableAdmin(address addr) external view returns (bool); /// @dev Returns true if the address is unpausable admin and false if not /// @param addr Address to check function isUnpausableAdmin(address addr) external view returns (bool); /// @dev Returns true if an address has configurator rights /// @param account Address to check function isConfigurator(address account) external view returns (bool); /// @dev Returns address of configurator function owner() external view returns (address); }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdaptersOrCreditFacadeOnlyException","type":"error"},{"inputs":[],"name":"AllowanceFailedException","type":"error"},{"inputs":[],"name":"CallerNotPausableAdminException","type":"error"},{"inputs":[],"name":"CallerNotUnPausableAdminException","type":"error"},{"inputs":[],"name":"CreditConfiguratorOnlyException","type":"error"},{"inputs":[],"name":"CreditFacadeOnlyException","type":"error"},{"inputs":[],"name":"HasNoOpenedAccountException","type":"error"},{"inputs":[],"name":"NotEnoughCollateralException","type":"error"},{"inputs":[],"name":"ReentrancyLockException","type":"error"},{"inputs":[],"name":"TargetContractNotAllowedException","type":"error"},{"inputs":[],"name":"TokenAlreadyAddedException","type":"error"},{"inputs":[],"name":"TokenNotAllowedException","type":"error"},{"inputs":[],"name":"TooManyEnabledTokensException","type":"error"},{"inputs":[],"name":"TooManyTokensException","type":"error"},{"inputs":[],"name":"ZeroAddressException","type":"error"},{"inputs":[],"name":"ZeroAddressOrUserAlreadyHasAccountException","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"ExecuteOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newConfigurator","type":"address"}],"name":"NewConfigurator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"_accountFactory","outputs":[{"internalType":"contract IAccountFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acl","outputs":[{"internalType":"contract IACL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"adapterToContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"}],"name":"addEmergencyLiquidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"addToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveCreditAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"enum ClosureAction","name":"closureActionType","type":"uint8"},{"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedAmountWithInterest","type":"uint256"}],"name":"calcClosePayments","outputs":[{"internalType":"uint256","name":"amountToPool","type":"uint256"},{"internalType":"uint256","name":"remainingFunds","type":"uint256"},{"internalType":"uint256","name":"profit","type":"uint256"},{"internalType":"uint256","name":"loss","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"}],"name":"calcCreditAccountAccruedInterest","outputs":[{"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedAmountWithInterest","type":"uint256"},{"internalType":"uint256","name":"borrowedAmountWithInterestAndFees","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"canLiquidateWhilePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"address","name":"targetContract","type":"address"}],"name":"changeContractAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"checkAndEnableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"}],"name":"checkAndOptimizeEnabledTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"checkEmergencyPausable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"enum ClosureAction","name":"closureActionType","type":"uint8"},{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"skipTokenMask","type":"uint256"},{"internalType":"bool","name":"convertWETH","type":"bool"}],"name":"closeCreditAccount","outputs":[{"internalType":"uint256","name":"remainingFunds","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"collateralTokens","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenMask","type":"uint256"}],"name":"collateralTokensByMask","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralTokensCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"contractToAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"creditAccounts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditConfigurator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditFacade","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cumulativeDropAtFastCheckRAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"disableToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyLiquidation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"enabledTokensMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"executeOrder","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"balanceInBefore","type":"uint256"},{"internalType":"uint256","name":"balanceOutBefore","type":"uint256"}],"name":"fastCollateralCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint16","name":"feeInterest","type":"uint16"},{"internalType":"uint16","name":"feeLiquidation","type":"uint16"},{"internalType":"uint16","name":"liquidationDiscount","type":"uint16"},{"internalType":"uint16","name":"feeLiquidationExpired","type":"uint16"},{"internalType":"uint16","name":"liquidationDiscountExpired","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forbiddenTokenMask","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"}],"name":"fullCollateralCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"getCreditAccountOrRevert","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"liquidationThresholds","outputs":[{"internalType":"uint16","name":"lt","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"increase","type":"bool"}],"name":"manageDebt","outputs":[{"internalType":"uint256","name":"newBorrowedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxAllowedEnabledTokenLength","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"}],"name":"openCreditAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolService","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOracle","outputs":[{"internalType":"contract IPriceOracleV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"}],"name":"removeEmergencyLiquidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_creditConfigurator","type":"address"}],"name":"setConfigurator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_forbidMask","type":"uint256"}],"name":"setForbidMask","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"}],"name":"setLiquidationThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newMaxEnabledTokens","type":"uint8"}],"name":"setMaxEnabledTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_feeInterest","type":"uint16"},{"internalType":"uint16","name":"_feeLiquidation","type":"uint16"},{"internalType":"uint16","name":"_liquidationDiscount","type":"uint16"},{"internalType":"uint16","name":"_feeLiquidationExpired","type":"uint16"},{"internalType":"uint16","name":"_liquidationDiscountExpired","type":"uint16"}],"name":"setParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"tokenMasksMap","outputs":[{"internalType":"uint256","name":"mask","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"transferAccountOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"universalAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_creditFacade","type":"address"}],"name":"upgradeCreditFacade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceOracle","type":"address"}],"name":"upgradePriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wethAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wethGateway","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101606040526000805463ff0000001916630c0000001790553480156200002557600080fd5b50604051620061b6380380620061b6833981016040819052620000489162000539565b806001600160a01b0316632954018c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000087573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ad919062000539565b6000805460ff191690556001600160a01b038116620000df57604051635919af9760e11b815260040160405180910390fd5b806001600160a01b031663087376956040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200011e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000144919062000539565b6001600160a01b03166080816001600160a01b031681525050506000816001600160a01b0316632954018c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200019f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c5919062000539565b6001600160a01b03831661010081905260e081905260408051632495a59960e01b81529051929350600092632495a599916004808201926020929091908290030181865afa1580156200021c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000242919062000539565b6001600160a01b03811660c05290506200025c8162000474565b816001600160a01b0316634c252f916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200029b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002c1919062000539565b6001600160a01b0316610120816001600160a01b031681525050816001600160a01b03166377532ed96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000340919062000539565b6001600160a01b0316610140816001600160a01b031681525050816001600160a01b031663fca513a86040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000399573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003bf919062000539565b6001600001600a6101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316639068a8686040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000427573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200044d919062000539565b6001600160a01b031660a0525050600380546001600160a01b03191633179055506200058a565b6001600160a01b03811660009081526006602052604090205415620004ac57604051632e5a5c7760e01b815260040160405180910390fd5b61010060055410620004d157604051633f02862960e11b815260040160405180910390fd5b600580546001600160a01b0383166000818152600660209081526040808320600190951b9485905584835260049091528120919091558254919290620005178362000560565b91905055505050565b6001600160a01b03811681146200053657600080fd5b50565b6000602082840312156200054c57600080fd5b8151620005598162000520565b9392505050565b60006000198214156200058357634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a05160c05160e051610100516101205161014051615aff620006b76000396000818161088d01528181613ec00152613f750152600081816105980152613e2801526000818161041001528181610f8e01528181610ff2015281816128f901528181612a5401528181612dfa01528181612f3b01528181612fac01528181613076015281816131ad0152818161325c01526143400152600061060d01526000818161069801528181610e5901528181610eea01528181610f3701528181610f6d015281816110760152818161239201528181612f1301528181613185015281816136d201528181613b7b01528181613d2501526147970152600081816108c70152818161111801526128bc015260008181610840015281816112dd01526126240152615aff6000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c80638456cb59116101de578063b3da9e6b1161010f578063e75538c7116100ad578063f9aa028a1161007c578063f9aa028a1461096e578063fdd576451461098e578063fe47cde7146109c4578063ff687543146109e457600080fd5b8063e75538c714610922578063e958b70414610935578063eb99c2bf14610948578063f67c5bd01461095b57600080fd5b8063db7ceb80116100e9578063db7ceb80146108c2578063dc2b21c1146108e9578063dc9e0faa146108fc578063e1998cf91461090f57600080fd5b8063b3da9e6b14610875578063c5e10eef14610888578063d48bfca7146108af57600080fd5b80639af1d35a1161017c578063a366f49611610156578063a366f49614610815578063a460e10414610828578063a50cf2c81461083b578063a70bc5421461086257600080fd5b80639af1d35a146107a05780639f5f86ae146107f95780639fd12b771461080c57600080fd5b80638fe3f93f116101b85780638fe3f93f14610754578063944ac59f1461076757806394cf073a1461077a578063953730181461078d57600080fd5b80638456cb591461071957806384edaa42146107215780638991b2f11461073457600080fd5b80634f0e0ef3116102b8578063693ce7f5116102565780636f307dc3116102305780636f307dc31461069357806378327438146106ba578063830aa745146106e05780638345f26e146106f357600080fd5b8063693ce7f51461064d5780636ce4074a146106605780636e98e5e41461068057600080fd5b806354fd4d501161029257806354fd4d5014610600578063570a7af2146106085780635c975abb1461062f578063654a9eda1461063a57600080fd5b80634f0e0ef3146105935780635063524a146105ba57806351e3f160146105ed57600080fd5b80632f7a1881116103255780633e8297ca116102ff5780633e8297ca1461054f5780633f4ba83a1461056f578063458936f51461057757806346fb371d1461058057600080fd5b80632f7a1881146104d65780633192195c146104fe57806338975bc41461052c57600080fd5b8063172c48c711610361578063172c48c7146104325780632362a2d8146104745780632630c12f1461049557806329df0b93146104c157600080fd5b8063055ee9b5146103885780630d8f9cee146103e857806316f0115b1461040b575b600080fd5b6103be6103963660046152ea565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6103fb6103f6366004615307565b610a1a565b60405190151581526020016103df565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b610445610440366004615340565b610bd1565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835261ffff9091166020830152016103df565b610487610482366004615376565b610be9565b6040519081526020016103df565b6001546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166103be565b6104d46104cf3660046152ea565b6111ac565b005b6000546103be90640100000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61051161050c3660046152ea565b611242565b604080519384526020840192909252908201526060016103df565b6103fb61053a3660046152ea565b600c6020526000908152604090205460ff1681565b61048761055d3660046152ea565b60096020526000908152604090205481565b6104d46112af565b61048760055481565b6104d461058e3660046153f8565b61139d565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6105cd6105c8366004615449565b611608565b6040805194855260208501939093529183015260608201526080016103df565b6104d46105fb366004615307565b6117f7565b610487600281565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b60005460ff166103fb565b6104d4610648366004615484565b6119a5565b6104d461065b3660046152ea565b611e60565b61067361066e3660046155a3565b611f00565b6040516103df91906156be565b6104d461068e366004615307565b6121e6565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6106cd6106c83660046152ea565b61238e565b60405161ffff90911681526020016103df565b6104d46106ee3660046153f8565b612467565b600054610707906301000000900460ff1681565b60405160ff90911681526020016103df565b6104d46125f6565b6104d461072f3660046152ea565b6126e2565b6104876107423660046152ea565b60086020526000908152604090205481565b6103be6107623660046156d1565b612782565b6104d4610775366004615708565b612b12565b61048761078836600461576d565b612c3f565b6104d461079b3660046152ea565b6133a0565b6001546040805161ffff808416825262010000840481166020830152640100000000840481169282019290925266010000000000008304821660608201526801000000000000000090920416608082015260a0016103df565b6104d46108073660046152ea565b6134cc565b61048760075481565b6104d4610823366004615340565b61358c565b6104d46108363660046152ea565b6135e2565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6104d46108703660046157af565b61367f565b6000546103fb9062010000900460ff1681565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6104d46108bd3660046152ea565b613805565b6103be7f000000000000000000000000000000000000000000000000000000000000000081565b6104d46108f73660046157e4565b61385f565b6104d461090a3660046152ea565b6138eb565b6104d461091d366004615307565b613991565b610445610930366004615340565b613b68565b6103be6109433660046152ea565b613bed565b6103fb610956366004615807565b613c51565b6104876109693660046152ea565b613d21565b6003546103be9073ffffffffffffffffffffffffffffffffffffffff1681565b6103be61099c3660046152ea565b600b6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600d546103be9073ffffffffffffffffffffffffffffffffffffffff1681565b6103be6109f23660046152ea565b600a6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6000805460ff161580610a35575060005462010000900460ff165b610aa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064015b60405180910390fd5b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16158015610af35750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15610b2a576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615610b6c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055610ba28383613daa565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690559392505050565b600080610be06001841b613b68565b91509150915091565b60008054610100900460ff1615610c2c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314610cb2576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff1615610d8e5773ffffffffffffffffffffffffffffffffffffffff85166000908152600c602052604090205460ff168015610d1e57506001876003811115610d0157610d01615835565b1480610d1e57506002876003811115610d1c57610d1c615835565b145b15610d2c5760039650610d8e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b6000610d9989613bed565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260026020526040812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590915080808080610df486611242565b509094509050610e068c8e8684611608565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b81166004830152939b5093985090955093506000917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec69190615864565b9050610ed288876158ac565b610edd9060016158ac565b811115610f1d57610f18877f00000000000000000000000000000000000000000000000000000000000000008d60018c8b870303038d613e1e565b610f67565b610f6773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d8960018a8d0186900301614070565b610fb5877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000896000613e1e565b6040517fca9505e40000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604481018490527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063ca9505e490606401600060405180830381600087803b15801561104b57600080fd5b505af115801561105f573d6000803e3d6000fd5b5050505050505050600184111561109e5761109e837f00000000000000000000000000000000000000000000000000000000000000008d876000613e1e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600860205260409020548619166110d38489888461410b565b6040517f89b77b3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000000000000000000000000000000000000000000016906389b77b3e90602401600060405180830381600087803b15801561115c57600080fd5b505af1158015611170573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550949c9b505050505050505050505050565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156111ff5750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611236576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61123f816141e5565b50565b600080600080600061125386614257565b919650925090508161126582876158c4565b61126f9190615901565b6001549094506127109061ffff16611287878761593c565b61129191906158c4565b61129b9190615901565b6112a590856158ac565b9496939550505050565b6040517fd4eb5db00000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d4eb5db090602401602060405180830381865afa158015611339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135d9190615953565b611393576040517f10332dee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139b6143d5565b565b60005460ff1615806113b7575060005462010000900460ff165b61141d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff161561145f576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff908116908416148015906114e15750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b80156115055750600d5473ffffffffffffffffffffffffffffffffffffffff163314155b80611524575073ffffffffffffffffffffffffffffffffffffffff8316155b1561155b576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61156482613d21565b61159a576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115a585613bed565b90506115b58385838560006144b6565b6115d9576115c8838583600060016144b6565b506115d78385838560016144b6565b505b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b6001546000908190819081906127109061ffff16611626888861593c565b61163091906158c4565b61163a9190615901565b61164490866158ac565b9350600187600381111561165a5761165a615835565b14806116775750600287600381111561167557611675615835565b145b806116935750600387600381111561169157611691615835565b145b156117e657600060018860038111156116ae576116ae615835565b141561171457600154612710906116d190640100000000900461ffff168b6158c4565b6116db9190615901565b600154909150612710906116f99062010000900461ffff168b6158c4565b6117039190615901565b61170d90866158ac565b94506117b0565b600288600381111561172857611728615835565b141561177b576001546127109061174f9068010000000000000000900461ffff168b6158c4565b6117599190615901565b600154909150612710906116f9906601000000000000900461ffff168b6158c4565b506001548890612710906117999062010000900461ffff16836158c4565b6117a39190615901565b6117ad90866158ac565b94505b848111156117c55760018582030393506117c9565b8094505b8581106117da5785850392506117e0565b84860391505b506117ec565b84840391505b945094509450949050565b60005460ff161580611811575060005462010000900460ff165b611877576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156118ca5750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611901576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615611943576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556119798282614657565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156119f85750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611a2f576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615611a71576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055611aa78584614657565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152600091908616906370a0823190602401602060405180830381865afa158015611b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3b9190615864565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529192506000918616906370a0823190602401602060405180830381865afa158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd19190615864565b60015490915060009081906a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16635cecbd0e611c0f868961593c565b8a611c1a898861593c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935273ffffffffffffffffffffffffffffffffffffffff918216602484015260448301528a1660648201526084016040805180830381865afa158015611c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cba9190615970565b9150915060018411611cd257611cd08989613daa565b505b611cdb8761238e565b611ce99061ffff16826158c4565b9050611cf48861238e565b611d029061ffff16836158c4565b9150818110611d1d57611d14896141e5565b505050506115d9565b73ffffffffffffffffffffffffffffffffffffffff891660009081526009602052604081205483611d5a6b033b2e3c9fd0803ce8000000856158c4565b611d649190615901565b611d7a906b033b2e3c9fd0803ce800000061593c565b611d8491906158ac565b60015490915061271090611daf906b033b2e3c9fd0803ce80000009062010000900461ffff166158c4565b611db99190615901565b8111611dfa5773ffffffffffffffffffffffffffffffffffffffff8a166000908152600960205260409020819055611df08a6141e5565b50505050506115d9565b611e038a614707565b50505073ffffffffffffffffffffffffffffffffffffffff871660009081526009602052604090206001905550505050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611eb1576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff909216640100000000027fffffffffffffffff0000000000000000000000000000000000000000ffffffff909216919091179055565b6060611f0e60005460ff1690565b1580611f22575060005462010000900460ff165b611f88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615611fca576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff90811690841614158061203f575073ffffffffffffffffffffffffffffffffffffffff8316155b1561209557600d5473ffffffffffffffffffffffffffffffffffffffff163314612095576040517ffc1a554300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120a085613bed565b90508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167faed1eb34af6acd8c1e3911fb2ebb875a66324b03957886bd002227b17f52ab0360405160405180910390a36040517f1cff79cd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690631cff79cd906121509087908790600401615994565b6000604051808303816000875af115801561216f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526121b591908101906159c3565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905595945050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314612237576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216156122a75773ffffffffffffffffffffffffffffffffffffffff8281166000908152600a6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b73ffffffffffffffffffffffffffffffffffffffff8116156123175773ffffffffffffffffffffffffffffffffffffffff8181166000908152600b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169184169190911790555b73ffffffffffffffffffffffffffffffffffffffff811673cccccccccccccccccccccccccccccccccccccccc141561238a57600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b5050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156124125750506001547e01000000000000000000000000000000000000000000000000000000000000900461ffff1690565b600061241d83613d21565b905080612456576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f81613b68565b949350505050565b60005460ff16156124d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612516576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff16331461259c576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125a68383614657565b6125c873ffffffffffffffffffffffffffffffffffffffff8316858584614070565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b6040517f3a41ec640000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633a41ec6490602401602060405180830381865afa158015612680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a49190615953565b6126da576040517fd794b1e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139b614a7b565b60035473ffffffffffffffffffffffffffffffffffffffff163314612733576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff166000908152600c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805460ff16156127f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612832576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff1633146128b8576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166321d18456857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190615864565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af11580156129e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a059190615a31565b6040517fbf28068b0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff80831660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063bf28068b90604401600060405180830381600087803b158015612a9a57600080fd5b505af1158015612aae573d6000803e3d6000fd5b50505050612abc8382614b3b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526008602052604081206001905580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690559392505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314612b63576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805461ffff92831668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff9484166601000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff96851664010000000002969096167fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff97851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090931694909816939093171794909416949094179190911716919091179055565b6000805460ff1615612cad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612cef576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314612d75576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000612d8387614257565b92509250925060008515612e5d57612d9b87856158ac565b9450612dab848884866001614c0e565b6040517fbf28068b0000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff8a811660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063bf28068b90604401600060405180830381600087803b158015612e4057600080fd5b505af1158015612e54573d6000803e3d6000fd5b505050506132e5565b60008484612e6b85836158c4565b612e759190615901565b612e7f919061593c565b60015490915060009061271090612e9a9061ffff16846158c4565b612ea49190615901565b9050612eb081836158ac565b891061310a578881612ec284896158ac565b612ecc91906158ac565b612ed6919061593c565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018c9052919850908b169063d1660f9990606401600060405180830381600087803b158015612f9257600080fd5b505af1158015612fa6573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ca9505e482848c612ff3919061593c565b612ffd919061593c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526024810184905260006044820152606401600060405180830381600087803b15801561305c57600080fd5b505af1158015613070573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131039190615864565b92506132e2565b6001546000906131209061ffff16612710615a4e565b61ffff166131306127108c6158c4565b61313a9190615901565b90506000613148828c61593c565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018e9052999a508a99919250908d169063d1660f9990606401600060405180830381600087803b15801561320957600080fd5b505af115801561321d573d6000803e3d6000fd5b50506040517fca9505e40000000000000000000000000000000000000000000000000000000081526000600482018190526024820185905260448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16925063ca9505e49150606401600060405180830381600087803b1580156132b757600080fd5b505af11580156132cb573d6000803e3d6000fd5b505050506132dd8883888a6000614c0e565b945050505b50505b6040517f16128211000000000000000000000000000000000000000000000000000000008152600481018690526024810182905273ffffffffffffffffffffffffffffffffffffffff891690631612821190604401600060405180830381600087803b15801561335457600080fd5b505af1158015613368573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055509498975050505050505050565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156133f35750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b1561342a576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff161561346c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556134a181614707565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60035473ffffffffffffffffffffffffffffffffffffffff16331461351d576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517ff62005acebe9b616aefb5f248b48f5e89f28437b27d1eebc0b2d911209f297af90600090a250565b60035473ffffffffffffffffffffffffffffffffffffffff1633146135dd576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600755565b60035473ffffffffffffffffffffffffffffffffffffffff163314613633576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff166000908152600c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60035473ffffffffffffffffffffffffffffffffffffffff1633146136d0576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613777576001805461ffff83167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790555050565b600061378283613d21565b9050806137bb576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff1675ffff000000000000000000000000000000000000000060a084901b161790555050565b60035473ffffffffffffffffffffffffffffffffffffffff163314613856576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61123f81614cf4565b60035473ffffffffffffffffffffffffffffffffffffffff1633146138b0576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460ff9092166301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b60035473ffffffffffffffffffffffffffffffffffffffff16331461393c576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff9092166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff909216919091179055565b60005460ff1615806139ab575060005462010000900460ff165b613a11576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615613a53576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613ad9576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613ae483613bed565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559050613b3b8282614b3b565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b6000808260011415613bc65750506001547f0000000000000000000000000000000000000000000000000000000000000000927e0100000000000000000000000000000000000000000000000000000000000090910461ffff169150565b600083815260046020526040902054915081613be560a082901c614de8565b915050915091565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600260205260409020541680613c4c576040517fb5ba4c4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613cab576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff16808015613ce3575073ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604090205460ff165b15613d1a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000851515021790555b9392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614613da15773ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040902054613da4565b60015b92915050565b600080613db683613d21565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260086020526040902054909150811615613e175773ffffffffffffffffffffffffffffffffffffffff8416600090815260086020526040902080548219169055600191505b5092915050565b808015613e7657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b15613fd8576040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905286169063d1660f9990606401600060405180830381600087803b158015613f1357600080fd5b505af1158015613f27573d6000803e3d6000fd5b50506040517f5869dba800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000169250635869dba89150604401600060405180830381600087803b158015613fbb57600080fd5b505af1158015613fcf573d6000803e3d6000fd5b50505050614069565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015284811660248301526044820184905286169063d1660f9990606401600060405180830381600087803b15801561405057600080fd5b505af1158015614064573d6000803e3d6000fd5b505050505b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052614105908590614e80565b50505050565b60025b81811161406957818116156141dd57600061412882613b68565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561419b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141bf9190615864565b905060018111156141da576141da8783886001850389613e1e565b50505b60011b61410e565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600860205260408120549061421582614f8c565b6000549091506301000000900460ff1681111561425257600061423783614fa2565b6142429060016158ac565b905061410584848460008561500d565b505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff16631afbb7a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142cb9190615864565b92508373ffffffffffffffffffffffffffffffffffffffff166317d11a156040518163ffffffff1660e01b8152600401602060405180830381865afa158015614318573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433c9190615864565b91507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143cd9190615864565b929491935050565b60005460ff16614441576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a97565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6040805173ffffffffffffffffffffffffffffffffffffffff8681166024830152604480830186905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905291517f1cff79cd000000000000000000000000000000000000000000000000000000008152600092861691631cff79cd91614577918a91600401615994565b6000604051808303816000875af19250505080156145d557506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526145d291908101906159c3565b60015b6145de57614612565b805115806146015750808060200190518101906145fb9190615953565b15156001145b1561461057600191505061464e565b505b811561464a576040517f2f10a7f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060005b95945050505050565b600061466282613d21565b90508015806146745750600754811615155b156146ab576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526008602052604090205481166142525773ffffffffffffffffffffffffffffffffffffffff83166000908152600860205260409020805482179055505050565b60015473ffffffffffffffffffffffffffffffffffffffff8281166000908152600860205260408120546a01000000000000000000009093049091169190808061475086611242565b6040517ff9a650300000000000000000000000000000000000000000000000000000000081526127108202600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166024830152919450908816925063f9a650309150604401602060405180830381865afa1580156147ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148109190615864565b925061481b84614fa2565b6001019150506000806000805b84811015614a485780156148415760018186031b614844565b60015b935086841615614a405760008061485a86613b68565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e811660048301529294509092506000918416906370a0823190602401602060405180830381865afa1580156148cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f39190615864565b90506001811115614a33576040517ff9a650300000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff848116602483015261ffff841691908d169063f9a6503090604401602060405180830381865afa158015614978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061499c9190615864565b6149a691906158c4565b6149b090876158ac565b9550888610614a2e5760006149c48b614f8c565b6000549091506301000000900460ff168111156149f0576149eb8d8c836001898e0361500d565b614a1f565b8515614a1f5773ffffffffffffffffffffffffffffffffffffffff8d1660009081526008602052604090208b90555b50505050505050505050505050565b614a3c565b98861898600194505b5050505b600101614828565b506040517f532e7bb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff1615614ae8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861448c3390565b73ffffffffffffffffffffffffffffffffffffffff82161580614b84575073ffffffffffffffffffffffffffffffffffffffff8281166000908152600260205260409020541615155b15614bbb576040517f9e59609e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60008115614c8b576000614c2286886158ac565b9050614c3286633b9aca006158c4565b8488614c4288633b9aca006158c4565b614c4c91906158c4565b614c569190615901565b614c6091906158ac565b633b9aca00614c6f83886158c4565b614c7991906158c4565b614c839190615901565b91505061464e565b8583614c9b87633b9aca006158c4565b614ca591906158c4565b614caf9190615901565b614cbd85633b9aca006158c4565b614cc7919061593c565b83614cd686633b9aca006158c4565b614ce091906158c4565b614cea9190615901565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205415614d51576040517f2e5a5c7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010060055410614d8e576040517f7e050c5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff83166000818152600660209081526040808320600190951b9485905584835260049091528120919091558254919290614ddf83615a74565b91905055505050565b600061ffff821115614e7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610a97565b5090565b6000614ee2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661517c9092919063ffffffff16565b8051909150156142525780806020019051810190614f009190615953565b614252576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a97565b60005b8115613c4c57600182811c921601614f8f565b60008160011415614fb557506000919050565b61010060015b6001614fc782846158ac565b901c92506001831b84811615801590614fe25750600185851c145b15614fed5750615006565b848110614ffc57839250615000565b8391505b50614fbb565b5050919050565b815b81811015615149576001811b8581161561514057600061502e82613b68565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529192506000918316906370a0823190602401602060405180830381865afa1580156150a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150c59190615864565b90506001811161513d57600054978318977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9097019660ff630100000090910416871161513d5750505073ffffffffffffffffffffffffffffffffffffffff8616600090815260086020526040902085905550614069565b50505b5060010161500f565b506040517f30b5495c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061245f848460008585843b6151ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a97565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516152189190615aad565b60006040518083038185875af1925050503d8060008114615255576040519150601f19603f3d011682016040523d82523d6000602084013e61525a565b606091505b509150915061526a828286615275565b979650505050505050565b60608315615284575081613d1a565b8251156152945782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9791906156be565b73ffffffffffffffffffffffffffffffffffffffff8116811461123f57600080fd5b6000602082840312156152fc57600080fd5b8135613d1a816152c8565b6000806040838503121561531a57600080fd5b8235615325816152c8565b91506020830135615335816152c8565b809150509250929050565b60006020828403121561535257600080fd5b5035919050565b803560048110613c4c57600080fd5b801515811461123f57600080fd5b600080600080600080600060e0888a03121561539157600080fd5b873561539c816152c8565b96506153aa60208901615359565b95506040880135945060608801356153c1816152c8565b935060808801356153d1816152c8565b925060a0880135915060c08801356153e881615368565b8091505092959891949750929550565b6000806000806080858703121561540e57600080fd5b8435615419816152c8565b93506020850135615429816152c8565b92506040850135615439816152c8565b9396929550929360600135925050565b6000806000806080858703121561545f57600080fd5b8435935061546f60208601615359565b93969395505050506040820135916060013590565b600080600080600060a0868803121561549c57600080fd5b85356154a7816152c8565b945060208601356154b7816152c8565b935060408601356154c7816152c8565b94979396509394606081013594506080013592915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615555576155556154df565b604052919050565b600067ffffffffffffffff821115615577576155776154df565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806000606084860312156155b857600080fd5b83356155c3816152c8565b925060208401356155d3816152c8565b9150604084013567ffffffffffffffff8111156155ef57600080fd5b8401601f8101861361560057600080fd5b803561561361560e8261555d565b61550e565b81815287602083850101111561562857600080fd5b816020840160208301376000602083830101528093505050509250925092565b60005b8381101561566357818101518382015260200161564b565b838111156141055750506000910152565b6000815180845261568c816020860160208601615648565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613d1a6020830184615674565b600080604083850312156156e457600080fd5b823591506020830135615335816152c8565b803561ffff81168114613c4c57600080fd5b600080600080600060a0868803121561572057600080fd5b615729866156f6565b9450615737602087016156f6565b9350615745604087016156f6565b9250615753606087016156f6565b9150615761608087016156f6565b90509295509295909350565b60008060006060848603121561578257600080fd5b833561578d816152c8565b92506020840135915060408401356157a481615368565b809150509250925092565b600080604083850312156157c257600080fd5b82356157cd816152c8565b91506157db602084016156f6565b90509250929050565b6000602082840312156157f657600080fd5b813560ff81168114613d1a57600080fd5b6000806040838503121561581a57600080fd5b8235615825816152c8565b9150602083013561533581615368565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020828403121561587657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156158bf576158bf61587d565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156158fc576158fc61587d565b500290565b600082615937577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008282101561594e5761594e61587d565b500390565b60006020828403121561596557600080fd5b8151613d1a81615368565b6000806040838503121561598357600080fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061245f6040830184615674565b6000602082840312156159d557600080fd5b815167ffffffffffffffff8111156159ec57600080fd5b8201601f810184136159fd57600080fd5b8051615a0b61560e8261555d565b818152856020838501011115615a2057600080fd5b61464e826020830160208601615648565b600060208284031215615a4357600080fd5b8151613d1a816152c8565b600061ffff808316818516808303821115615a6b57615a6b61587d565b01949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615aa657615aa661587d565b5060010190565b60008251615abf818460208701615648565b919091019291505056fea264697066735822122098b131e40cdbeea1a6bd054f778411777fdf344e5f59e80117d76e3db0455f4264736f6c634300080a003300000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e4
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c80638456cb59116101de578063b3da9e6b1161010f578063e75538c7116100ad578063f9aa028a1161007c578063f9aa028a1461096e578063fdd576451461098e578063fe47cde7146109c4578063ff687543146109e457600080fd5b8063e75538c714610922578063e958b70414610935578063eb99c2bf14610948578063f67c5bd01461095b57600080fd5b8063db7ceb80116100e9578063db7ceb80146108c2578063dc2b21c1146108e9578063dc9e0faa146108fc578063e1998cf91461090f57600080fd5b8063b3da9e6b14610875578063c5e10eef14610888578063d48bfca7146108af57600080fd5b80639af1d35a1161017c578063a366f49611610156578063a366f49614610815578063a460e10414610828578063a50cf2c81461083b578063a70bc5421461086257600080fd5b80639af1d35a146107a05780639f5f86ae146107f95780639fd12b771461080c57600080fd5b80638fe3f93f116101b85780638fe3f93f14610754578063944ac59f1461076757806394cf073a1461077a578063953730181461078d57600080fd5b80638456cb591461071957806384edaa42146107215780638991b2f11461073457600080fd5b80634f0e0ef3116102b8578063693ce7f5116102565780636f307dc3116102305780636f307dc31461069357806378327438146106ba578063830aa745146106e05780638345f26e146106f357600080fd5b8063693ce7f51461064d5780636ce4074a146106605780636e98e5e41461068057600080fd5b806354fd4d501161029257806354fd4d5014610600578063570a7af2146106085780635c975abb1461062f578063654a9eda1461063a57600080fd5b80634f0e0ef3146105935780635063524a146105ba57806351e3f160146105ed57600080fd5b80632f7a1881116103255780633e8297ca116102ff5780633e8297ca1461054f5780633f4ba83a1461056f578063458936f51461057757806346fb371d1461058057600080fd5b80632f7a1881146104d65780633192195c146104fe57806338975bc41461052c57600080fd5b8063172c48c711610361578063172c48c7146104325780632362a2d8146104745780632630c12f1461049557806329df0b93146104c157600080fd5b8063055ee9b5146103885780630d8f9cee146103e857806316f0115b1461040b575b600080fd5b6103be6103963660046152ea565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6103fb6103f6366004615307565b610a1a565b60405190151581526020016103df565b6103be7f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e481565b610445610440366004615340565b610bd1565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835261ffff9091166020830152016103df565b610487610482366004615376565b610be9565b6040519081526020016103df565b6001546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166103be565b6104d46104cf3660046152ea565b6111ac565b005b6000546103be90640100000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61051161050c3660046152ea565b611242565b604080519384526020840192909252908201526060016103df565b6103fb61053a3660046152ea565b600c6020526000908152604090205460ff1681565b61048761055d3660046152ea565b60096020526000908152604090205481565b6104d46112af565b61048760055481565b6104d461058e3660046153f8565b61139d565b6103be7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6105cd6105c8366004615449565b611608565b6040805194855260208501939093529183015260608201526080016103df565b6104d46105fb366004615307565b6117f7565b610487600281565b6103be7f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e481565b60005460ff166103fb565b6104d4610648366004615484565b6119a5565b6104d461065b3660046152ea565b611e60565b61067361066e3660046155a3565b611f00565b6040516103df91906156be565b6104d461068e366004615307565b6121e6565b6103be7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6106cd6106c83660046152ea565b61238e565b60405161ffff90911681526020016103df565b6104d46106ee3660046153f8565b612467565b600054610707906301000000900460ff1681565b60405160ff90911681526020016103df565b6104d46125f6565b6104d461072f3660046152ea565b6126e2565b6104876107423660046152ea565b60086020526000908152604090205481565b6103be6107623660046156d1565b612782565b6104d4610775366004615708565b612b12565b61048761078836600461576d565b612c3f565b6104d461079b3660046152ea565b6133a0565b6001546040805161ffff808416825262010000840481166020830152640100000000840481169282019290925266010000000000008304821660608201526801000000000000000090920416608082015260a0016103df565b6104d46108073660046152ea565b6134cc565b61048760075481565b6104d4610823366004615340565b61358c565b6104d46108363660046152ea565b6135e2565b6103be7f000000000000000000000000523da3a8961e4dd4f6206dbf7e6c749f51796bb381565b6104d46108703660046157af565b61367f565b6000546103fb9062010000900460ff1681565b6103be7f0000000000000000000000004f952c4c5415b2609899abdc2f8f352f600d14d681565b6104d46108bd3660046152ea565b613805565b6103be7f000000000000000000000000444cd42baeddeb707eed823f7177b9abcc779c0481565b6104d46108f73660046157e4565b61385f565b6104d461090a3660046152ea565b6138eb565b6104d461091d366004615307565b613991565b610445610930366004615340565b613b68565b6103be6109433660046152ea565b613bed565b6103fb610956366004615807565b613c51565b6104876109693660046152ea565b613d21565b6003546103be9073ffffffffffffffffffffffffffffffffffffffff1681565b6103be61099c3660046152ea565b600b6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600d546103be9073ffffffffffffffffffffffffffffffffffffffff1681565b6103be6109f23660046152ea565b600a6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6000805460ff161580610a35575060005462010000900460ff165b610aa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064015b60405180910390fd5b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16158015610af35750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15610b2a576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615610b6c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055610ba28383613daa565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690559392505050565b600080610be06001841b613b68565b91509150915091565b60008054610100900460ff1615610c2c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314610cb2576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff1615610d8e5773ffffffffffffffffffffffffffffffffffffffff85166000908152600c602052604090205460ff168015610d1e57506001876003811115610d0157610d01615835565b1480610d1e57506002876003811115610d1c57610d1c615835565b145b15610d2c5760039650610d8e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b6000610d9989613bed565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260026020526040812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590915080808080610df486611242565b509094509050610e068c8e8684611608565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b81166004830152939b5093985090955093506000917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48909116906370a0823190602401602060405180830381865afa158015610ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec69190615864565b9050610ed288876158ac565b610edd9060016158ac565b811115610f1d57610f18877f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488d60018c8b870303038d613e1e565b610f67565b610f6773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48168d8960018a8d0186900301614070565b610fb5877f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e4896000613e1e565b6040517fca9505e40000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604481018490527f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff169063ca9505e490606401600060405180830381600087803b15801561104b57600080fd5b505af115801561105f573d6000803e3d6000fd5b5050505050505050600184111561109e5761109e837f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488d876000613e1e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600860205260409020548619166110d38489888461410b565b6040517f89b77b3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000444cd42baeddeb707eed823f7177b9abcc779c0416906389b77b3e90602401600060405180830381600087803b15801561115c57600080fd5b505af1158015611170573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550949c9b505050505050505050505050565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156111ff5750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611236576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61123f816141e5565b50565b600080600080600061125386614257565b919650925090508161126582876158c4565b61126f9190615901565b6001549094506127109061ffff16611287878761593c565b61129191906158c4565b61129b9190615901565b6112a590856158ac565b9496939550505050565b6040517fd4eb5db00000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000523da3a8961e4dd4f6206dbf7e6c749f51796bb373ffffffffffffffffffffffffffffffffffffffff169063d4eb5db090602401602060405180830381865afa158015611339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135d9190615953565b611393576040517f10332dee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139b6143d5565b565b60005460ff1615806113b7575060005462010000900460ff165b61141d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff161561145f576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff908116908416148015906114e15750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b80156115055750600d5473ffffffffffffffffffffffffffffffffffffffff163314155b80611524575073ffffffffffffffffffffffffffffffffffffffff8316155b1561155b576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61156482613d21565b61159a576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115a585613bed565b90506115b58385838560006144b6565b6115d9576115c8838583600060016144b6565b506115d78385838560016144b6565b505b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b6001546000908190819081906127109061ffff16611626888861593c565b61163091906158c4565b61163a9190615901565b61164490866158ac565b9350600187600381111561165a5761165a615835565b14806116775750600287600381111561167557611675615835565b145b806116935750600387600381111561169157611691615835565b145b156117e657600060018860038111156116ae576116ae615835565b141561171457600154612710906116d190640100000000900461ffff168b6158c4565b6116db9190615901565b600154909150612710906116f99062010000900461ffff168b6158c4565b6117039190615901565b61170d90866158ac565b94506117b0565b600288600381111561172857611728615835565b141561177b576001546127109061174f9068010000000000000000900461ffff168b6158c4565b6117599190615901565b600154909150612710906116f9906601000000000000900461ffff168b6158c4565b506001548890612710906117999062010000900461ffff16836158c4565b6117a39190615901565b6117ad90866158ac565b94505b848111156117c55760018582030393506117c9565b8094505b8581106117da5785850392506117e0565b84860391505b506117ec565b84840391505b945094509450949050565b60005460ff161580611811575060005462010000900460ff165b611877576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156118ca5750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611901576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615611943576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556119798282614657565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156119f85750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15611a2f576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615611a71576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055611aa78584614657565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152600091908616906370a0823190602401602060405180830381865afa158015611b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3b9190615864565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529192506000918616906370a0823190602401602060405180830381865afa158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd19190615864565b60015490915060009081906a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16635cecbd0e611c0f868961593c565b8a611c1a898861593c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935273ffffffffffffffffffffffffffffffffffffffff918216602484015260448301528a1660648201526084016040805180830381865afa158015611c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cba9190615970565b9150915060018411611cd257611cd08989613daa565b505b611cdb8761238e565b611ce99061ffff16826158c4565b9050611cf48861238e565b611d029061ffff16836158c4565b9150818110611d1d57611d14896141e5565b505050506115d9565b73ffffffffffffffffffffffffffffffffffffffff891660009081526009602052604081205483611d5a6b033b2e3c9fd0803ce8000000856158c4565b611d649190615901565b611d7a906b033b2e3c9fd0803ce800000061593c565b611d8491906158ac565b60015490915061271090611daf906b033b2e3c9fd0803ce80000009062010000900461ffff166158c4565b611db99190615901565b8111611dfa5773ffffffffffffffffffffffffffffffffffffffff8a166000908152600960205260409020819055611df08a6141e5565b50505050506115d9565b611e038a614707565b50505073ffffffffffffffffffffffffffffffffffffffff871660009081526009602052604090206001905550505050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611eb1576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff909216640100000000027fffffffffffffffff0000000000000000000000000000000000000000ffffffff909216919091179055565b6060611f0e60005460ff1690565b1580611f22575060005462010000900460ff165b611f88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615611fca576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff90811690841614158061203f575073ffffffffffffffffffffffffffffffffffffffff8316155b1561209557600d5473ffffffffffffffffffffffffffffffffffffffff163314612095576040517ffc1a554300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120a085613bed565b90508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167faed1eb34af6acd8c1e3911fb2ebb875a66324b03957886bd002227b17f52ab0360405160405180910390a36040517f1cff79cd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690631cff79cd906121509087908790600401615994565b6000604051808303816000875af115801561216f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526121b591908101906159c3565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905595945050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314612237576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216156122a75773ffffffffffffffffffffffffffffffffffffffff8281166000908152600a6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b73ffffffffffffffffffffffffffffffffffffffff8116156123175773ffffffffffffffffffffffffffffffffffffffff8181166000908152600b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169184169190911790555b73ffffffffffffffffffffffffffffffffffffffff811673cccccccccccccccccccccccccccccccccccccccc141561238a57600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b5050565b60007f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156124125750506001547e01000000000000000000000000000000000000000000000000000000000000900461ffff1690565b600061241d83613d21565b905080612456576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f81613b68565b949350505050565b60005460ff16156124d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612516576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff16331461259c576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125a68383614657565b6125c873ffffffffffffffffffffffffffffffffffffffff8316858584614070565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b6040517f3a41ec640000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000523da3a8961e4dd4f6206dbf7e6c749f51796bb373ffffffffffffffffffffffffffffffffffffffff1690633a41ec6490602401602060405180830381865afa158015612680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a49190615953565b6126da576040517fd794b1e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139b614a7b565b60035473ffffffffffffffffffffffffffffffffffffffff163314612733576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff166000908152600c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805460ff16156127f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612832576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff1633146128b8576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000444cd42baeddeb707eed823f7177b9abcc779c0473ffffffffffffffffffffffffffffffffffffffff166321d18456857f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190615864565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af11580156129e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a059190615a31565b6040517fbf28068b0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff80831660248301529192507f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e49091169063bf28068b90604401600060405180830381600087803b158015612a9a57600080fd5b505af1158015612aae573d6000803e3d6000fd5b50505050612abc8382614b3b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526008602052604081206001905580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690559392505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314612b63576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805461ffff92831668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff9484166601000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff96851664010000000002969096167fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff97851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090931694909816939093171794909416949094179190911716919091179055565b6000805460ff1615612cad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615612cef576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314612d75576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000612d8387614257565b92509250925060008515612e5d57612d9b87856158ac565b9450612dab848884866001614c0e565b6040517fbf28068b0000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff8a811660248301529192507f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e49091169063bf28068b90604401600060405180830381600087803b158015612e4057600080fd5b505af1158015612e54573d6000803e3d6000fd5b505050506132e5565b60008484612e6b85836158c4565b612e759190615901565b612e7f919061593c565b60015490915060009061271090612e9a9061ffff16846158c4565b612ea49190615901565b9050612eb081836158ac565b891061310a578881612ec284896158ac565b612ecc91906158ac565b612ed6919061593c565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301527f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e481166024830152604482018c9052919850908b169063d1660f9990606401600060405180830381600087803b158015612f9257600080fd5b505af1158015612fa6573d6000803e3d6000fd5b505050507f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff1663ca9505e482848c612ff3919061593c565b612ffd919061593c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260048101919091526024810184905260006044820152606401600060405180830381600087803b15801561305c57600080fd5b505af1158015613070573d6000803e3d6000fd5b505050507f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131039190615864565b92506132e2565b6001546000906131209061ffff16612710615a4e565b61ffff166131306127108c6158c4565b61313a9190615901565b90506000613148828c61593c565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301527f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e481166024830152604482018e9052999a508a99919250908d169063d1660f9990606401600060405180830381600087803b15801561320957600080fd5b505af115801561321d573d6000803e3d6000fd5b50506040517fca9505e40000000000000000000000000000000000000000000000000000000081526000600482018190526024820185905260448201527f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff16925063ca9505e49150606401600060405180830381600087803b1580156132b757600080fd5b505af11580156132cb573d6000803e3d6000fd5b505050506132dd8883888a6000614c0e565b945050505b50505b6040517f16128211000000000000000000000000000000000000000000000000000000008152600481018690526024810182905273ffffffffffffffffffffffffffffffffffffffff891690631612821190604401600060405180830381600087803b15801561335457600080fd5b505af1158015613368573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055509498975050505050505050565b336000908152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff161580156133f35750600054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314155b1561342a576040517fad40d9e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff161561346c576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556134a181614707565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60035473ffffffffffffffffffffffffffffffffffffffff16331461351d576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517ff62005acebe9b616aefb5f248b48f5e89f28437b27d1eebc0b2d911209f297af90600090a250565b60035473ffffffffffffffffffffffffffffffffffffffff1633146135dd576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600755565b60035473ffffffffffffffffffffffffffffffffffffffff163314613633576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff166000908152600c6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60035473ffffffffffffffffffffffffffffffffffffffff1633146136d0576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415613777576001805461ffff83167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790555050565b600061378283613d21565b9050806137bb576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff1675ffff000000000000000000000000000000000000000060a084901b161790555050565b60035473ffffffffffffffffffffffffffffffffffffffff163314613856576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61123f81614cf4565b60035473ffffffffffffffffffffffffffffffffffffffff1633146138b0576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460ff9092166301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b60035473ffffffffffffffffffffffffffffffffffffffff16331461393c576040517feee4716900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff9092166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff909216919091179055565b60005460ff1615806139ab575060005462010000900460ff165b613a11576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600054610100900460ff1615613a53576040517f69bc183d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790819055640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613ad9576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613ae483613bed565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559050613b3b8282614b3b565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b6000808260011415613bc65750506001547f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48927e0100000000000000000000000000000000000000000000000000000000000090910461ffff169150565b600083815260046020526040902054915081613be560a082901c614de8565b915050915091565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600260205260409020541680613c4c576040517fb5ba4c4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60008054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613cab576040517fd8026b2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff16808015613ce3575073ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604090205460ff165b15613d1a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000851515021790555b9392505050565b60007f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614613da15773ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040902054613da4565b60015b92915050565b600080613db683613d21565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260086020526040902054909150811615613e175773ffffffffffffffffffffffffffffffffffffffff8416600090815260086020526040902080548219169055600191505b5092915050565b808015613e7657507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b15613fd8576040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f0000000000000000000000004f952c4c5415b2609899abdc2f8f352f600d14d6811660248301526044820184905286169063d1660f9990606401600060405180830381600087803b158015613f1357600080fd5b505af1158015613f27573d6000803e3d6000fd5b50506040517f5869dba800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018690527f0000000000000000000000004f952c4c5415b2609899abdc2f8f352f600d14d6169250635869dba89150604401600060405180830381600087803b158015613fbb57600080fd5b505af1158015613fcf573d6000803e3d6000fd5b50505050614069565b6040517fd1660f9900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015284811660248301526044820184905286169063d1660f9990606401600060405180830381600087803b15801561405057600080fd5b505af1158015614064573d6000803e3d6000fd5b505050505b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052614105908590614e80565b50505050565b60025b81811161406957818116156141dd57600061412882613b68565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561419b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141bf9190615864565b905060018111156141da576141da8783886001850389613e1e565b50505b60011b61410e565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600860205260408120549061421582614f8c565b6000549091506301000000900460ff1681111561425257600061423783614fa2565b6142429060016158ac565b905061410584848460008561500d565b505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff16631afbb7a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142cb9190615864565b92508373ffffffffffffffffffffffffffffffffffffffff166317d11a156040518163ffffffff1660e01b8152600401602060405180830381865afa158015614318573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433c9190615864565b91507f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e473ffffffffffffffffffffffffffffffffffffffff16630fce70fb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143cd9190615864565b929491935050565b60005460ff16614441576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a97565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6040805173ffffffffffffffffffffffffffffffffffffffff8681166024830152604480830186905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905291517f1cff79cd000000000000000000000000000000000000000000000000000000008152600092861691631cff79cd91614577918a91600401615994565b6000604051808303816000875af19250505080156145d557506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526145d291908101906159c3565b60015b6145de57614612565b805115806146015750808060200190518101906145fb9190615953565b15156001145b1561461057600191505061464e565b505b811561464a576040517f2f10a7f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060005b95945050505050565b600061466282613d21565b90508015806146745750600754811615155b156146ab576040517f700ca0af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526008602052604090205481166142525773ffffffffffffffffffffffffffffffffffffffff83166000908152600860205260409020805482179055505050565b60015473ffffffffffffffffffffffffffffffffffffffff8281166000908152600860205260408120546a01000000000000000000009093049091169190808061475086611242565b6040517ff9a650300000000000000000000000000000000000000000000000000000000081526127108202600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881166024830152919450908816925063f9a650309150604401602060405180830381865afa1580156147ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148109190615864565b925061481b84614fa2565b6001019150506000806000805b84811015614a485780156148415760018186031b614844565b60015b935086841615614a405760008061485a86613b68565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e811660048301529294509092506000918416906370a0823190602401602060405180830381865afa1580156148cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f39190615864565b90506001811115614a33576040517ff9a650300000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff848116602483015261ffff841691908d169063f9a6503090604401602060405180830381865afa158015614978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061499c9190615864565b6149a691906158c4565b6149b090876158ac565b9550888610614a2e5760006149c48b614f8c565b6000549091506301000000900460ff168111156149f0576149eb8d8c836001898e0361500d565b614a1f565b8515614a1f5773ffffffffffffffffffffffffffffffffffffffff8d1660009081526008602052604090208b90555b50505050505050505050505050565b614a3c565b98861898600194505b5050505b600101614828565b506040517f532e7bb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff1615614ae8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a97565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861448c3390565b73ffffffffffffffffffffffffffffffffffffffff82161580614b84575073ffffffffffffffffffffffffffffffffffffffff8281166000908152600260205260409020541615155b15614bbb576040517f9e59609e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60008115614c8b576000614c2286886158ac565b9050614c3286633b9aca006158c4565b8488614c4288633b9aca006158c4565b614c4c91906158c4565b614c569190615901565b614c6091906158ac565b633b9aca00614c6f83886158c4565b614c7991906158c4565b614c839190615901565b91505061464e565b8583614c9b87633b9aca006158c4565b614ca591906158c4565b614caf9190615901565b614cbd85633b9aca006158c4565b614cc7919061593c565b83614cd686633b9aca006158c4565b614ce091906158c4565b614cea9190615901565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205415614d51576040517f2e5a5c7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010060055410614d8e576040517f7e050c5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff83166000818152600660209081526040808320600190951b9485905584835260049091528120919091558254919290614ddf83615a74565b91905055505050565b600061ffff821115614e7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610a97565b5090565b6000614ee2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661517c9092919063ffffffff16565b8051909150156142525780806020019051810190614f009190615953565b614252576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a97565b60005b8115613c4c57600182811c921601614f8f565b60008160011415614fb557506000919050565b61010060015b6001614fc782846158ac565b901c92506001831b84811615801590614fe25750600185851c145b15614fed5750615006565b848110614ffc57839250615000565b8391505b50614fbb565b5050919050565b815b81811015615149576001811b8581161561514057600061502e82613b68565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529192506000918316906370a0823190602401602060405180830381865afa1580156150a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150c59190615864565b90506001811161513d57600054978318977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9097019660ff630100000090910416871161513d5750505073ffffffffffffffffffffffffffffffffffffffff8616600090815260086020526040902085905550614069565b50505b5060010161500f565b506040517f30b5495c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061245f848460008585843b6151ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a97565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516152189190615aad565b60006040518083038185875af1925050503d8060008114615255576040519150601f19603f3d011682016040523d82523d6000602084013e61525a565b606091505b509150915061526a828286615275565b979650505050505050565b60608315615284575081613d1a565b8251156152945782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9791906156be565b73ffffffffffffffffffffffffffffffffffffffff8116811461123f57600080fd5b6000602082840312156152fc57600080fd5b8135613d1a816152c8565b6000806040838503121561531a57600080fd5b8235615325816152c8565b91506020830135615335816152c8565b809150509250929050565b60006020828403121561535257600080fd5b5035919050565b803560048110613c4c57600080fd5b801515811461123f57600080fd5b600080600080600080600060e0888a03121561539157600080fd5b873561539c816152c8565b96506153aa60208901615359565b95506040880135945060608801356153c1816152c8565b935060808801356153d1816152c8565b925060a0880135915060c08801356153e881615368565b8091505092959891949750929550565b6000806000806080858703121561540e57600080fd5b8435615419816152c8565b93506020850135615429816152c8565b92506040850135615439816152c8565b9396929550929360600135925050565b6000806000806080858703121561545f57600080fd5b8435935061546f60208601615359565b93969395505050506040820135916060013590565b600080600080600060a0868803121561549c57600080fd5b85356154a7816152c8565b945060208601356154b7816152c8565b935060408601356154c7816152c8565b94979396509394606081013594506080013592915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615555576155556154df565b604052919050565b600067ffffffffffffffff821115615577576155776154df565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806000606084860312156155b857600080fd5b83356155c3816152c8565b925060208401356155d3816152c8565b9150604084013567ffffffffffffffff8111156155ef57600080fd5b8401601f8101861361560057600080fd5b803561561361560e8261555d565b61550e565b81815287602083850101111561562857600080fd5b816020840160208301376000602083830101528093505050509250925092565b60005b8381101561566357818101518382015260200161564b565b838111156141055750506000910152565b6000815180845261568c816020860160208601615648565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613d1a6020830184615674565b600080604083850312156156e457600080fd5b823591506020830135615335816152c8565b803561ffff81168114613c4c57600080fd5b600080600080600060a0868803121561572057600080fd5b615729866156f6565b9450615737602087016156f6565b9350615745604087016156f6565b9250615753606087016156f6565b9150615761608087016156f6565b90509295509295909350565b60008060006060848603121561578257600080fd5b833561578d816152c8565b92506020840135915060408401356157a481615368565b809150509250925092565b600080604083850312156157c257600080fd5b82356157cd816152c8565b91506157db602084016156f6565b90509250929050565b6000602082840312156157f657600080fd5b813560ff81168114613d1a57600080fd5b6000806040838503121561581a57600080fd5b8235615825816152c8565b9150602083013561533581615368565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020828403121561587657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156158bf576158bf61587d565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156158fc576158fc61587d565b500290565b600082615937577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008282101561594e5761594e61587d565b500390565b60006020828403121561596557600080fd5b8151613d1a81615368565b6000806040838503121561598357600080fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061245f6040830184615674565b6000602082840312156159d557600080fd5b815167ffffffffffffffff8111156159ec57600080fd5b8201601f810184136159fd57600080fd5b8051615a0b61560e8261555d565b818152856020838501011115615a2057600080fd5b61464e826020830160208601615648565b600060208284031215615a4357600080fd5b8151613d1a816152c8565b600061ffff808316818516808303821115615a6b57615a6b61587d565b01949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615aa657615aa661587d565b5060010190565b60008251615abf818460208701615648565b919091019291505056fea264697066735822122098b131e40cdbeea1a6bd054f778411777fdf344e5f59e80117d76e3db0455f4264736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e4
-----Decoded View---------------
Arg [0] : _pool (address): 0x86130bDD69143D8a4E5fc50bf4323D48049E98E4
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e4
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
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.