Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
9780504 | 12 hrs ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
CreditFacadeV3
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; // THIRD-PARTY import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; // LIBS & TRAITS import {BalancesLogic, Balance, BalanceDelta, BalanceWithMask, Comparison} from "../libraries/BalancesLogic.sol"; import {ACLNonReentrantTrait} from "../traits/ACLNonReentrantTrait.sol"; import {BitMask, UNDERLYING_TOKEN_MASK} from "../libraries/BitMask.sol"; // INTERFACES import "../interfaces/ICreditFacadeV3.sol"; import "../interfaces/IAddressProviderV3.sol"; import { ICreditManagerV3, ManageDebtAction, RevocationPair, CollateralDebtData, CollateralCalcTask, BOT_PERMISSIONS_SET_FLAG, INACTIVE_CREDIT_ACCOUNT_ADDRESS } from "../interfaces/ICreditManagerV3.sol"; import {AllowanceAction} from "../interfaces/ICreditConfiguratorV3.sol"; import {IPriceOracleV3} from "../interfaces/IPriceOracleV3.sol"; import {IUpdatablePriceFeed} from "@gearbox-protocol/core-v2/contracts/interfaces/IPriceFeed.sol"; import {IPoolV3} from "../interfaces/IPoolV3.sol"; import {IDegenNFTV2} from "@gearbox-protocol/core-v2/contracts/interfaces/IDegenNFTV2.sol"; import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; import {IBotListV3} from "../interfaces/IBotListV3.sol"; // CONSTANTS import {PERCENTAGE_FACTOR} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; // EXCEPTIONS import "../interfaces/IExceptions.sol"; uint256 constant OPEN_CREDIT_ACCOUNT_FLAGS = ALL_PERMISSIONS & ~DECREASE_DEBT_PERMISSION; uint256 constant CLOSE_CREDIT_ACCOUNT_FLAGS = ALL_PERMISSIONS & ~INCREASE_DEBT_PERMISSION; uint256 constant LIQUIDATE_CREDIT_ACCOUNT_FLAGS = EXTERNAL_CALLS_PERMISSION | ADD_COLLATERAL_PERMISSION | WITHDRAW_COLLATERAL_PERMISSION; /// @title Credit facade V3 /// @notice Provides a user interface to open, close and liquidate leveraged positions in the credit manager, /// and implements the main entry-point for credit accounts management: multicall. /// @notice Multicall allows account owners to batch all the desired operations (adding or withdrawing collateral, /// changing debt size, interacting with external protocols via adapters or increasing quotas) into one call, /// followed by the collateral check that ensures that account is sufficiently collateralized. /// For more details on what one can achieve with multicalls, see `_multicall` and `ICreditFacadeV3Multicall`. /// @notice Users can also let external bots manage their accounts via `botMulticall`. Bots can be relatively general, /// the facade only ensures that they can do no harm to the protocol by running the collateral check after the /// multicall and checking the permissions given to them by users. See `BotListV3` for additional details. /// @notice Credit facade implements a few safeguards on top of those present in the credit manager, including debt and /// quota size validation, pausing on large protocol losses, Degen NFT whitelist mode, and forbidden tokens /// (they count towards account value, but having them enabled as collateral restricts available actions and /// activates a safer version of collateral check). contract CreditFacadeV3 is ICreditFacadeV3, ACLNonReentrantTrait { using Address for address; using Address for address payable; using BitMask for uint256; using SafeCast for uint256; using SafeERC20 for IERC20; /// @notice Contract version uint256 public constant override version = 3_01; /// @notice Maximum quota size, as a multiple of `maxDebt` uint256 public constant override maxQuotaMultiplier = 2; /// @notice Credit manager connected to this credit facade address public immutable override creditManager; /// @notice Whether credit facade is expirable bool public immutable override expirable; /// @notice WETH token address address public immutable override weth; /// @notice Degen NFT address address public immutable override degenNFT; /// @notice Expiration timestamp uint40 public override expirationDate; /// @notice Maximum amount that can be borrowed by a credit manager in a single block, as a multiple of `maxDebt` uint8 public override maxDebtPerBlockMultiplier; /// @notice Last block when underlying was borrowed by a credit manager uint64 internal lastBlockBorrowed; /// @notice The total amount borrowed by a credit manager in `lastBlockBorrowed` uint128 internal totalBorrowedInBlock; /// @notice Bot list address address public override botList; /// @notice Credit account debt limits packed into a single slot DebtLimits public override debtLimits; /// @notice Bit mask encoding a set of forbidden tokens uint256 public override forbiddenTokenMask; /// @notice Info on bad debt liquidation losses packed into a single slot CumulativeLossParams public override lossParams; /// @notice Mapping account => emergency liquidator status mapping(address => bool) public override canLiquidateWhilePaused; /// @dev Ensures that function caller is credit configurator modifier creditConfiguratorOnly() { _checkCreditConfigurator(); _; } /// @dev Ensures that function caller is `creditAccount`'s owner modifier creditAccountOwnerOnly(address creditAccount) { _checkCreditAccountOwner(creditAccount); _; } /// @dev Ensures that function can't be called when the contract is paused, unless caller is an emergency liquidator modifier whenNotPausedOrEmergency() { require(!paused() || canLiquidateWhilePaused[msg.sender], "Pausable: paused"); _; } /// @dev Ensures that function can't be called when the contract is expired modifier whenNotExpired() { _checkExpired(); _; } /// @dev Wraps any ETH sent in a function call and sends it back to the caller modifier wrapETH() { _wrapETH(); _; } /// @notice Constructor /// @param _creditManager Credit manager to connect this facade to /// @param _degenNFT Degen NFT address or `address(0)` /// @param _expirable Whether this facade should be expirable constructor(address _creditManager, address _degenNFT, bool _expirable) ACLNonReentrantTrait(ICreditManagerV3(_creditManager).addressProvider()) { creditManager = _creditManager; // U:[FA-1] address addressProvider = ICreditManagerV3(_creditManager).addressProvider(); weth = IAddressProviderV3(addressProvider).getAddressOrRevert(AP_WETH_TOKEN, NO_VERSION_CONTROL); // U:[FA-1] botList = IAddressProviderV3(addressProvider).getAddressOrRevert(AP_BOT_LIST, 3_00); // U:[FA-1] degenNFT = _degenNFT; // U:[FA-1] expirable = _expirable; // U:[FA-1] } // ------------------ // // ACCOUNT MANAGEMENT // // ------------------ // /// @notice Opens a new credit account /// - Wraps any ETH sent in the function call and sends it back to the caller /// - If Degen NFT is enabled, burns one from the caller /// - Opens an account in the credit manager /// - Performs a multicall (all calls allowed except debt decrease and withdrawals) /// - Runs the collateral check /// @param onBehalfOf Address on whose behalf to open the account /// @param calls List of calls to perform after opening the account /// @param referralCode Referral code to use for potential rewards, 0 if no referral code is provided /// @return creditAccount Address of the newly opened account /// @dev Reverts if credit facade is paused or expired /// @dev Reverts if `onBehalfOf` is not caller while Degen NFT is enabled function openCreditAccount(address onBehalfOf, MultiCall[] calldata calls, uint256 referralCode) external payable override whenNotPaused // U:[FA-2] whenNotExpired // U:[FA-3] nonReentrant // U:[FA-4] wrapETH // U:[FA-7] returns (address creditAccount) { if (degenNFT != address(0)) { if (msg.sender != onBehalfOf) { revert ForbiddenInWhitelistedModeException(); // U:[FA-9] } IDegenNFTV2(degenNFT).burn(onBehalfOf, 1); // U:[FA-9] } creditAccount = ICreditManagerV3(creditManager).openCreditAccount({onBehalfOf: onBehalfOf}); // U:[FA-10] emit OpenCreditAccount(creditAccount, onBehalfOf, msg.sender, referralCode); // U:[FA-10] if (calls.length != 0) { // same as `_multicallFullCollateralCheck` but leverages the fact that account is freshly opened to save gas BalanceWithMask[] memory forbiddenBalances; uint256 skipCalls = _applyOnDemandPriceUpdates(calls); FullCheckParams memory fullCheckParams = _multicall({ creditAccount: creditAccount, calls: calls, enabledTokensMask: 0, flags: OPEN_CREDIT_ACCOUNT_FLAGS, skip: skipCalls }); // U:[FA-10] _fullCollateralCheck({ creditAccount: creditAccount, enabledTokensMaskBefore: 0, fullCheckParams: fullCheckParams, forbiddenBalances: forbiddenBalances, forbiddenTokensMask: forbiddenTokenMask }); // U:[FA-10] } } /// @notice Closes a credit account /// - Wraps any ETH sent in the function call and sends it back to the caller /// - Performs a multicall (all calls are allowed except debt increase) /// - Closes a credit account in the credit manager /// - Erases all bots permissions /// @param creditAccount Account to close /// @param calls List of calls to perform before closing the account /// @dev Reverts if `creditAccount` is not opened in connected credit manager by caller /// @dev Reverts if facade is paused /// @dev Reverts if account has enabled tokens after executing `calls` /// @dev Reverts if account's debt is not zero after executing `calls` function closeCreditAccount(address creditAccount, MultiCall[] calldata calls) external payable override creditAccountOwnerOnly(creditAccount) // U:[FA-5] whenNotPaused // U:[FA-2] nonReentrant // U:[FA-4] wrapETH // U:[FA-7] { uint256 enabledTokensMask = _enabledTokensMaskOf(creditAccount); if (calls.length != 0) { FullCheckParams memory fullCheckParams = _multicall(creditAccount, calls, enabledTokensMask, CLOSE_CREDIT_ACCOUNT_FLAGS, 0); // U:[FA-11] enabledTokensMask = fullCheckParams.enabledTokensMaskAfter; } if (enabledTokensMask != 0) revert CloseAccountWithEnabledTokensException(); // U:[FA-11] if (_flagsOf(creditAccount) & BOT_PERMISSIONS_SET_FLAG != 0) { IBotListV3(botList).eraseAllBotPermissions(creditManager, creditAccount); // U:[FA-11] } ICreditManagerV3(creditManager).closeCreditAccount(creditAccount); // U:[FA-11] emit CloseCreditAccount(creditAccount, msg.sender); // U:[FA-11] } /// @notice Liquidates a credit account /// - Updates price feeds before running all computations if such calls are present in the multicall /// - Evaluates account's collateral and debt to determine whether liquidated account is unhealthy or expired /// - Performs a multicall (only `addCollateral`, `withdrawCollateral` and adapter calls are allowed) /// - Liquidates a credit account in the credit manager, which repays debt to the pool, removes quotas, and /// transfers underlying to the liquidator /// - If pool incurs a loss on liquidation, further borrowing through the facade is forbidden /// - If cumulative loss from bad debt liquidations exceeds the threshold, the facade is paused /// @notice The function computes account’s total value (oracle value of enabled tokens), discounts it by liquidator’s /// premium, and uses this value to compute funds due to the pool and owner. /// Debt to the pool must be repaid in underlying, while funds due to owner might be covered by underlying /// as well as by tokens that counted towards total value calculation, with the only condition that balance /// of such tokens can’t be increased in the multicall. /// Typically, a liquidator would swap all holdings on the account to underlying via multicall and receive /// the premium in underlying. /// An alternative strategy would be to add underlying collateral to repay debt and withdraw desired tokens /// to handle them in another way, while remaining tokens would cover funds due to owner. /// @param creditAccount Account to liquidate /// @param to Address to transfer underlying left after liquidation /// @param calls List of calls to perform before liquidating the account /// @dev When the credit facade is paused, reverts if caller is not an approved emergency liquidator /// @dev Reverts if `creditAccount` is not opened in connected credit manager /// @dev Reverts if account has no debt or is neither unhealthy nor expired /// @dev Reverts if remaining token balances increase during the multicall function liquidateCreditAccount(address creditAccount, address to, MultiCall[] calldata calls) external override whenNotPausedOrEmergency // U:[FA-2,12] nonReentrant // U:[FA-4] { uint256 skipCalls = _applyOnDemandPriceUpdates(calls); CollateralDebtData memory collateralDebtData = ICreditManagerV3(creditManager).calcDebtAndCollateral(creditAccount, CollateralCalcTask.DEBT_COLLATERAL); // U:[FA-16] bool isUnhealthy = collateralDebtData.twvUSD < collateralDebtData.totalDebtUSD; if (collateralDebtData.debt == 0 || !isUnhealthy && !_isExpired()) { revert CreditAccountNotLiquidatableException(); // U:[FA-13] } collateralDebtData.enabledTokensMask = collateralDebtData.enabledTokensMask.disable(UNDERLYING_TOKEN_MASK); // U:[FA-14] BalanceWithMask[] memory initialBalances = BalancesLogic.storeBalances({ creditAccount: creditAccount, tokensMask: collateralDebtData.enabledTokensMask, getTokenByMaskFn: _getTokenByMask }); FullCheckParams memory fullCheckParams = _multicall( creditAccount, calls, collateralDebtData.enabledTokensMask, LIQUIDATE_CREDIT_ACCOUNT_FLAGS, skipCalls ); // U:[FA-16] collateralDebtData.enabledTokensMask &= fullCheckParams.enabledTokensMaskAfter; // U:[FA-16] bool success = BalancesLogic.compareBalances({ creditAccount: creditAccount, tokensMask: collateralDebtData.enabledTokensMask, balances: initialBalances, comparison: Comparison.LESS }); if (!success) revert RemainingTokenBalanceIncreasedException(); // U:[FA-14] collateralDebtData.enabledTokensMask = collateralDebtData.enabledTokensMask.enable(UNDERLYING_TOKEN_MASK); // U:[FA-16] (uint256 remainingFunds, uint256 reportedLoss) = ICreditManagerV3(creditManager).liquidateCreditAccount({ creditAccount: creditAccount, collateralDebtData: collateralDebtData, to: to, isExpired: !isUnhealthy }); // U:[FA-15,16] emit LiquidateCreditAccount(creditAccount, msg.sender, to, remainingFunds); // U:[FA-16] if (reportedLoss != 0) { maxDebtPerBlockMultiplier = 0; // U:[FA-17] // both cast and addition are safe because amounts are of much smaller scale lossParams.currentCumulativeLoss += uint128(reportedLoss); // U:[FA-17] // can't pause an already paused contract if (!paused() && lossParams.currentCumulativeLoss > lossParams.maxCumulativeLoss) { _pause(); // U:[FA-17] } } } /// @notice Executes a batch of calls allowing user to manage their credit account /// - Wraps any ETH sent in the function call and sends it back to the caller /// - Performs a multicall (all calls are allowed) /// - Runs the collateral check /// @param creditAccount Account to perform the calls on /// @param calls List of calls to perform /// @dev Reverts if `creditAccount` is not opened in connected credit manager by caller /// @dev Reverts if credit facade is paused or expired function multicall(address creditAccount, MultiCall[] calldata calls) external payable override creditAccountOwnerOnly(creditAccount) // U:[FA-5] whenNotPaused // U:[FA-2] whenNotExpired // U:[FA-3] nonReentrant // U:[FA-4] wrapETH // U:[FA-7] { _multicallFullCollateralCheck(creditAccount, calls, ALL_PERMISSIONS); // U:[FA-18] } /// @notice Executes a batch of calls allowing bot to manage a credit account /// - Performs a multicall (allowed calls are determined by permissions given by account's owner /// or by DAO in case bot has special permissions in the credit manager) /// - Runs the collateral check /// @param creditAccount Account to perform the calls on /// @param calls List of calls to perform /// @dev Reverts if credit facade is paused or expired /// @dev Reverts if `creditAccount` is not opened in connected credit manager /// @dev Reverts if calling bot is forbidden or has no permissions to manage `creditAccount` function botMulticall(address creditAccount, MultiCall[] calldata calls) external override whenNotPaused // U:[FA-2] whenNotExpired // U:[FA-3] nonReentrant // U:[FA-4] { _getBorrowerOrRevert(creditAccount); // U:[FA-5] (uint256 botPermissions, bool forbidden, bool hasSpecialPermissions) = IBotListV3(botList).getBotStatus({ bot: msg.sender, creditManager: creditManager, creditAccount: creditAccount }); if ( botPermissions == 0 || forbidden || (!hasSpecialPermissions && (_flagsOf(creditAccount) & BOT_PERMISSIONS_SET_FLAG == 0)) ) { revert NotApprovedBotException(); // U:[FA-19] } _multicallFullCollateralCheck(creditAccount, calls, botPermissions); // U:[FA-19, 20] } /// @notice Sets `bot`'s permissions to manage `creditAccount` /// @param creditAccount Account to set permissions for /// @param bot Bot to set permissions for /// @param permissions A bit mask encoding bot permissions /// @dev Reverts if `creditAccount` is not opened in connected credit manager by caller /// @dev Reverts if `permissions` has unexpected bits enabled /// @dev Reverts if account has more active bots than allowed after changing permissions /// @dev Changes account's `BOT_PERMISSIONS_SET_FLAG` in the credit manager if needed function setBotPermissions(address creditAccount, address bot, uint192 permissions) external override creditAccountOwnerOnly(creditAccount) // U:[FA-5] nonReentrant // U:[FA-4] { if (permissions & ~ALL_PERMISSIONS != 0) revert UnexpectedPermissionsException(); // U:[FA-41] uint256 remainingBots = IBotListV3(botList).setBotPermissions({ bot: bot, creditManager: creditManager, creditAccount: creditAccount, permissions: permissions }); // U:[FA-41] if (remainingBots == 0) { _setFlagFor({creditAccount: creditAccount, flag: BOT_PERMISSIONS_SET_FLAG, value: false}); // U:[FA-41] } else if (_flagsOf(creditAccount) & BOT_PERMISSIONS_SET_FLAG == 0) { _setFlagFor({creditAccount: creditAccount, flag: BOT_PERMISSIONS_SET_FLAG, value: true}); // U:[FA-41] } } // --------- // // MULTICALL // // --------- // /// @dev Batches price feed updates, multicall and collateral check into a single function function _multicallFullCollateralCheck(address creditAccount, MultiCall[] calldata calls, uint256 flags) internal { uint256 forbiddenTokensMask = forbiddenTokenMask; uint256 enabledTokensMaskBefore = _enabledTokensMaskOf(creditAccount); // U:[FA-18] BalanceWithMask[] memory forbiddenBalances = BalancesLogic.storeBalances({ creditAccount: creditAccount, tokensMask: forbiddenTokensMask & enabledTokensMaskBefore, getTokenByMaskFn: _getTokenByMask }); uint256 skipCalls = _applyOnDemandPriceUpdates(calls); FullCheckParams memory fullCheckParams = _multicall( creditAccount, calls, enabledTokensMaskBefore, forbiddenBalances.length != 0 ? flags.enable(FORBIDDEN_TOKENS_BEFORE_CALLS) : flags, skipCalls ); _fullCollateralCheck({ creditAccount: creditAccount, enabledTokensMaskBefore: enabledTokensMaskBefore, fullCheckParams: fullCheckParams, forbiddenBalances: forbiddenBalances, forbiddenTokensMask: forbiddenTokensMask }); // U:[FA-18] } /// @dev Multicall implementation /// @param creditAccount Account to perform actions with /// @param calls Array of `(target, callData)` tuples representing a sequence of calls to perform /// - if `target` is this contract's address, `callData` must be an ABI-encoded calldata of a method /// from `ICreditFacadeV3Multicall`, which is dispatched and handled appropriately /// - otherwise, `target` must be an allowed adapter, which is called with `callData`, and is expected to /// return two ABI-encoded `uint256` masks of tokens that should be enabled/disabled after the call /// @param enabledTokensMask Bitmask of account's enabled collateral tokens before the multicall /// @param flags Permissions and flags that dictate what methods can be called /// @param skip The number of calls that can be skipped (see `_applyOnDemandPriceUpdates`) /// @return fullCheckParams Collateral check parameters, see `FullCheckParams` for details function _multicall( address creditAccount, MultiCall[] calldata calls, uint256 enabledTokensMask, uint256 flags, uint256 skip ) internal returns (FullCheckParams memory fullCheckParams) { emit StartMultiCall({creditAccount: creditAccount, caller: msg.sender}); // U:[FA-18] uint256 quotedTokensMaskInverted; Balance[] memory expectedBalances; fullCheckParams.minHealthFactor = PERCENTAGE_FACTOR; unchecked { uint256 len = calls.length; for (uint256 i = skip; i < len; ++i) { MultiCall calldata mcall = calls[i]; // credit facade calls if (mcall.target == address(this)) { bytes4 method = bytes4(mcall.callData); // storeExpectedBalances if (method == ICreditFacadeV3Multicall.storeExpectedBalances.selector) { if (expectedBalances.length != 0) revert ExpectedBalancesAlreadySetException(); // U:[FA-23] BalanceDelta[] memory balanceDeltas = abi.decode(mcall.callData[4:], (BalanceDelta[])); // U:[FA-23] expectedBalances = BalancesLogic.storeBalances(creditAccount, balanceDeltas); // U:[FA-23] } // compareBalances else if (method == ICreditFacadeV3Multicall.compareBalances.selector) { if (expectedBalances.length == 0) revert ExpectedBalancesNotSetException(); // U:[FA-23] if (!BalancesLogic.compareBalances(creditAccount, expectedBalances, Comparison.GREATER)) { revert BalanceLessThanExpectedException(); // U:[FA-23] } expectedBalances = new Balance[](0); // U:[FA-23] } // addCollateral else if (method == ICreditFacadeV3Multicall.addCollateral.selector) { _revertIfNoPermission(flags, ADD_COLLATERAL_PERMISSION); // U:[FA-21] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.enable({ bitsToEnable: _addCollateral(creditAccount, mcall.callData[4:]), invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-26] } // addCollateralWithPermit else if (method == ICreditFacadeV3Multicall.addCollateralWithPermit.selector) { _revertIfNoPermission(flags, ADD_COLLATERAL_PERMISSION); // U:[FA-21] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.enable({ bitsToEnable: _addCollateralWithPermit(creditAccount, mcall.callData[4:]), invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-26B] } // updateQuota else if (method == ICreditFacadeV3Multicall.updateQuota.selector) { _revertIfNoPermission(flags, UPDATE_QUOTA_PERMISSION); // U:[FA-21] (uint256 tokensToEnable, uint256 tokensToDisable) = _updateQuota(creditAccount, mcall.callData[4:], flags & FORBIDDEN_TOKENS_BEFORE_CALLS != 0); // U:[FA-34] enabledTokensMask = enabledTokensMask.enableDisable(tokensToEnable, tokensToDisable); // U:[FA-34] } // withdrawCollateral else if (method == ICreditFacadeV3Multicall.withdrawCollateral.selector) { _revertIfNoPermission(flags, WITHDRAW_COLLATERAL_PERMISSION); // U:[FA-21] fullCheckParams.revertOnForbiddenTokens = true; // U:[FA-30] fullCheckParams.useSafePrices = true; uint256 tokensToDisable = _withdrawCollateral(creditAccount, mcall.callData[4:]); // U:[FA-34] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.disable({ bitsToDisable: tokensToDisable, invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-35] } // increaseDebt else if (method == ICreditFacadeV3Multicall.increaseDebt.selector) { _revertIfNoPermission(flags, INCREASE_DEBT_PERMISSION); // U:[FA-21] fullCheckParams.revertOnForbiddenTokens = true; // U:[FA-30] (uint256 tokensToEnable,) = _manageDebt( creditAccount, mcall.callData[4:], enabledTokensMask, ManageDebtAction.INCREASE_DEBT ); // U:[FA-27] enabledTokensMask = enabledTokensMask.enable(tokensToEnable); // U:[FA-27] } // decreaseDebt else if (method == ICreditFacadeV3Multicall.decreaseDebt.selector) { _revertIfNoPermission(flags, DECREASE_DEBT_PERMISSION); // U:[FA-21] (, uint256 tokensToDisable) = _manageDebt( creditAccount, mcall.callData[4:], enabledTokensMask, ManageDebtAction.DECREASE_DEBT ); // U:[FA-31] enabledTokensMask = enabledTokensMask.disable(tokensToDisable); // U:[FA-31] } // setFullCheckParams else if (method == ICreditFacadeV3Multicall.setFullCheckParams.selector) { (fullCheckParams.collateralHints, fullCheckParams.minHealthFactor) = abi.decode(mcall.callData[4:], (uint256[], uint16)); // U:[FA-24] if (fullCheckParams.minHealthFactor < PERCENTAGE_FACTOR) { revert CustomHealthFactorTooLowException(); // U:[FA-24] } uint256 hintsLen = fullCheckParams.collateralHints.length; for (uint256 j; j < hintsLen; ++j) { uint256 mask = fullCheckParams.collateralHints[j]; if (mask == 0 || mask & mask - 1 != 0) revert InvalidCollateralHintException(); // U:[FA-24] } } // enableToken else if (method == ICreditFacadeV3Multicall.enableToken.selector) { _revertIfNoPermission(flags, ENABLE_TOKEN_PERMISSION); // U:[FA-21] address token = abi.decode(mcall.callData[4:], (address)); // U:[FA-33] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.enable({ bitsToEnable: _getTokenMaskOrRevert(token), invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-33] } // disableToken else if (method == ICreditFacadeV3Multicall.disableToken.selector) { _revertIfNoPermission(flags, DISABLE_TOKEN_PERMISSION); // U:[FA-21] address token = abi.decode(mcall.callData[4:], (address)); // U:[FA-33] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.disable({ bitsToDisable: _getTokenMaskOrRevert(token), invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-33] } // revokeAdapterAllowances else if (method == ICreditFacadeV3Multicall.revokeAdapterAllowances.selector) { _revertIfNoPermission(flags, REVOKE_ALLOWANCES_PERMISSION); // U:[FA-21] _revokeAdapterAllowances(creditAccount, mcall.callData[4:]); // U:[FA-36] } // unknown method else { revert UnknownMethodException(); // U:[FA-22] } } // adapter calls else { _revertIfNoPermission(flags, EXTERNAL_CALLS_PERMISSION); // U:[FA-21] bytes memory result; { address targetContract = ICreditManagerV3(creditManager).adapterToContract(mcall.target); if (targetContract == address(0)) { revert TargetContractNotAllowedException(); } if (flags & EXTERNAL_CONTRACT_WAS_CALLED == 0) { flags = flags.enable(EXTERNAL_CONTRACT_WAS_CALLED); _setActiveCreditAccount(creditAccount); // U:[FA-38] } result = mcall.target.functionCall(mcall.callData); // U:[FA-38] emit Execute({creditAccount: creditAccount, targetContract: targetContract}); } (uint256 tokensToEnable, uint256 tokensToDisable) = abi.decode(result, (uint256, uint256)); // U:[FA-38] quotedTokensMaskInverted = _quotedTokensMaskInvertedLoE(quotedTokensMaskInverted); enabledTokensMask = enabledTokensMask.enableDisable({ bitsToEnable: tokensToEnable, bitsToDisable: tokensToDisable, invertedSkipMask: quotedTokensMaskInverted }); // U:[FA-38] } } } if (expectedBalances.length != 0) { if (!BalancesLogic.compareBalances(creditAccount, expectedBalances, Comparison.GREATER)) { revert BalanceLessThanExpectedException(); // U:[FA-23] } } if (enabledTokensMask & forbiddenTokenMask != 0) { fullCheckParams.useSafePrices = true; } if (flags & EXTERNAL_CONTRACT_WAS_CALLED != 0) { _unsetActiveCreditAccount(); // U:[FA-38] } fullCheckParams.enabledTokensMaskAfter = enabledTokensMask; // U:[FA-38] emit FinishMultiCall(); // U:[FA-18] } /// @dev Applies on-demand price feed updates placed at the beginning of the multicall (if there are any) /// @return skipCalls Number of update calls made that can be skiped later in the `_multicall` function _applyOnDemandPriceUpdates(MultiCall[] calldata calls) internal returns (uint256 skipCalls) { address priceOracle; unchecked { uint256 len = calls.length; for (uint256 i; i < len; ++i) { MultiCall calldata mcall = calls[i]; if ( mcall.target == address(this) && bytes4(mcall.callData) == ICreditFacadeV3Multicall.onDemandPriceUpdate.selector ) { (address token, bool reserve, bytes memory data) = abi.decode(mcall.callData[4:], (address, bool, bytes)); // U:[FA-25] priceOracle = _priceOracleLoE(priceOracle); // U:[FA-25] address priceFeed = IPriceOracleV3(priceOracle).priceFeedsRaw(token, reserve); // U:[FA-25] if (priceFeed == address(0)) { revert PriceFeedDoesNotExistException(); // U:[FA-25] } IUpdatablePriceFeed(priceFeed).updatePrice(data); // U:[FA-25] } else { return i; } } return len; } } /// @dev Performs collateral check to ensure that /// - account is sufficiently collateralized /// - account has no forbidden tokens after risky operations /// - no forbidden tokens have been enabled during the multicall /// - no enabled forbidden token balance has increased during the multicall function _fullCollateralCheck( address creditAccount, uint256 enabledTokensMaskBefore, FullCheckParams memory fullCheckParams, BalanceWithMask[] memory forbiddenBalances, uint256 forbiddenTokensMask ) internal { uint256 enabledTokensMask = ICreditManagerV3(creditManager).fullCollateralCheck( creditAccount, fullCheckParams.enabledTokensMaskAfter, fullCheckParams.collateralHints, fullCheckParams.minHealthFactor, fullCheckParams.useSafePrices ); // U:[FA-45] uint256 enabledForbiddenTokensMask = enabledTokensMask & forbiddenTokensMask; if (enabledForbiddenTokensMask != 0) { if (fullCheckParams.revertOnForbiddenTokens) revert ForbiddenTokensException(); // U:[FA-45] uint256 enabledForbiddenTokensMaskBefore = enabledTokensMaskBefore & forbiddenTokensMask; if (enabledForbiddenTokensMask & ~enabledForbiddenTokensMaskBefore != 0) { revert ForbiddenTokenEnabledException(); // U:[FA-45] } bool success = BalancesLogic.compareBalances({ creditAccount: creditAccount, tokensMask: enabledForbiddenTokensMask, balances: forbiddenBalances, comparison: Comparison.LESS }); if (!success) revert ForbiddenTokenBalanceIncreasedException(); // U:[FA-45] } } /// @dev `ICreditFacadeV3Multicall.addCollateral` implementation function _addCollateral(address creditAccount, bytes calldata callData) internal returns (uint256 tokensToEnable) { (address token, uint256 amount) = abi.decode(callData, (address, uint256)); // U:[FA-26] tokensToEnable = _addCollateral({payer: msg.sender, creditAccount: creditAccount, token: token, amount: amount}); // U:[FA-26] emit AddCollateral(creditAccount, token, amount); // U:[FA-26] } /// @dev `ICreditFacadeV3Multicall.addCollateralWithPermit` implementation function _addCollateralWithPermit(address creditAccount, bytes calldata callData) internal returns (uint256 tokensToEnable) { (address token, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) = abi.decode(callData, (address, uint256, uint256, uint8, bytes32, bytes32)); // U:[FA-26B] // `token` is only validated later in `addCollateral`, but to benefit off of it the attacker would have to make // it recognizable as collateral in the credit manager, which requires gaining configurator access rights try IERC20Permit(token).permit(msg.sender, creditManager, amount, deadline, v, r, s) {} catch {} // U:[FA-26B] tokensToEnable = _addCollateral({payer: msg.sender, creditAccount: creditAccount, token: token, amount: amount}); // U:[FA-26B] emit AddCollateral(creditAccount, token, amount); // U:[FA-26B] } /// @dev `ICreditFacadeV3Multicall.{increase|decrease}Debt` implementation function _manageDebt( address creditAccount, bytes calldata callData, uint256 enabledTokensMask, ManageDebtAction action ) internal returns (uint256 tokensToEnable, uint256 tokensToDisable) { uint256 amount = abi.decode(callData, (uint256)); // U:[FA-27,31] if (action == ManageDebtAction.INCREASE_DEBT) { _revertIfOutOfBorrowingLimit(amount); // U:[FA-28] } uint256 newDebt; (newDebt, tokensToEnable, tokensToDisable) = ICreditManagerV3(creditManager).manageDebt(creditAccount, amount, enabledTokensMask, action); // U:[FA-27,31] _revertIfOutOfDebtLimits(newDebt); // U:[FA-28, 32, 33, 33A] if (action == ManageDebtAction.INCREASE_DEBT) { emit IncreaseDebt({creditAccount: creditAccount, amount: amount}); // U:[FA-27] } else { emit DecreaseDebt({creditAccount: creditAccount, amount: amount}); // U:[FA-31] } } /// @dev `ICreditFacadeV3Multicall.updateQuota` implementation function _updateQuota(address creditAccount, bytes calldata callData, bool hasForbiddenTokens) internal returns (uint256 tokensToEnable, uint256 tokensToDisable) { (address token, int96 quotaChange, uint96 minQuota) = abi.decode(callData, (address, int96, uint96)); // U:[FA-34] // Ensures that user is not trying to increase quota for a forbidden token. This happens implicitly when user // has no enabled forbidden tokens because quota increase would try to enable the token, which is prohibited. // Thus some gas is saved in this case by not querying token's mask. if (hasForbiddenTokens && quotaChange > 0) { if (_getTokenMaskOrRevert(token) & forbiddenTokenMask != 0) { revert ForbiddenTokensException(); } } (tokensToEnable, tokensToDisable) = ICreditManagerV3(creditManager).updateQuota({ creditAccount: creditAccount, token: token, quotaChange: quotaChange != type(int96).min ? quotaChange / int96(uint96(PERCENTAGE_FACTOR)) * int96(uint96(PERCENTAGE_FACTOR)) : quotaChange, minQuota: minQuota, maxQuota: uint96(Math.min(type(uint96).max, maxQuotaMultiplier * debtLimits.maxDebt)) }); // U:[FA-34] } /// @dev `ICreditFacadeV3Multicall.withdrawCollateral` implementation function _withdrawCollateral(address creditAccount, bytes calldata callData) internal returns (uint256 tokensToDisable) { (address token, uint256 amount, address to) = abi.decode(callData, (address, uint256, address)); // U:[FA-35] if (amount == type(uint256).max) { amount = IERC20(token).balanceOf(creditAccount); if (amount <= 1) return 0; unchecked { --amount; } } tokensToDisable = ICreditManagerV3(creditManager).withdrawCollateral(creditAccount, token, amount, to); // U:[FA-35] emit WithdrawCollateral(creditAccount, token, amount, to); // U:[FA-35] } /// @dev `ICreditFacadeV3Multicall.revokeAdapterAllowances` implementation function _revokeAdapterAllowances(address creditAccount, bytes calldata callData) internal { RevocationPair[] memory revocations = abi.decode(callData, (RevocationPair[])); // U:[FA-36] ICreditManagerV3(creditManager).revokeAdapterAllowances(creditAccount, revocations); // U:[FA-36] } // ------------- // // CONFIGURATION // // ------------- // /// @notice Sets the credit facade expiration timestamp /// @param newExpirationDate New expiration timestamp /// @dev Reverts if caller is not credit configurator /// @dev Reverts if credit facade is not expirable function setExpirationDate(uint40 newExpirationDate) external override creditConfiguratorOnly // U:[FA-6] { if (!expirable) { revert NotAllowedWhenNotExpirableException(); // U:[FA-48] } expirationDate = newExpirationDate; // U:[FA-48] } /// @notice Sets debt limits per credit account /// @param newMinDebt New minimum debt amount per credit account /// @param newMaxDebt New maximum debt amount per credit account /// @param newMaxDebtPerBlockMultiplier New max debt per block multiplier, `type(uint8).max` to disable the check /// @dev Reverts if caller is not credit configurator /// @dev Reverts if `maxDebt * maxDebtPerBlockMultiplier` doesn't fit into `uint128` function setDebtLimits(uint128 newMinDebt, uint128 newMaxDebt, uint8 newMaxDebtPerBlockMultiplier) external override creditConfiguratorOnly // U:[FA-6] { if ((uint256(newMaxDebtPerBlockMultiplier) * newMaxDebt) >= type(uint128).max) { revert IncorrectParameterException(); // U:[FA-49] } debtLimits.minDebt = newMinDebt; // U:[FA-49] debtLimits.maxDebt = newMaxDebt; // U:[FA-49] maxDebtPerBlockMultiplier = newMaxDebtPerBlockMultiplier; // U:[FA-49] } /// @notice Sets the new bot list /// @param newBotList New bot list address /// @dev Reverts if caller is not credit configurator function setBotList(address newBotList) external override creditConfiguratorOnly // U:[FA-6] { botList = newBotList; // U:[FA-50] } /// @notice Sets the new max cumulative loss /// @param newMaxCumulativeLoss New max cumulative loss /// @param resetCumulativeLoss Whether to reset the current cumulative loss to zero /// @dev Reverts if caller is not credit configurator function setCumulativeLossParams(uint128 newMaxCumulativeLoss, bool resetCumulativeLoss) external override creditConfiguratorOnly // U:[FA-6] { lossParams.maxCumulativeLoss = newMaxCumulativeLoss; // U:[FA-51] if (resetCumulativeLoss) { lossParams.currentCumulativeLoss = 0; // U:[FA-51] } } /// @notice Changes token's forbidden status /// @param token Token to change the status for /// @param allowance Status to set /// @dev Reverts if caller is not credit configurator function setTokenAllowance(address token, AllowanceAction allowance) external override creditConfiguratorOnly // U:[FA-6] { uint256 tokenMask = _getTokenMaskOrRevert(token); // U:[FA-52] forbiddenTokenMask = (allowance == AllowanceAction.ALLOW) ? forbiddenTokenMask.disable(tokenMask) : forbiddenTokenMask.enable(tokenMask); // U:[FA-52] } /// @notice Changes account's status as emergency liquidator /// @param liquidator Account to change the status for /// @param allowance Status to set /// @dev Reverts if caller is not credit configurator function setEmergencyLiquidator(address liquidator, AllowanceAction allowance) external override creditConfiguratorOnly // U:[FA-6] { canLiquidateWhilePaused[liquidator] = allowance == AllowanceAction.ALLOW; // U:[FA-53] } // --------- // // INTERNALS // // --------- // /// @dev Ensures that amount borrowed by credit manager in the current block does not exceed the limit /// @dev Skipped when `maxDebtPerBlockMultiplier == type(uint8).max` function _revertIfOutOfBorrowingLimit(uint256 amount) internal { uint8 _maxDebtPerBlockMultiplier = maxDebtPerBlockMultiplier; // U:[FA-43] if (_maxDebtPerBlockMultiplier == type(uint8).max) return; // U:[FA-43] uint256 newDebtInCurrentBlock; if (lastBlockBorrowed == block.number) { newDebtInCurrentBlock = amount + totalBorrowedInBlock; // U:[FA-43] } else { newDebtInCurrentBlock = amount; lastBlockBorrowed = uint64(block.number); // U:[FA-43] } if (newDebtInCurrentBlock > uint256(_maxDebtPerBlockMultiplier) * debtLimits.maxDebt) { revert BorrowedBlockLimitException(); // U:[FA-43] } // the conversion is safe because of the check in `setDebtLimits` totalBorrowedInBlock = uint128(newDebtInCurrentBlock); // U:[FA-43] } /// @dev Ensures that account's debt principal is within allowed range or is zero function _revertIfOutOfDebtLimits(uint256 debt) internal view { uint256 minDebt; uint256 maxDebt; // minDebt = debtLimits.minDebt; // maxDebt = debtLimits.maxDebt; assembly { let data := sload(debtLimits.slot) maxDebt := shr(128, data) minDebt := and(data, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } if (debt != 0 && ((debt < minDebt) || (debt > maxDebt))) { revert BorrowAmountOutOfLimitsException(); // U:[FA-44] } } /// @dev Ensures that `flags` has the `permission` bit enabled function _revertIfNoPermission(uint256 flags, uint256 permission) internal pure { if (flags & permission == 0) { revert NoPermissionException(permission); // U:[FA-39] } } /// @dev Load-on-empty function to read inverted quoted tokens mask at most once if it's needed, /// returns its argument if it's not empty or inverted `quotedTokensMask` from credit manager otherwise /// @dev Non-empty inverted quoted tokens mask always has it's LSB set to 1 since underlying can't be quoted function _quotedTokensMaskInvertedLoE(uint256 quotedTokensMaskInvertedOrEmpty) internal view returns (uint256) { return quotedTokensMaskInvertedOrEmpty == 0 ? ~ICreditManagerV3(creditManager).quotedTokensMask() : quotedTokensMaskInvertedOrEmpty; } /// @dev Load-on-empty function to read price oracle at most once if it's needed, /// returns its argument if it's not empty or `priceOracle` from credit manager otherwise /// @dev Non-empty price oracle always has non-zero address function _priceOracleLoE(address priceOracleOrEmpty) internal view returns (address) { return priceOracleOrEmpty == address(0) ? ICreditManagerV3(creditManager).priceOracle() : priceOracleOrEmpty; } /// @dev Wraps any ETH sent in the function call and sends it back to `msg.sender` function _wrapETH() internal { if (msg.value != 0) { IWETH(weth).deposit{value: msg.value}(); // U:[FA-7] IERC20(weth).safeTransfer(msg.sender, msg.value); // U:[FA-7] } } /// @dev Whether credit facade has expired (`false` if it's not expirable or expiration timestamp is not set) function _isExpired() internal view returns (bool) { if (!expirable) return false; // U:[FA-46] uint40 _expirationDate = expirationDate; return _expirationDate != 0 && block.timestamp >= _expirationDate; // U:[FA-46] } /// @dev Internal wrapper for `creditManager.getBorrowerOrRevert` call to reduce contract size function _getBorrowerOrRevert(address creditAccount) internal view returns (address) { return ICreditManagerV3(creditManager).getBorrowerOrRevert({creditAccount: creditAccount}); } /// @dev Internal wrapper for `creditManager.getTokenMaskOrRevert` call to reduce contract size function _getTokenMaskOrRevert(address token) internal view returns (uint256) { return ICreditManagerV3(creditManager).getTokenMaskOrRevert(token); } /// @dev Internal wrapper for `creditManager.getTokenByMask` call to reduce contract size function _getTokenByMask(uint256 mask) internal view returns (address) { return ICreditManagerV3(creditManager).getTokenByMask(mask); } /// @dev Internal wrapper for `creditManager.flagsOf` call to reduce contract size function _flagsOf(address creditAccount) internal view returns (uint16) { return ICreditManagerV3(creditManager).flagsOf(creditAccount); } /// @dev Internal wrapper for `creditManager.setFlagFor` call to reduce contract size function _setFlagFor(address creditAccount, uint16 flag, bool value) internal { ICreditManagerV3(creditManager).setFlagFor(creditAccount, flag, value); } /// @dev Internal wrapper for `creditManager.setActiveCreditAccount` call to reduce contract size function _setActiveCreditAccount(address creditAccount) internal { ICreditManagerV3(creditManager).setActiveCreditAccount(creditAccount); } /// @dev Same as above but unsets active credit account function _unsetActiveCreditAccount() internal { _setActiveCreditAccount(INACTIVE_CREDIT_ACCOUNT_ADDRESS); } /// @dev Internal wrapper for `creditManager.addCollateral` call to reduce contract size function _addCollateral(address payer, address creditAccount, address token, uint256 amount) internal returns (uint256 tokenMask) { tokenMask = ICreditManagerV3(creditManager).addCollateral({ payer: payer, creditAccount: creditAccount, token: token, amount: amount }); } /// @dev Internal wrapper for `creditManager.enabledTokensMaskOf` call to reduce contract size function _enabledTokensMaskOf(address creditAccount) internal view returns (uint256) { return ICreditManagerV3(creditManager).enabledTokensMaskOf(creditAccount); } /// @dev Reverts if `msg.sender` is not credit configurator function _checkCreditConfigurator() internal view { if (msg.sender != ICreditManagerV3(creditManager).creditConfigurator()) { revert CallerNotConfiguratorException(); } } /// @dev Reverts if `msg.sender` is not `creditAccount` owner function _checkCreditAccountOwner(address creditAccount) internal view { if (msg.sender != _getBorrowerOrRevert(creditAccount)) { revert CallerNotCreditAccountOwnerException(); } } /// @dev Reverts if credit facade is expired function _checkExpired() internal view { if (_isExpired()) { revert NotAllowedAfterExpirationException(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. 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 uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @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 * * _Available since v4.2._ */ 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 uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(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 * * _Available since v2.5._ */ 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 uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(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 * * _Available since v4.2._ */ 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 uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(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 * * _Available since v2.5._ */ 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 uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(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 * * _Available since v2.5._ */ 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 uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(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 * * _Available since v2.5._ */ 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 * * _Available since v2.5._ */ 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. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @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 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @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 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @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 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @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 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @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 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ 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 // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; import "../interfaces/IDaiLikePermit.sol"; import "../interfaces/IPermit2.sol"; import "../interfaces/IWETH.sol"; import "../libraries/RevertReasonForwarder.sol"; /// @title Implements efficient safe methods for ERC20 interface. library SafeERC20 { error SafeTransferFailed(); error SafeTransferFromFailed(); error ForceApproveFailed(); error SafeIncreaseAllowanceFailed(); error SafeDecreaseAllowanceFailed(); error SafePermitBadLength(); error Permit2TransferAmountTooHigh(); address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857; // SafePermitBadLength.selector uint256 private constant _RAW_CALL_GAS_LIMIT = 5000; function safeBalanceOf( IERC20 token, address account ) internal view returns(uint256 tokenBalance) { bytes4 selector = IERC20.balanceOf.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0x00, selector) mstore(0x04, account) let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20) tokenBalance := mload(0) if or(iszero(success), lt(returndatasize(), 0x20)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } /// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract. function safeTransferFromUniversal( IERC20 token, address from, address to, uint256 amount, bool permit2 ) internal { if (permit2) { safeTransferFromPermit2(token, from, to, amount); } else { safeTransferFrom(token, from, to, amount); } } /// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract. function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { bytes4 selector = token.transferFrom.selector; bool success; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), from) mstore(add(data, 0x24), to) mstore(add(data, 0x44), amount) success := call(gas(), token, 0, data, 100, 0x0, 0x20) if success { switch returndatasize() case 0 { success := gt(extcodesize(token), 0) } default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) } } } if (!success) revert SafeTransferFromFailed(); } /// @dev Permit2 version of safeTransferFrom above. function safeTransferFromPermit2( IERC20 token, address from, address to, uint256 amount ) internal { if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh(); bytes4 selector = IPermit2.transferFrom.selector; bool success; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), from) mstore(add(data, 0x24), to) mstore(add(data, 0x44), amount) mstore(add(data, 0x64), token) success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0) if success { success := gt(extcodesize(_PERMIT2), 0) } } if (!success) revert SafeTransferFromFailed(); } /// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract. function safeTransfer( IERC20 token, address to, uint256 value ) internal { if (!_makeCall(token, token.transfer.selector, to, value)) { revert SafeTransferFailed(); } } /// @dev If `approve(from, to, amount)` fails, try to `approve(from, to, 0)` before retry. function forceApprove( IERC20 token, address spender, uint256 value ) internal { if (!_makeCall(token, token.approve.selector, spender, value)) { if ( !_makeCall(token, token.approve.selector, spender, 0) || !_makeCall(token, token.approve.selector, spender, value) ) { revert ForceApproveFailed(); } } } /// @dev Allowance increase with safe math check. function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 allowance = token.allowance(address(this), spender); if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed(); forceApprove(token, spender, allowance + value); } /// @dev Allowance decrease with safe math check. function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 allowance = token.allowance(address(this), spender); if (value > allowance) revert SafeDecreaseAllowanceFailed(); forceApprove(token, spender, allowance - value); } function safePermit(IERC20 token, bytes calldata permit) internal { if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert(); } function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal { if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert(); } function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) { return tryPermit(token, msg.sender, address(this), permit); } function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) { bytes4 permitSelector = IERC20Permit.permit.selector; bytes4 daiPermitSelector = IDaiLikePermit.permit.selector; bytes4 permit2Selector = IPermit2.permit.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) switch permit.length case 100 { mstore(ptr, permitSelector) mstore(add(ptr, 0x04), owner) mstore(add(ptr, 0x24), spender) // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs) { // stack too deep let deadline := shr(224, calldataload(add(permit.offset, 0x20))) let vs := calldataload(add(permit.offset, 0x44)) calldatacopy(add(ptr, 0x44), permit.offset, 0x20) // value mstore(add(ptr, 0x64), sub(deadline, 1)) mstore(add(ptr, 0x84), add(27, shr(255, vs))) calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // r mstore(add(ptr, 0xc4), shr(1, shl(1, vs))) } // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0xe4, 0, 0) } case 72 { mstore(ptr, daiPermitSelector) mstore(add(ptr, 0x04), owner) mstore(add(ptr, 0x24), spender) // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs) { // stack too deep let expiry := shr(224, calldataload(add(permit.offset, 0x04))) let vs := calldataload(add(permit.offset, 0x28)) mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) mstore(add(ptr, 0x64), sub(expiry, 1)) mstore(add(ptr, 0x84), true) mstore(add(ptr, 0xa4), add(27, shr(255, vs))) calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20) // r mstore(add(ptr, 0xe4), shr(1, shl(1, vs))) } // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0x104, 0, 0) } case 224 { mstore(ptr, permitSelector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0xe4, 0, 0) } case 256 { mstore(ptr, daiPermitSelector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0x104, 0, 0) } case 96 { // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs) mstore(ptr, permit2Selector) mstore(add(ptr, 0x04), owner) mstore(add(ptr, 0x24), token) calldatacopy(add(ptr, 0x50), permit.offset, 0x14) // amount mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // expiration mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // nonce mstore(add(ptr, 0xa4), spender) mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // sigDeadline mstore(add(ptr, 0xe4), 0x100) mstore(add(ptr, 0x104), 0x40) calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // r calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // vs // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature) success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0) } case 352 { mstore(ptr, permit2Selector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature) success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0) } default { mstore(ptr, _PERMIT_LENGTH_ERROR) revert(ptr, 4) } } } function _makeCall( IERC20 token, bytes4 selector, address to, uint256 amount ) private returns (bool success) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), to) mstore(add(data, 0x24), amount) success := call(gas(), token, 0, data, 0x44, 0x0, 0x20) if success { switch returndatasize() case 0 { success := gt(extcodesize(token), 0) } default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) } } } } function safeDeposit(IWETH weth, uint256 amount) internal { if (amount > 0) { bytes4 selector = IWETH.deposit.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0, selector) if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } function safeWithdraw(IWETH weth, uint256 amount) internal { bytes4 selector = IWETH.withdraw.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0, selector) mstore(4, amount) if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal { safeWithdraw(weth, amount); if (to != address(this)) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; import {BitMask} from "./BitMask.sol"; import {Balance} from "@gearbox-protocol/core-v2/contracts/libraries/Balances.sol"; struct BalanceWithMask { address token; uint256 tokenMask; uint256 balance; } struct BalanceDelta { address token; int256 amount; } enum Comparison { GREATER, LESS } /// @title Balances logic library /// @notice Implements functions for before-and-after balance comparisons library BalancesLogic { using BitMask for uint256; using SafeCast for int256; using SafeCast for uint256; using SafeERC20 for IERC20; /// @dev Compares current `token` balance with `value` /// @param token Token to check balance for /// @param value Value to compare current token balance with /// @param comparison Whether current balance must be greater/less than or equal to `value` function checkBalance(address creditAccount, address token, uint256 value, Comparison comparison) internal view returns (bool) { uint256 current = IERC20(token).safeBalanceOf(creditAccount); return (comparison == Comparison.GREATER && current >= value) || (comparison == Comparison.LESS && current <= value); // U:[BLL-1] } /// @dev Returns an array of expected token balances after operations /// @param creditAccount Credit account to compute balances for /// @param deltas Array of expected token balance changes function storeBalances(address creditAccount, BalanceDelta[] memory deltas) internal view returns (Balance[] memory balances) { uint256 len = deltas.length; balances = new Balance[](len); // U:[BLL-2] for (uint256 i = 0; i < len;) { int256 balance = IERC20(deltas[i].token).safeBalanceOf(creditAccount).toInt256(); balances[i] = Balance({token: deltas[i].token, balance: (balance + deltas[i].amount).toUint256()}); // U:[BLL-2] unchecked { ++i; } } } /// @dev Compares current balances with the previously stored ones /// @param creditAccount Credit account to compare balances for /// @param balances Array of previously stored balances /// @param comparison Whether current balances must be greater/less than or equal to stored ones /// @return success True if condition specified by `comparison` holds for all tokens, false otherwise function compareBalances(address creditAccount, Balance[] memory balances, Comparison comparison) internal view returns (bool success) { uint256 len = balances.length; unchecked { for (uint256 i = 0; i < len; ++i) { if (!BalancesLogic.checkBalance(creditAccount, balances[i].token, balances[i].balance, comparison)) { return false; // U:[BLL-3] } } } return true; // U:[BLL-3] } /// @dev Returns balances of specified tokens on the credit account /// @param creditAccount Credit account to compute balances for /// @param tokensMask Bit mask of tokens to compute balances for /// @param getTokenByMaskFn Function that returns token's address by its mask function storeBalances( address creditAccount, uint256 tokensMask, function (uint256) view returns (address) getTokenByMaskFn ) internal view returns (BalanceWithMask[] memory balances) { if (tokensMask == 0) return balances; balances = new BalanceWithMask[](tokensMask.calcEnabledTokens()); // U:[BLL-4] unchecked { uint256 i; while (tokensMask != 0) { uint256 tokenMask = tokensMask & uint256(-int256(tokensMask)); tokensMask ^= tokenMask; address token = getTokenByMaskFn(tokenMask); balances[i] = BalanceWithMask({ token: token, tokenMask: tokenMask, balance: IERC20(token).safeBalanceOf(creditAccount) }); // U:[BLL-4] ++i; } } } /// @dev Compares current balances of specified tokens with the previously stored ones /// @param creditAccount Credit account to compare balances for /// @param tokensMask Bit mask of tokens to compare balances for /// @param balances Array of previously stored balances /// @param comparison Whether current balances must be greater/less than or equal to stored ones /// @return success True if condition specified by `comparison` holds for all tokens, false otherwise function compareBalances( address creditAccount, uint256 tokensMask, BalanceWithMask[] memory balances, Comparison comparison ) internal view returns (bool) { if (tokensMask == 0) return true; unchecked { uint256 len = balances.length; for (uint256 i; i < len; ++i) { if (tokensMask & balances[i].tokenMask != 0) { if (!BalancesLogic.checkBalance(creditAccount, balances[i].token, balances[i].balance, comparison)) { return false; // U:[BLL-5] } } } } return true; // U:[BLL-5] } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {IACL} from "@gearbox-protocol/core-v2/contracts/interfaces/IACL.sol"; import { CallerNotControllerException, CallerNotPausableAdminException, CallerNotUnpausableAdminException } from "../interfaces/IExceptions.sol"; import {ACLTrait} from "./ACLTrait.sol"; import {ReentrancyGuardTrait} from "./ReentrancyGuardTrait.sol"; /// @title ACL non-reentrant trait /// @notice Extended version of `ACLTrait` that implements pausable functionality, /// reentrancy protection and external controller role abstract contract ACLNonReentrantTrait is ACLTrait, Pausable, ReentrancyGuardTrait { /// @notice Emitted when new external controller is set event NewController(address indexed newController); /// @notice External controller address address public controller; /// @dev Ensures that function caller is external controller or configurator modifier controllerOnly() { _ensureCallerIsControllerOrConfigurator(); _; } /// @dev Reverts if the caller is not controller or configurator /// @dev Used to cut contract size on modifiers function _ensureCallerIsControllerOrConfigurator() internal view { if (msg.sender != controller && !_isConfigurator({account: msg.sender})) { revert CallerNotControllerException(); } } /// @dev Ensures that function caller has pausable admin role modifier pausableAdminsOnly() { _ensureCallerIsPausableAdmin(); _; } /// @dev Reverts if the caller is not pausable admin /// @dev Used to cut contract size on modifiers function _ensureCallerIsPausableAdmin() internal view { if (!_isPausableAdmin({account: msg.sender})) { revert CallerNotPausableAdminException(); } } /// @dev Ensures that function caller has unpausable admin role modifier unpausableAdminsOnly() { _ensureCallerIsUnpausableAdmin(); _; } /// @dev Reverts if the caller is not unpausable admin /// @dev Used to cut contract size on modifiers function _ensureCallerIsUnpausableAdmin() internal view { if (!_isUnpausableAdmin({account: msg.sender})) { revert CallerNotUnpausableAdminException(); } } /// @notice Constructor /// @param addressProvider Address provider contract address constructor(address addressProvider) ACLTrait(addressProvider) { controller = IACL(acl).owner(); } /// @notice Pauses contract, can only be called by an account with pausable admin role function pause() external virtual pausableAdminsOnly { _pause(); } /// @notice Unpauses contract, can only be called by an account with unpausable admin role function unpause() external virtual unpausableAdminsOnly { _unpause(); } /// @notice Sets new external controller, can only be called by configurator function setController(address newController) external configuratorOnly { if (controller == newController) return; controller = newController; emit NewController(newController); } /// @dev Checks whether given account has pausable admin role function _isPausableAdmin(address account) internal view returns (bool) { return IACL(acl).isPausableAdmin(account); } /// @dev Checks whether given account has unpausable admin role function _isUnpausableAdmin(address account) internal view returns (bool) { return IACL(acl).isUnpausableAdmin(account); } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IncorrectParameterException} from "../interfaces/IExceptions.sol"; uint256 constant UNDERLYING_TOKEN_MASK = 1; /// @title Bit mask library /// @notice Implements functions that manipulate bit masks /// Bit masks are utilized extensively by Gearbox to efficiently store token sets (enabled tokens on accounts /// or forbidden tokens) and check for set inclusion. A mask is a uint256 number that has its i-th bit set to /// 1 if i-th item is included into the set. For example, each token has a mask equal to 2**i, so set inclusion /// can be checked by checking tokenMask & setMask != 0. library BitMask { /// @dev Calculates an index of an item based on its mask (using a binary search) /// @dev The input should always have only 1 bit set, otherwise the result may be unpredictable function calcIndex(uint256 mask) internal pure returns (uint8 index) { if (mask == 0) revert IncorrectParameterException(); // U:[BM-1] uint16 lb = 0; // U:[BM-2] uint16 ub = 256; // U:[BM-2] uint16 mid = 128; // U:[BM-2] unchecked { while (true) { uint256 newMask = 1 << mid; if (newMask & mask != 0) return uint8(mid); // U:[BM-2] if (newMask > mask) ub = mid; // U:[BM-2] else lb = mid; // U:[BM-2] mid = (lb + ub) >> 1; // U:[BM-2] } } } /// @dev Calculates the number of `1` bits /// @param enabledTokensMask Bit mask to compute the number of `1` bits in function calcEnabledTokens(uint256 enabledTokensMask) internal pure returns (uint256 totalTokensEnabled) { unchecked { while (enabledTokensMask > 0) { enabledTokensMask &= enabledTokensMask - 1; // U:[BM-3] ++totalTokensEnabled; // U:[BM-3] } } } /// @dev Enables bits from the second mask in the first mask /// @param enabledTokenMask The initial mask /// @param bitsToEnable Mask of bits to enable function enable(uint256 enabledTokenMask, uint256 bitsToEnable) internal pure returns (uint256) { return enabledTokenMask | bitsToEnable; // U:[BM-4] } /// @dev Disables bits from the second mask in the first mask /// @param enabledTokenMask The initial mask /// @param bitsToDisable Mask of bits to disable function disable(uint256 enabledTokenMask, uint256 bitsToDisable) internal pure returns (uint256) { return enabledTokenMask & ~bitsToDisable; // U:[BM-4] } /// @dev Computes a new mask with sets of new enabled and disabled bits /// @dev bitsToEnable and bitsToDisable are applied sequentially to original mask /// @param enabledTokensMask The initial mask /// @param bitsToEnable Mask with bits to enable /// @param bitsToDisable Mask with bits to disable function enableDisable(uint256 enabledTokensMask, uint256 bitsToEnable, uint256 bitsToDisable) internal pure returns (uint256) { return (enabledTokensMask | bitsToEnable) & (~bitsToDisable); // U:[BM-5] } /// @dev Enables bits from the second mask in the first mask, skipping specified bits /// @param enabledTokenMask The initial mask /// @param bitsToEnable Mask with bits to enable /// @param invertedSkipMask An inversion of mask of immutable bits function enable(uint256 enabledTokenMask, uint256 bitsToEnable, uint256 invertedSkipMask) internal pure returns (uint256) { return enabledTokenMask | (bitsToEnable & invertedSkipMask); // U:[BM-6] } /// @dev Disables bits from the second mask in the first mask, skipping specified bits /// @param enabledTokenMask The initial mask /// @param bitsToDisable Mask with bits to disable /// @param invertedSkipMask An inversion of mask of immutable bits function disable(uint256 enabledTokenMask, uint256 bitsToDisable, uint256 invertedSkipMask) internal pure returns (uint256) { return enabledTokenMask & (~(bitsToDisable & invertedSkipMask)); // U:[BM-6] } /// @dev Computes a new mask with sets of new enabled and disabled bits, skipping some bits /// @dev bitsToEnable and bitsToDisable are applied sequentially to original mask. Skipmask is applied in both cases. /// @param enabledTokensMask The initial mask /// @param bitsToEnable Mask with bits to enable /// @param bitsToDisable Mask with bits to disable /// @param invertedSkipMask An inversion of mask of immutable bits function enableDisable( uint256 enabledTokensMask, uint256 bitsToEnable, uint256 bitsToDisable, uint256 invertedSkipMask ) internal pure returns (uint256) { return (enabledTokensMask | (bitsToEnable & invertedSkipMask)) & (~(bitsToDisable & invertedSkipMask)); // U:[BM-7] } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; import "./ICreditFacadeV3Multicall.sol"; import {AllowanceAction} from "../interfaces/ICreditConfiguratorV3.sol"; /// @notice Debt limits packed into a single slot /// @param minDebt Minimum debt amount per credit account /// @param maxDebt Maximum debt amount per credit account struct DebtLimits { uint128 minDebt; uint128 maxDebt; } /// @notice Info on bad debt liquidation losses packed into a single slot /// @param currentCumulativeLoss Current cumulative loss from bad debt liquidations /// @param maxCumulativeLoss Max cumulative loss incurred before the facade gets paused struct CumulativeLossParams { uint128 currentCumulativeLoss; uint128 maxCumulativeLoss; } /// @notice Collateral check params /// @param collateralHints Optional array of token masks to check first to reduce the amount of computation /// when known subset of account's collateral tokens covers all the debt /// @param minHealthFactor Min account's health factor in bps in order not to revert /// @param enabledTokensMaskAfter Bitmask of account's enabled collateral tokens after the multicall /// @param revertOnForbiddenTokens Whether to revert on enabled forbidden tokens after the multicall /// @param useSafePrices Whether to use safe pricing (min of main and reserve feeds) when evaluating collateral struct FullCheckParams { uint256[] collateralHints; uint16 minHealthFactor; uint256 enabledTokensMaskAfter; bool revertOnForbiddenTokens; bool useSafePrices; } interface ICreditFacadeV3Events { /// @notice Emitted when a new credit account is opened event OpenCreditAccount( address indexed creditAccount, address indexed onBehalfOf, address indexed caller, uint256 referralCode ); /// @notice Emitted when account is closed event CloseCreditAccount(address indexed creditAccount, address indexed borrower); /// @notice Emitted when account is liquidated event LiquidateCreditAccount( address indexed creditAccount, address indexed liquidator, address to, uint256 remainingFunds ); /// @notice Emitted when account's debt is increased event IncreaseDebt(address indexed creditAccount, uint256 amount); /// @notice Emitted when account's debt is decreased event DecreaseDebt(address indexed creditAccount, uint256 amount); /// @notice Emitted when collateral is added to account event AddCollateral(address indexed creditAccount, address indexed token, uint256 amount); /// @notice Emitted when collateral is withdrawn from account event WithdrawCollateral(address indexed creditAccount, address indexed token, uint256 amount, address to); /// @notice Emitted when a multicall is started event StartMultiCall(address indexed creditAccount, address indexed caller); /// @notice Emitted when a call from account to an external contract is made during a multicall event Execute(address indexed creditAccount, address indexed targetContract); /// @notice Emitted when a multicall is finished event FinishMultiCall(); } /// @title Credit facade V3 interface interface ICreditFacadeV3 is IVersion, ICreditFacadeV3Events { function creditManager() external view returns (address); function degenNFT() external view returns (address); function weth() external view returns (address); function botList() external view returns (address); function maxDebtPerBlockMultiplier() external view returns (uint8); function maxQuotaMultiplier() external view returns (uint256); function expirable() external view returns (bool); function expirationDate() external view returns (uint40); function debtLimits() external view returns (uint128 minDebt, uint128 maxDebt); function lossParams() external view returns (uint128 currentCumulativeLoss, uint128 maxCumulativeLoss); function forbiddenTokenMask() external view returns (uint256); function canLiquidateWhilePaused(address) external view returns (bool); // ------------------ // // ACCOUNT MANAGEMENT // // ------------------ // function openCreditAccount(address onBehalfOf, MultiCall[] calldata calls, uint256 referralCode) external payable returns (address creditAccount); function closeCreditAccount(address creditAccount, MultiCall[] calldata calls) external payable; function liquidateCreditAccount(address creditAccount, address to, MultiCall[] calldata calls) external; function multicall(address creditAccount, MultiCall[] calldata calls) external payable; function botMulticall(address creditAccount, MultiCall[] calldata calls) external; function setBotPermissions(address creditAccount, address bot, uint192 permissions) external; // ------------- // // CONFIGURATION // // ------------- // function setExpirationDate(uint40 newExpirationDate) external; function setDebtLimits(uint128 newMinDebt, uint128 newMaxDebt, uint8 newMaxDebtPerBlockMultiplier) external; function setBotList(address newBotList) external; function setCumulativeLossParams(uint128 newMaxCumulativeLoss, bool resetCumulativeLoss) external; function setTokenAllowance(address token, AllowanceAction allowance) external; function setEmergencyLiquidator(address liquidator, AllowanceAction allowance) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; uint256 constant NO_VERSION_CONTROL = 0; bytes32 constant AP_CONTRACTS_REGISTER = "CONTRACTS_REGISTER"; bytes32 constant AP_ACL = "ACL"; bytes32 constant AP_PRICE_ORACLE = "PRICE_ORACLE"; bytes32 constant AP_ACCOUNT_FACTORY = "ACCOUNT_FACTORY"; bytes32 constant AP_DATA_COMPRESSOR = "DATA_COMPRESSOR"; bytes32 constant AP_TREASURY = "TREASURY"; bytes32 constant AP_GEAR_TOKEN = "GEAR_TOKEN"; bytes32 constant AP_WETH_TOKEN = "WETH_TOKEN"; bytes32 constant AP_WETH_GATEWAY = "WETH_GATEWAY"; bytes32 constant AP_ROUTER = "ROUTER"; bytes32 constant AP_BOT_LIST = "BOT_LIST"; bytes32 constant AP_GEAR_STAKING = "GEAR_STAKING"; bytes32 constant AP_ZAPPER_REGISTER = "ZAPPER_REGISTER"; interface IAddressProviderV3Events { /// @notice Emitted when an address is set for a contract key event SetAddress(bytes32 indexed key, address indexed value, uint256 indexed version); } /// @title Address provider V3 interface interface IAddressProviderV3 is IAddressProviderV3Events, IVersion { function addresses(bytes32 key, uint256 _version) external view returns (address); function getAddressOrRevert(bytes32 key, uint256 _version) external view returns (address result); function setAddress(bytes32 key, address value, bool saveVersion) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; uint8 constant BOT_PERMISSIONS_SET_FLAG = 1; uint8 constant DEFAULT_MAX_ENABLED_TOKENS = 4; address constant INACTIVE_CREDIT_ACCOUNT_ADDRESS = address(1); /// @notice Debt management type /// - `INCREASE_DEBT` borrows additional funds from the pool, updates account's debt and cumulative interest index /// - `DECREASE_DEBT` repays debt components (quota interest and fees -> base interest and fees -> debt principal) /// and updates all corresponding state varibles (base interest index, quota interest and fees, debt). /// When repaying all the debt, ensures that account has no enabled quotas. enum ManageDebtAction { INCREASE_DEBT, DECREASE_DEBT } /// @notice Collateral/debt calculation mode /// - `GENERIC_PARAMS` returns generic data like account debt and cumulative indexes /// - `DEBT_ONLY` is same as `GENERIC_PARAMS` but includes more detailed debt info, like accrued base/quota /// interest and fees /// - `FULL_COLLATERAL_CHECK_LAZY` checks whether account is sufficiently collateralized in a lazy fashion, /// i.e. it stops iterating over collateral tokens once TWV reaches the desired target. /// Since it may return underestimated TWV, it's only available for internal use. /// - `DEBT_COLLATERAL` is same as `DEBT_ONLY` but also returns total value and total LT-weighted value of /// account's tokens, this mode is used during account liquidation /// - `DEBT_COLLATERAL_SAFE_PRICES` is same as `DEBT_COLLATERAL` but uses safe prices from price oracle enum CollateralCalcTask { GENERIC_PARAMS, DEBT_ONLY, FULL_COLLATERAL_CHECK_LAZY, DEBT_COLLATERAL, DEBT_COLLATERAL_SAFE_PRICES } struct CreditAccountInfo { uint256 debt; uint256 cumulativeIndexLastUpdate; uint128 cumulativeQuotaInterest; uint128 quotaFees; uint256 enabledTokensMask; uint16 flags; uint64 lastDebtUpdate; address borrower; } struct CollateralDebtData { uint256 debt; uint256 cumulativeIndexNow; uint256 cumulativeIndexLastUpdate; uint128 cumulativeQuotaInterest; uint256 accruedInterest; uint256 accruedFees; uint256 totalDebtUSD; uint256 totalValue; uint256 totalValueUSD; uint256 twvUSD; uint256 enabledTokensMask; uint256 quotedTokensMask; address[] quotedTokens; address _poolQuotaKeeper; } struct CollateralTokenData { address token; uint16 ltInitial; uint16 ltFinal; uint40 timestampRampStart; uint24 rampDuration; } struct RevocationPair { address spender; address token; } interface ICreditManagerV3Events { /// @notice Emitted when new credit configurator is set event SetCreditConfigurator(address indexed newConfigurator); } /// @title Credit manager V3 interface interface ICreditManagerV3 is IVersion, ICreditManagerV3Events { function pool() external view returns (address); function underlying() external view returns (address); function creditFacade() external view returns (address); function creditConfigurator() external view returns (address); function addressProvider() external view returns (address); function accountFactory() external view returns (address); function name() external view returns (string memory); // ------------------ // // ACCOUNT MANAGEMENT // // ------------------ // function openCreditAccount(address onBehalfOf) external returns (address); function closeCreditAccount(address creditAccount) external; function liquidateCreditAccount( address creditAccount, CollateralDebtData calldata collateralDebtData, address to, bool isExpired ) external returns (uint256 remainingFunds, uint256 loss); function manageDebt(address creditAccount, uint256 amount, uint256 enabledTokensMask, ManageDebtAction action) external returns (uint256 newDebt, uint256 tokensToEnable, uint256 tokensToDisable); function addCollateral(address payer, address creditAccount, address token, uint256 amount) external returns (uint256 tokensToEnable); function withdrawCollateral(address creditAccount, address token, uint256 amount, address to) external returns (uint256 tokensToDisable); function externalCall(address creditAccount, address target, bytes calldata callData) external returns (bytes memory result); function approveToken(address creditAccount, address token, address spender, uint256 amount) external; function revokeAdapterAllowances(address creditAccount, RevocationPair[] calldata revocations) external; // -------- // // ADAPTERS // // -------- // function adapterToContract(address adapter) external view returns (address targetContract); function contractToAdapter(address targetContract) external view returns (address adapter); function execute(bytes calldata data) external returns (bytes memory result); function approveCreditAccount(address token, uint256 amount) external; function setActiveCreditAccount(address creditAccount) external; function getActiveCreditAccountOrRevert() external view returns (address creditAccount); // ----------------- // // COLLATERAL CHECKS // // ----------------- // function priceOracle() external view returns (address); function fullCollateralCheck( address creditAccount, uint256 enabledTokensMask, uint256[] calldata collateralHints, uint16 minHealthFactor, bool useSafePrices ) external returns (uint256 enabledTokensMaskAfter); function isLiquidatable(address creditAccount, uint16 minHealthFactor) external view returns (bool); function calcDebtAndCollateral(address creditAccount, CollateralCalcTask task) external view returns (CollateralDebtData memory cdd); // ------ // // QUOTAS // // ------ // function poolQuotaKeeper() external view returns (address); function quotedTokensMask() external view returns (uint256); function updateQuota(address creditAccount, address token, int96 quotaChange, uint96 minQuota, uint96 maxQuota) external returns (uint256 tokensToEnable, uint256 tokensToDisable); // --------------------- // // CREDIT MANAGER PARAMS // // --------------------- // function maxEnabledTokens() external view returns (uint8); function fees() external view returns ( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationDiscount, uint16 feeLiquidationExpired, uint16 liquidationDiscountExpired ); function collateralTokensCount() external view returns (uint8); function getTokenMaskOrRevert(address token) external view returns (uint256 tokenMask); function getTokenByMask(uint256 tokenMask) external view returns (address token); function liquidationThresholds(address token) external view returns (uint16 lt); function ltParams(address token) external view returns (uint16 ltInitial, uint16 ltFinal, uint40 timestampRampStart, uint24 rampDuration); function collateralTokenByMask(uint256 tokenMask) external view returns (address token, uint16 liquidationThreshold); // ------------ // // ACCOUNT INFO // // ------------ // function creditAccountInfo(address creditAccount) external view returns ( uint256 debt, uint256 cumulativeIndexLastUpdate, uint128 cumulativeQuotaInterest, uint128 quotaFees, uint256 enabledTokensMask, uint16 flags, uint64 lastDebtUpdate, address borrower ); function getBorrowerOrRevert(address creditAccount) external view returns (address borrower); function flagsOf(address creditAccount) external view returns (uint16); function setFlagFor(address creditAccount, uint16 flag, bool value) external; function enabledTokensMaskOf(address creditAccount) external view returns (uint256); function creditAccounts() external view returns (address[] memory); function creditAccounts(uint256 offset, uint256 limit) external view returns (address[] memory); function creditAccountsLen() external view returns (uint256); // ------------- // // CONFIGURATION // // ------------- // function addToken(address token) external; function setCollateralTokenData( address token, uint16 ltInitial, uint16 ltFinal, uint40 timestampRampStart, uint24 rampDuration ) external; function setFees( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationDiscount, uint16 feeLiquidationExpired, uint16 liquidationDiscountExpired ) external; function setQuotedMask(uint256 quotedTokensMask) external; function setMaxEnabledTokens(uint8 maxEnabledTokens) external; function setContractAllowance(address adapter, address targetContract) external; function setCreditFacade(address creditFacade) external; function setPriceOracle(address priceOracle) external; function setCreditConfigurator(address creditConfigurator) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; enum AllowanceAction { FORBID, ALLOW } /// @notice Struct with credit manager configuration parameters /// @param minDebt Minimum debt amount per account /// @param maxDebt Maximum debt amount per account /// @param degenNFT Whether to apply Degen NFT whitelist logic /// @param expirable Whether facade must be expirable /// @param name Credit manager name struct CreditManagerOpts { uint128 minDebt; uint128 maxDebt; address degenNFT; bool expirable; string name; } interface ICreditConfiguratorV3Events { // ------ // // TOKENS // // ------ // /// @notice Emitted when a token is made recognizable as collateral in the credit manager event AddCollateralToken(address indexed token); /// @notice Emitted when a new collateral token liquidation threshold is set event SetTokenLiquidationThreshold(address indexed token, uint16 liquidationThreshold); /// @notice Emitted when a collateral token liquidation threshold ramping is scheduled event ScheduleTokenLiquidationThresholdRamp( address indexed token, uint16 liquidationThresholdInitial, uint16 liquidationThresholdFinal, uint40 timestampRampStart, uint40 timestampRampEnd ); /// @notice Emitted when a collateral token is forbidden event ForbidToken(address indexed token); /// @notice Emitted when a previously forbidden collateral token is allowed event AllowToken(address indexed token); /// @notice Emitted when a token is made quoted event QuoteToken(address indexed token); // -------- // // ADAPTERS // // -------- // /// @notice Emitted when a new adapter and its target contract are allowed in the credit manager event AllowAdapter(address indexed targetContract, address indexed adapter); /// @notice Emitted when adapter and its target contract are forbidden in the credit manager event ForbidAdapter(address indexed targetContract, address indexed adapter); // -------------- // // CREDIT MANAGER // // -------------- // /// @notice Emitted when a new maximum number of enabled tokens is set in the credit manager event SetMaxEnabledTokens(uint8 maxEnabledTokens); /// @notice Emitted when new fee parameters are set in the credit manager event UpdateFees( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationPremium, uint16 feeLiquidationExpired, uint16 liquidationPremiumExpired ); // -------- // // UPGRADES // // -------- // /// @notice Emitted when a new price oracle is set in the credit manager event SetPriceOracle(address indexed priceOracle); /// @notice Emitted when a new bot list is set in the credit facade event SetBotList(address indexed botList); /// @notice Emitted when a new facade is connected to the credit manager event SetCreditFacade(address indexed creditFacade); /// @notice Emitted when credit manager's configurator contract is upgraded event CreditConfiguratorUpgraded(address indexed creditConfigurator); // ------------- // // CREDIT FACADE // // ------------- // /// @notice Emitted when new debt principal limits are set event SetBorrowingLimits(uint256 minDebt, uint256 maxDebt); /// @notice Emitted when a new max debt per block multiplier is set event SetMaxDebtPerBlockMultiplier(uint8 maxDebtPerBlockMultiplier); /// @notice Emitted when a new max cumulative loss is set event SetMaxCumulativeLoss(uint128 maxCumulativeLoss); /// @notice Emitted when cumulative loss is reset to zero in the credit facade event ResetCumulativeLoss(); /// @notice Emitted when a new expiration timestamp is set in the credit facade event SetExpirationDate(uint40 expirationDate); /// @notice Emitted when an address is added to the list of emergency liquidators event AddEmergencyLiquidator(address indexed liquidator); /// @notice Emitted when an address is removed from the list of emergency liquidators event RemoveEmergencyLiquidator(address indexed liquidator); } /// @title Credit configurator V3 interface interface ICreditConfiguratorV3 is IVersion, ICreditConfiguratorV3Events { function addressProvider() external view returns (address); function creditManager() external view returns (address); function creditFacade() external view returns (address); function underlying() external view returns (address); // ------ // // TOKENS // // ------ // function addCollateralToken(address token, uint16 liquidationThreshold) external; function setLiquidationThreshold(address token, uint16 liquidationThreshold) external; function rampLiquidationThreshold( address token, uint16 liquidationThresholdFinal, uint40 rampStart, uint24 rampDuration ) external; function forbidToken(address token) external; function allowToken(address token) external; function makeTokenQuoted(address token) external; // -------- // // ADAPTERS // // -------- // function allowedAdapters() external view returns (address[] memory); function allowAdapter(address adapter) external; function forbidAdapter(address adapter) external; // -------------- // // CREDIT MANAGER // // -------------- // function setFees( uint16 feeInterest, uint16 feeLiquidation, uint16 liquidationPremium, uint16 feeLiquidationExpired, uint16 liquidationPremiumExpired ) external; function setMaxEnabledTokens(uint8 newMaxEnabledTokens) external; // -------- // // UPGRADES // // -------- // function setPriceOracle(uint256 newVersion) external; function setBotList(uint256 newVersion) external; function setCreditFacade(address newCreditFacade, bool migrateParams) external; function upgradeCreditConfigurator(address newCreditConfigurator) external; // ------------- // // CREDIT FACADE // // ------------- // function setMinDebtLimit(uint128 newMinDebt) external; function setMaxDebtLimit(uint128 newMaxDebt) external; function setMaxDebtPerBlockMultiplier(uint8 newMaxDebtLimitPerBlockMultiplier) external; function forbidBorrowing() external; function setMaxCumulativeLoss(uint128 newMaxCumulativeLoss) external; function resetCumulativeLoss() external; function setExpirationDate(uint40 newExpirationDate) external; function emergencyLiquidators() external view returns (address[] memory); function addEmergencyLiquidator(address liquidator) external; function removeEmergencyLiquidator(address liquidator) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IPriceOracleBase} from "@gearbox-protocol/core-v2/contracts/interfaces/IPriceOracleBase.sol"; struct PriceFeedParams { address priceFeed; uint32 stalenessPeriod; bool skipCheck; uint8 decimals; bool useReserve; bool trusted; } interface IPriceOracleV3Events { /// @notice Emitted when new price feed is set for token event SetPriceFeed( address indexed token, address indexed priceFeed, uint32 stalenessPeriod, bool skipCheck, bool trusted ); /// @notice Emitted when new reserve price feed is set for token event SetReservePriceFeed(address indexed token, address indexed priceFeed, uint32 stalenessPeriod, bool skipCheck); /// @notice Emitted when new reserve price feed status is set for a token event SetReservePriceFeedStatus(address indexed token, bool active); } /// @title Price oracle V3 interface interface IPriceOracleV3 is IPriceOracleBase, IPriceOracleV3Events { function getPriceSafe(address token) external view returns (uint256); function getPriceRaw(address token, bool reserve) external view returns (uint256); function priceFeedsRaw(address token, bool reserve) external view returns (address); function priceFeedParams(address token) external view returns (address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals, bool trusted); function safeConvertToUSD(uint256 amount, address token) external view returns (uint256); // ------------- // // CONFIGURATION // // ------------- // function setPriceFeed(address token, address priceFeed, uint32 stalenessPeriod, bool trusted) external; function setReservePriceFeed(address token, address priceFeed, uint32 stalenessPeriod) external; function setReservePriceFeedStatus(address token, bool active) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.0; import { PriceFeedType } from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol"; /// @title Price feed interface interface IPriceFeed { function priceFeedType() external view returns (PriceFeedType); function version() external view returns (uint256); function decimals() external view returns (uint8); function description() external view returns (string memory); function skipPriceCheck() external view returns (bool); function latestRoundData() external view returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80); } /// @title Updatable price feed interface interface IUpdatablePriceFeed is IPriceFeed { function updatable() external view returns (bool); function updatePrice(bytes calldata data) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; pragma abicoder v1; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; interface IPoolV3Events { /// @notice Emitted when depositing liquidity with referral code event Refer(address indexed onBehalfOf, uint256 indexed referralCode, uint256 amount); /// @notice Emitted when credit account borrows funds from the pool event Borrow(address indexed creditManager, address indexed creditAccount, uint256 amount); /// @notice Emitted when credit account's debt is repaid to the pool event Repay(address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss); /// @notice Emitted when incurred loss can't be fully covered by burning treasury's shares event IncurUncoveredLoss(address indexed creditManager, uint256 loss); /// @notice Emitted when new interest rate model contract is set event SetInterestRateModel(address indexed newInterestRateModel); /// @notice Emitted when new pool quota keeper contract is set event SetPoolQuotaKeeper(address indexed newPoolQuotaKeeper); /// @notice Emitted when new total debt limit is set event SetTotalDebtLimit(uint256 limit); /// @notice Emitted when new credit manager is connected to the pool event AddCreditManager(address indexed creditManager); /// @notice Emitted when new debt limit is set for a credit manager event SetCreditManagerDebtLimit(address indexed creditManager, uint256 newLimit); /// @notice Emitted when new withdrawal fee is set event SetWithdrawFee(uint256 fee); } /// @title Pool V3 interface interface IPoolV3 is IVersion, IPoolV3Events, IERC4626, IERC20Permit { function addressProvider() external view returns (address); function underlyingToken() external view returns (address); function treasury() external view returns (address); function withdrawFee() external view returns (uint16); function creditManagers() external view returns (address[] memory); function availableLiquidity() external view returns (uint256); function expectedLiquidity() external view returns (uint256); function expectedLiquidityLU() external view returns (uint256); // ---------------- // // ERC-4626 LENDING // // ---------------- // function depositWithReferral(uint256 assets, address receiver, uint256 referralCode) external returns (uint256 shares); function mintWithReferral(uint256 shares, address receiver, uint256 referralCode) external returns (uint256 assets); // --------- // // BORROWING // // --------- // function totalBorrowed() external view returns (uint256); function totalDebtLimit() external view returns (uint256); function creditManagerBorrowed(address creditManager) external view returns (uint256); function creditManagerDebtLimit(address creditManager) external view returns (uint256); function creditManagerBorrowable(address creditManager) external view returns (uint256 borrowable); function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external; function repayCreditAccount(uint256 repaidAmount, uint256 profit, uint256 loss) external; // ------------- // // INTEREST RATE // // ------------- // function interestRateModel() external view returns (address); function baseInterestRate() external view returns (uint256); function supplyRate() external view returns (uint256); function baseInterestIndex() external view returns (uint256); function baseInterestIndexLU() external view returns (uint256); function lastBaseInterestUpdate() external view returns (uint40); // ------ // // QUOTAS // // ------ // function poolQuotaKeeper() external view returns (address); function quotaRevenue() external view returns (uint256); function lastQuotaRevenueUpdate() external view returns (uint40); function updateQuotaRevenue(int256 quotaRevenueDelta) external; function setQuotaRevenue(uint256 newQuotaRevenue) external; // ------------- // // CONFIGURATION // // ------------- // function setInterestRateModel(address newInterestRateModel) external; function setPoolQuotaKeeper(address newPoolQuotaKeeper) external; function setTotalDebtLimit(uint256 newLimit) external; function setCreditManagerDebtLimit(address creditManager, uint256 newLimit) external; function setWithdrawFee(uint256 newWithdrawFee) external; }
// 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"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; interface IDegenNFTV2Exceptions { /// @dev Thrown if an access-restricted function was called by non-CreditFacade error CreditFacadeOrConfiguratorOnlyException(); /// @dev Thrown if an access-restricted function was called by non-minter error MinterOnlyException(); /// @dev Thrown if trying to add a burner address that is not a correct Credit Facade error InvalidCreditFacadeException(); /// @dev Thrown if the account's balance is not sufficient for an action (usually a burn) error InsufficientBalanceException(); } interface IDegenNFTV2Events { /// @dev Minted when new minter set event NewMinterSet(address indexed); /// @dev Minted each time when new credit facade added event NewCreditFacadeAdded(address indexed); /// @dev Minted each time when new credit facade added event NewCreditFacadeRemoved(address indexed); } interface IDegenNFTV2 is IDegenNFTV2Exceptions, IDegenNFTV2Events, IVersion, IERC721Metadata { /// @dev address of the current minter function minter() external view returns (address); /// @dev Stores the total number of tokens on holder accounts function totalSupply() external view returns (uint256); /// @dev Stores the base URI for NFT metadata function baseURI() external view returns (string memory); /// @dev Mints a specified amount of tokens to the address /// @param to Address the tokens are minted to /// @param amount The number of tokens to mint function mint(address to, uint256 amount) external; /// @dev Burns a number of tokens from a specified address /// @param from The address a token will be burnt from /// @param amount The number of tokens to burn function burn(address from, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.4; interface IWETH { /// @dev Deposits native ETH into the contract and mints WETH function deposit() external payable; /// @dev Transfers WETH to another account function transfer(address to, uint256 value) external returns (bool); /// @dev Burns WETH from msg.sender and send back native ETH function withdraw(uint256) external; }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; /// @notice Bot info /// @param forbidden Whether bot is forbidden /// @param specialPermissions Mapping credit manager => bot's special permissions /// @param permissions Mapping credit manager => credit account => bot's permissions struct BotInfo { bool forbidden; mapping(address => uint192) specialPermissions; mapping(address => mapping(address => uint192)) permissions; } interface IBotListV3Events { // ----------- // // PERMISSIONS // // ----------- // /// @notice Emitted when new `bot`'s permissions and funding params are set for `creditAccount` in `creditManager` event SetBotPermissions( address indexed bot, address indexed creditManager, address indexed creditAccount, uint192 permissions ); /// @notice Emitted when `bot`'s permissions and funding params are removed for `creditAccount` in `creditManager` event EraseBot(address indexed bot, address indexed creditManager, address indexed creditAccount); // ------------- // // CONFIGURATION // // ------------- // /// @notice Emitted when `bot`'s forbidden status is set event SetBotForbiddenStatus(address indexed bot, bool forbidden); /// @notice Emitted when `bot`'s special permissions in `creditManager` are set event SetBotSpecialPermissions(address indexed bot, address indexed creditManager, uint192 permissions); /// @notice Emitted when `creditManager`'s approved status is set event SetCreditManagerApprovedStatus(address indexed creditManager, bool approved); } /// @title Bot list V3 interface interface IBotListV3 is IBotListV3Events, IVersion { // ----------- // // PERMISSIONS // // ----------- // function botPermissions(address bot, address creditManager, address creditAccount) external view returns (uint192); function activeBots(address creditManager, address creditAccount) external view returns (address[] memory); function getBotStatus(address bot, address creditManager, address creditAccount) external view returns (uint192 permissions, bool forbidden, bool hasSpecialPermissions); function setBotPermissions(address bot, address creditManager, address creditAccount, uint192 permissions) external returns (uint256 activeBotsRemaining); function eraseAllBotPermissions(address creditManager, address creditAccount) external; // ------------- // // CONFIGURATION // // ------------- // function botForbiddenStatus(address bot) external view returns (bool); function botSpecialPermissions(address bot, address creditManager) external view returns (uint192); function approvedCreditManager(address creditManager) external view returns (bool); function setBotForbiddenStatus(address bot, bool forbidden) external; function setBotSpecialPermissions(address bot, address creditManager, uint192 permissions) external; function setCreditManagerApprovedStatus(address creditManager, bool approved) external; }
// SPDX-License-Identifier: MIT // 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; uint16 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals // 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 Foundation, 2023. pragma solidity ^0.8.17; // ------- // // GENERAL // // ------- // /// @notice Thrown on attempting to set an important address to zero address error ZeroAddressException(); /// @notice Thrown when attempting to pass a zero amount to a funding-related operation error AmountCantBeZeroException(); /// @notice Thrown on incorrect input parameter error IncorrectParameterException(); /// @notice Thrown when balance is insufficient to perform an operation error InsufficientBalanceException(); /// @notice Thrown if parameter is out of range error ValueOutOfRangeException(); /// @notice Thrown when trying to send ETH to a contract that is not allowed to receive ETH directly error ReceiveIsNotAllowedException(); /// @notice Thrown on attempting to set an EOA as an important contract in the system error AddressIsNotContractException(address); /// @notice Thrown on attempting to receive a token that is not a collateral token or was forbidden error TokenNotAllowedException(); /// @notice Thrown on attempting to add a token that is already in a collateral list error TokenAlreadyAddedException(); /// @notice Thrown when attempting to use quota-related logic for a token that is not quoted in quota keeper error TokenIsNotQuotedException(); /// @notice Thrown on attempting to interact with an address that is not a valid target contract error TargetContractNotAllowedException(); /// @notice Thrown if function is not implemented error NotImplementedException(); // ------------------ // // CONTRACTS REGISTER // // ------------------ // /// @notice Thrown when an address is expected to be a registered credit manager, but is not error RegisteredCreditManagerOnlyException(); /// @notice Thrown when an address is expected to be a registered pool, but is not error RegisteredPoolOnlyException(); // ---------------- // // ADDRESS PROVIDER // // ---------------- // /// @notice Reverts if address key isn't found in address provider error AddressNotFoundException(); // ----------------- // // POOL, PQK, GAUGES // // ----------------- // /// @notice Thrown by pool-adjacent contracts when a credit manager being connected has a wrong pool address error IncompatibleCreditManagerException(); /// @notice Thrown when attempting to set an incompatible successor staking contract error IncompatibleSuccessorException(); /// @notice Thrown when attempting to vote in a non-approved contract error VotingContractNotAllowedException(); /// @notice Thrown when attempting to unvote more votes than there are error InsufficientVotesException(); /// @notice Thrown when attempting to borrow more than the second point on a two-point curve error BorrowingMoreThanU2ForbiddenException(); /// @notice Thrown when a credit manager attempts to borrow more than its limit in the current block, or in general error CreditManagerCantBorrowException(); /// @notice Thrown when attempting to connect a quota keeper to an incompatible pool error IncompatiblePoolQuotaKeeperException(); /// @notice Thrown when the quota is outside of min/max bounds error QuotaIsOutOfBoundsException(); // -------------- // // CREDIT MANAGER // // -------------- // /// @notice Thrown on failing a full collateral check after multicall error NotEnoughCollateralException(); /// @notice Thrown if an attempt to approve a collateral token to adapter's target contract fails error AllowanceFailedException(); /// @notice Thrown on attempting to perform an action for a credit account that does not exist error CreditAccountDoesNotExistException(); /// @notice Thrown on configurator attempting to add more than 255 collateral tokens error TooManyTokensException(); /// @notice Thrown if more than the maximum number of tokens were enabled on a credit account error TooManyEnabledTokensException(); /// @notice Thrown when attempting to execute a protocol interaction without active credit account set error ActiveCreditAccountNotSetException(); /// @notice Thrown when trying to update credit account's debt more than once in the same block error DebtUpdatedTwiceInOneBlockException(); /// @notice Thrown when trying to repay all debt while having active quotas error DebtToZeroWithActiveQuotasException(); /// @notice Thrown when a zero-debt account attempts to update quota error UpdateQuotaOnZeroDebtAccountException(); /// @notice Thrown when attempting to close an account with non-zero debt error CloseAccountWithNonZeroDebtException(); /// @notice Thrown when value of funds remaining on the account after liquidation is insufficient error InsufficientRemainingFundsException(); /// @notice Thrown when Credit Facade tries to write over a non-zero active Credit Account error ActiveCreditAccountOverridenException(); // ------------------- // // CREDIT CONFIGURATOR // // ------------------- // /// @notice Thrown on attempting to use a non-ERC20 contract or an EOA as a token error IncorrectTokenContractException(); /// @notice Thrown if the newly set LT if zero or greater than the underlying's LT error IncorrectLiquidationThresholdException(); /// @notice Thrown if borrowing limits are incorrect: minLimit > maxLimit or maxLimit > blockLimit error IncorrectLimitsException(); /// @notice Thrown if the new expiration date is less than the current expiration date or current timestamp error IncorrectExpirationDateException(); /// @notice Thrown if a contract returns a wrong credit manager or reverts when trying to retrieve it error IncompatibleContractException(); /// @notice Thrown if attempting to forbid an adapter that is not registered in the credit manager error AdapterIsNotRegisteredException(); // ------------- // // CREDIT FACADE // // ------------- // /// @notice Thrown when attempting to perform an action that is forbidden in whitelisted mode error ForbiddenInWhitelistedModeException(); /// @notice Thrown if credit facade is not expirable, and attempted aciton requires expirability error NotAllowedWhenNotExpirableException(); /// @notice Thrown if a selector that doesn't match any allowed function is passed to the credit facade in a multicall error UnknownMethodException(); /// @notice Thrown when trying to close an account with enabled tokens error CloseAccountWithEnabledTokensException(); /// @notice Thrown if a liquidator tries to liquidate an account with a health factor above 1 error CreditAccountNotLiquidatableException(); /// @notice Thrown if too much new debt was taken within a single block error BorrowedBlockLimitException(); /// @notice Thrown if the new debt principal for a credit account falls outside of borrowing limits error BorrowAmountOutOfLimitsException(); /// @notice Thrown if a user attempts to open an account via an expired credit facade error NotAllowedAfterExpirationException(); /// @notice Thrown if expected balances are attempted to be set twice without performing a slippage check error ExpectedBalancesAlreadySetException(); /// @notice Thrown if attempting to perform a slippage check when excepted balances are not set error ExpectedBalancesNotSetException(); /// @notice Thrown if balance of at least one token is less than expected during a slippage check error BalanceLessThanExpectedException(); /// @notice Thrown when trying to perform an action that is forbidden when credit account has enabled forbidden tokens error ForbiddenTokensException(); /// @notice Thrown when new forbidden tokens are enabled during the multicall error ForbiddenTokenEnabledException(); /// @notice Thrown when enabled forbidden token balance is increased during the multicall error ForbiddenTokenBalanceIncreasedException(); /// @notice Thrown when the remaining token balance is increased during the liquidation error RemainingTokenBalanceIncreasedException(); /// @notice Thrown if `botMulticall` is called by an address that is not approved by account owner or is forbidden error NotApprovedBotException(); /// @notice Thrown when attempting to perform a multicall action with no permission for it error NoPermissionException(uint256 permission); /// @notice Thrown when attempting to give a bot unexpected permissions error UnexpectedPermissionsException(); /// @notice Thrown when a custom HF parameter lower than 10000 is passed into the full collateral check error CustomHealthFactorTooLowException(); /// @notice Thrown when submitted collateral hint is not a valid token mask error InvalidCollateralHintException(); // ------ // // ACCESS // // ------ // /// @notice Thrown on attempting to call an access restricted function not as credit account owner error CallerNotCreditAccountOwnerException(); /// @notice Thrown on attempting to call an access restricted function not as configurator error CallerNotConfiguratorException(); /// @notice Thrown on attempting to call an access-restructed function not as account factory error CallerNotAccountFactoryException(); /// @notice Thrown on attempting to call an access restricted function not as credit manager error CallerNotCreditManagerException(); /// @notice Thrown on attempting to call an access restricted function not as credit facade error CallerNotCreditFacadeException(); /// @notice Thrown on attempting to call an access restricted function not as controller or configurator error CallerNotControllerException(); /// @notice Thrown on attempting to pause a contract without pausable admin rights error CallerNotPausableAdminException(); /// @notice Thrown on attempting to unpause a contract without unpausable admin rights error CallerNotUnpausableAdminException(); /// @notice Thrown on attempting to call an access restricted function not as gauge error CallerNotGaugeException(); /// @notice Thrown on attempting to call an access restricted function not as quota keeper error CallerNotPoolQuotaKeeperException(); /// @notice Thrown on attempting to call an access restricted function not as voter error CallerNotVoterException(); /// @notice Thrown on attempting to call an access restricted function not as allowed adapter error CallerNotAdapterException(); /// @notice Thrown on attempting to call an access restricted function not as migrator error CallerNotMigratorException(); /// @notice Thrown when an address that is not the designated executor attempts to execute a transaction error CallerNotExecutorException(); /// @notice Thrown on attempting to call an access restricted function not as veto admin error CallerNotVetoAdminException(); // ------------------- // // CONTROLLER TIMELOCK // // ------------------- // /// @notice Thrown when the new parameter values do not satisfy required conditions error ParameterChecksFailedException(); /// @notice Thrown when attempting to execute a non-queued transaction error TxNotQueuedException(); /// @notice Thrown when attempting to execute a transaction that is either immature or stale error TxExecutedOutsideTimeWindowException(); /// @notice Thrown when execution of a transaction fails error TxExecutionRevertedException(); /// @notice Thrown when the value of a parameter on execution is different from the value on queue error ParameterChangedAfterQueuedTxException(); // -------- // // BOT LIST // // -------- // /// @notice Thrown when attempting to set non-zero permissions for a forbidden or special bot error InvalidBotException(); // --------------- // // ACCOUNT FACTORY // // --------------- // /// @notice Thrown when trying to deploy second master credit account for a credit manager error MasterCreditAccountAlreadyDeployedException(); /// @notice Thrown when trying to rescue funds from a credit account that is currently in use error CreditAccountIsInUseException(); // ------------ // // PRICE ORACLE // // ------------ // /// @notice Thrown on attempting to set a token price feed to an address that is not a correct price feed error IncorrectPriceFeedException(); /// @notice Thrown on attempting to interact with a price feed for a token not added to the price oracle error PriceFeedDoesNotExistException(); /// @notice Thrown when price feed returns incorrect price for a token error IncorrectPriceException(); /// @notice Thrown when token's price feed becomes stale error StalePriceException();
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./IERC20Permit.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IDaiLikePermit { function permit( address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IPermit2 { struct PermitDetails { // ERC20 token address address token; // the maximum amount allowed to spend uint160 amount; // timestamp at which a spender's token allowances become invalid uint48 expiration; // an incrementing value indexed per owner,token,and spender for each signature uint48 nonce; } /// @notice The permit message signed for a single token allownce struct PermitSingle { // the permit data for a single token alownce PermitDetails details; // address permissioned on the allowed tokens address spender; // deadline on the permit signature uint256 sigDeadline; } /// @notice Packed allowance struct PackedAllowance { // amount allowed uint160 amount; // permission expiry uint48 expiration; // an incrementing value indexed per owner,token,and spender for each signature uint48 nonce; } function transferFrom(address user, address spender, uint160 amount, address token) external; function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external; function allowance(address user, address token, address spender) external view returns (PackedAllowance memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Revert reason forwarder. library RevertReasonForwarder { /// @dev Forwards latest externall call revert. function reRevert() internal pure { // bubble up revert reason from latest external call assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; struct Balance { address token; uint256 balance; } library BalanceOps { error UnknownToken(address); function copyBalance(Balance memory b) internal pure returns (Balance memory) { return Balance({ token: b.token, balance: b.balance }); } function addBalance( Balance[] memory b, address token, uint256 amount ) internal pure { b[getIndex(b, token)].balance += amount; } function subBalance( Balance[] memory b, address token, uint256 amount ) internal pure { b[getIndex(b, token)].balance -= amount; } function getBalance(Balance[] memory b, address token) internal pure returns (uint256 amount) { return b[getIndex(b, token)].balance; } function setBalance( Balance[] memory b, address token, uint256 amount ) internal pure { b[getIndex(b, token)].balance = amount; } function getIndex(Balance[] memory b, address token) internal pure returns (uint256 index) { for (uint256 i; i < b.length; ) { if (b[i].token == token) { return i; } unchecked { ++i; } } revert UnknownToken(token); } function copy(Balance[] memory b, uint256 len) internal pure returns (Balance[] memory res) { res = new Balance[](len); for (uint256 i; i < len; ) { res[i] = copyBalance(b[i]); unchecked { ++i; } } } function clone(Balance[] memory b) internal pure returns (Balance[] memory) { return copy(b, b.length); } function getModifiedAfterSwap( Balance[] memory b, address tokenFrom, uint256 amountFrom, address tokenTo, uint256 amountTo ) internal pure returns (Balance[] memory res) { res = copy(b, b.length); setBalance(res, tokenFrom, getBalance(b, tokenFrom) - amountFrom); setBalance(res, tokenTo, getBalance(b, tokenTo) + amountTo); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (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 Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { 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; 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); }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {IACL} from "@gearbox-protocol/core-v2/contracts/interfaces/IACL.sol"; import {AP_ACL, IAddressProviderV3, NO_VERSION_CONTROL} from "../interfaces/IAddressProviderV3.sol"; import {CallerNotConfiguratorException} from "../interfaces/IExceptions.sol"; import {SanityCheckTrait} from "./SanityCheckTrait.sol"; /// @title ACL trait /// @notice Utility class for ACL (access-control list) consumers abstract contract ACLTrait is SanityCheckTrait { /// @notice ACL contract address address public immutable acl; /// @notice Constructor /// @param addressProvider Address provider contract address constructor(address addressProvider) nonZeroAddress(addressProvider) { acl = IAddressProviderV3(addressProvider).getAddressOrRevert(AP_ACL, NO_VERSION_CONTROL); } /// @dev Ensures that function caller has configurator role modifier configuratorOnly() { _ensureCallerIsConfigurator(); _; } /// @dev Reverts if the caller is not the configurator /// @dev Used to cut contract size on modifiers function _ensureCallerIsConfigurator() internal view { if (!_isConfigurator({account: msg.sender})) { revert CallerNotConfiguratorException(); } } /// @dev Checks whether given account has configurator role function _isConfigurator(address account) internal view returns (bool) { return IACL(acl).isConfigurator(account); } }
// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; uint8 constant NOT_ENTERED = 1; uint8 constant ENTERED = 2; /// @title Reentrancy guard trait /// @notice Same as OpenZeppelin's `ReentrancyGuard` but only uses 1 byte of storage instead of 32 abstract contract ReentrancyGuardTrait { uint8 internal _reentrancyStatus = NOT_ENTERED; /// @dev Prevents a contract from calling itself, directly or indirectly. /// Calling a `nonReentrant` function from another `nonReentrant` /// function is not supported. It is possible to prevent this from happening /// by making the `nonReentrant` function external, and making it call a /// `private` function that does the actual work. modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true _ensureNotEntered(); // Any calls to nonReentrant after this point will fail _reentrancyStatus = ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _reentrancyStatus = NOT_ENTERED; } /// @dev Reverts if the contract is currently entered /// @dev Used to cut contract size on modifiers function _ensureNotEntered() internal view { require(_reentrancyStatus != ENTERED, "ReentrancyGuard: reentrant call"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; struct MultiCall { address target; bytes callData; } library MultiCallOps { function copyMulticall(MultiCall memory call) internal pure returns (MultiCall memory) { return MultiCall({ target: call.target, callData: call.callData }); } function trim(MultiCall[] memory calls) internal pure returns (MultiCall[] memory trimmed) { uint256 len = calls.length; if (len == 0) return calls; uint256 foundLen; while (calls[foundLen].target != address(0)) { unchecked { ++foundLen; if (foundLen == len) return calls; } } if (foundLen > 0) return copy(calls, foundLen); } function copy(MultiCall[] memory calls, uint256 len) internal pure returns (MultiCall[] memory res) { res = new MultiCall[](len); for (uint256 i; i < len; ) { res[i] = copyMulticall(calls[i]); unchecked { ++i; } } } function clone(MultiCall[] memory calls) internal pure returns (MultiCall[] memory res) { return copy(calls, calls.length); } function append(MultiCall[] memory calls, MultiCall memory newCall) internal pure returns (MultiCall[] memory res) { uint256 len = calls.length; res = new MultiCall[](len + 1); for (uint256 i; i < len; ) { res[i] = copyMulticall(calls[i]); unchecked { ++i; } } res[len] = copyMulticall(newCall); } function prepend(MultiCall[] memory calls, MultiCall memory newCall) internal pure returns (MultiCall[] memory res) { uint256 len = calls.length; res = new MultiCall[](len + 1); res[0] = copyMulticall(newCall); for (uint256 i = 1; i < len + 1; ) { res[i] = copyMulticall(calls[i]); unchecked { ++i; } } } function concat(MultiCall[] memory calls1, MultiCall[] memory calls2) internal pure returns (MultiCall[] memory res) { uint256 len1 = calls1.length; uint256 lenTotal = len1 + calls2.length; if (lenTotal == calls1.length) return clone(calls1); if (lenTotal == calls2.length) return clone(calls2); res = new MultiCall[](lenTotal); for (uint256 i; i < lenTotal; ) { res[i] = (i < len1) ? copyMulticall(calls1[i]) : copyMulticall(calls2[i - len1]); unchecked { ++i; } } } }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Holdings, 2022 pragma solidity ^0.8.10; /// @title Version interface /// @notice Defines contract version interface IVersion { /// @notice Contract version function version() external view returns (uint256); }
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {BalanceDelta} from "../libraries/BalancesLogic.sol"; import {RevocationPair} from "./ICreditManagerV3.sol"; // ----------- // // PERMISSIONS // // ----------- // uint192 constant ADD_COLLATERAL_PERMISSION = 1; uint192 constant INCREASE_DEBT_PERMISSION = 1 << 1; uint192 constant DECREASE_DEBT_PERMISSION = 1 << 2; uint192 constant ENABLE_TOKEN_PERMISSION = 1 << 3; uint192 constant DISABLE_TOKEN_PERMISSION = 1 << 4; uint192 constant WITHDRAW_COLLATERAL_PERMISSION = 1 << 5; uint192 constant UPDATE_QUOTA_PERMISSION = 1 << 6; uint192 constant REVOKE_ALLOWANCES_PERMISSION = 1 << 7; uint192 constant EXTERNAL_CALLS_PERMISSION = 1 << 16; uint256 constant ALL_CREDIT_FACADE_CALLS_PERMISSION = ADD_COLLATERAL_PERMISSION | WITHDRAW_COLLATERAL_PERMISSION | INCREASE_DEBT_PERMISSION | DECREASE_DEBT_PERMISSION | ENABLE_TOKEN_PERMISSION | DISABLE_TOKEN_PERMISSION | UPDATE_QUOTA_PERMISSION | REVOKE_ALLOWANCES_PERMISSION; uint256 constant ALL_PERMISSIONS = ALL_CREDIT_FACADE_CALLS_PERMISSION | EXTERNAL_CALLS_PERMISSION; // ----- // // FLAGS // // ----- // /// @dev Indicates that there are enabled forbidden tokens on the account before multicall uint256 constant FORBIDDEN_TOKENS_BEFORE_CALLS = 1 << 192; /// @dev Indicates that external calls from credit account to adapters were made during multicall, /// set to true on the first call to the adapter uint256 constant EXTERNAL_CONTRACT_WAS_CALLED = 1 << 193; /// @title Credit facade V3 multicall interface /// @dev Unless specified otherwise, all these methods are only available in `openCreditAccount`, /// `closeCreditAccount`, `multicall`, and, with account owner's permission, `botMulticall` interface ICreditFacadeV3Multicall { /// @notice Updates the price for a token with on-demand updatable price feed /// @param token Token to push the price update for /// @param reserve Whether to update reserve price feed or main price feed /// @param data Data to call `updatePrice` with /// @dev Calls of this type must be placed before all other calls in the multicall not to revert /// @dev This method is available in all kinds of multicalls function onDemandPriceUpdate(address token, bool reserve, bytes calldata data) external; /// @notice Stores expected token balances (current balance + delta) after operations for a slippage check. /// Normally, a check is performed automatically at the end of the multicall, but more fine-grained /// behavior can be achieved by placing `storeExpectedBalances` and `compareBalances` where needed. /// @param balanceDeltas Array of (token, minBalanceDelta) pairs, deltas are allowed to be negative /// @dev Reverts if expected balances are already set /// @dev This method is available in all kinds of multicalls function storeExpectedBalances(BalanceDelta[] calldata balanceDeltas) external; /// @notice Performs a slippage check ensuring that current token balances are greater than saved expected ones /// @dev Resets stored expected balances /// @dev Reverts if expected balances are not stored /// @dev This method is available in all kinds of multicalls function compareBalances() external; /// @notice Adds collateral to account /// @param token Token to add /// @param amount Amount to add /// @dev Requires token approval from caller to the credit manager /// @dev This method can also be called during liquidation function addCollateral(address token, uint256 amount) external; /// @notice Adds collateral to account using signed EIP-2612 permit message /// @param token Token to add /// @param amount Amount to add /// @param deadline Permit deadline /// @dev `v`, `r`, `s` must be a valid signature of the permit message from caller to the credit manager /// @dev This method can also be called during liquidation function addCollateralWithPermit(address token, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /// @notice Increases account's debt /// @param amount Underlying amount to borrow /// @dev Increasing debt is prohibited when closing an account /// @dev Increasing debt is prohibited if it was previously updated in the same block /// @dev The resulting debt amount must be within allowed range /// @dev Increasing debt is prohibited if there are forbidden tokens enabled as collateral on the account /// @dev After debt increase, total amount borrowed by the credit manager in the current block must not exceed /// the limit defined in the facade function increaseDebt(uint256 amount) external; /// @notice Decreases account's debt /// @param amount Underlying amount to repay, value above account's total debt indicates full repayment /// @dev Decreasing debt is prohibited when opening an account /// @dev Decreasing debt is prohibited if it was previously updated in the same block /// @dev The resulting debt amount must be within allowed range or zero /// @dev Full repayment brings account into a special mode that skips collateral checks and thus requires /// an account to have no potential debt sources, e.g., all quotas must be disabled function decreaseDebt(uint256 amount) external; /// @notice Updates account's quota for a token /// @param token Token to update the quota for /// @param quotaChange Desired quota change in underlying token units (`type(int96).min` to disable quota) /// @param minQuota Minimum resulting account's quota for token required not to revert /// @dev Enables token as collateral if quota is increased from zero, disables if decreased to zero /// @dev Quota increase is prohibited if there are forbidden tokens enabled as collateral on the account /// @dev Quota update is prohibited if account has zero debt /// @dev Resulting account's quota for token must not exceed the limit defined in the facade function updateQuota(address token, int96 quotaChange, uint96 minQuota) external; /// @notice Withdraws collateral from account /// @param token Token to withdraw /// @param amount Amount to withdraw, `type(uint256).max` to withdraw all balance /// @param to Token recipient /// @dev This method can also be called during liquidation /// @dev Withdrawals are prohibited in multicalls if there are forbidden tokens enabled as collateral on the account /// @dev Withdrawals activate safe pricing (min of main and reserve feeds) in collateral check function withdrawCollateral(address token, uint256 amount, address to) external; /// @notice Sets advanced collateral check parameters /// @param collateralHints Optional array of token masks to check first to reduce the amount of computation /// when known subset of account's collateral tokens covers all the debt /// @param minHealthFactor Min account's health factor in bps in order not to revert, must be at least 10000 function setFullCheckParams(uint256[] calldata collateralHints, uint16 minHealthFactor) external; /// @notice Enables token as account's collateral, which makes it count towards account's total value /// @param token Token to enable as collateral /// @dev Enabling forbidden tokens is prohibited /// @dev Quoted tokens can only be enabled via `updateQuota`, this method is no-op for them function enableToken(address token) external; /// @notice Disables token as account's collateral /// @param token Token to disable as collateral /// @dev Quoted tokens can only be disabled via `updateQuota`, this method is no-op for them function disableToken(address token) external; /// @notice Revokes account's allowances for specified spender/token pairs /// @param revocations Array of spender/token pairs /// @dev Exists primarily to allow users to revoke allowances on accounts from old account factory on mainnet function revokeAdapterAllowances(RevocationPair[] calldata revocations) external; }
// 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 Price oracle base interface /// @notice Functions shared accross newer and older versions interface IPriceOracleBase is IVersion { function getPrice(address token) external view returns (uint256); function convertToUSD( uint256 amount, address token ) external view returns (uint256); function convertFromUSD( uint256 amount, address token ) external view returns (uint256); function convert( uint256 amount, address tokenFrom, address tokenTo ) external view returns (uint256); function priceFeeds( address token ) external view returns (address priceFeed); }
// SPDX-License-Identifier: UNLICENSED // Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way. // (c) Gearbox Foundation, 2023 pragma solidity ^0.8.17; enum PriceFeedType { CHAINLINK_ORACLE, YEARN_ORACLE, CURVE_2LP_ORACLE, CURVE_3LP_ORACLE, CURVE_4LP_ORACLE, ZERO_ORACLE, WSTETH_ORACLE, BOUNDED_ORACLE, COMPOSITE_ORACLE, WRAPPED_AAVE_V2_ORACLE, COMPOUND_V2_ORACLE, BALANCER_STABLE_LP_ORACLE, BALANCER_WEIGHTED_LP_ORACLE, CURVE_CRYPTO_ORACLE, THE_SAME_AS, REDSTONE_ORACLE, ERC4626_VAULT_ORACLE, NETWORK_DEPENDENT, CURVE_USD_ORACLE, PYTH_ORACLE, MELLOW_LRT_ORACLE, PENDLE_PT_TWAP_ORACLE }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// 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: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; import {ZeroAddressException} from "../interfaces/IExceptions.sol"; /// @title Sanity check trait abstract contract SanityCheckTrait { /// @dev Ensures that passed address is non-zero modifier nonZeroAddress(address addr) { _revertIfZeroAddress(addr); _; } /// @dev Reverts if address is zero function _revertIfZeroAddress(address addr) private pure { if (addr == address(0)) revert ZeroAddressException(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@1inch/=node_modules/@1inch/", "@arbitrum/=node_modules/@arbitrum/", "@chainlink/=node_modules/@chainlink/", "@eth-optimism/=node_modules/@eth-optimism/", "@gearbox-protocol/=node_modules/@gearbox-protocol/", "@openzeppelin/=node_modules/@openzeppelin/", "@redstone-finance/=node_modules/@redstone-finance/", "ds-test/=lib/forge-std/lib/ds-test/src/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_creditManager","type":"address"},{"internalType":"address","name":"_degenNFT","type":"address"},{"internalType":"bool","name":"_expirable","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BalanceLessThanExpectedException","type":"error"},{"inputs":[],"name":"BorrowAmountOutOfLimitsException","type":"error"},{"inputs":[],"name":"BorrowedBlockLimitException","type":"error"},{"inputs":[],"name":"CallerNotConfiguratorException","type":"error"},{"inputs":[],"name":"CallerNotCreditAccountOwnerException","type":"error"},{"inputs":[],"name":"CallerNotPausableAdminException","type":"error"},{"inputs":[],"name":"CallerNotUnpausableAdminException","type":"error"},{"inputs":[],"name":"CloseAccountWithEnabledTokensException","type":"error"},{"inputs":[],"name":"CreditAccountNotLiquidatableException","type":"error"},{"inputs":[],"name":"CustomHealthFactorTooLowException","type":"error"},{"inputs":[],"name":"ExpectedBalancesAlreadySetException","type":"error"},{"inputs":[],"name":"ExpectedBalancesNotSetException","type":"error"},{"inputs":[],"name":"ForbiddenInWhitelistedModeException","type":"error"},{"inputs":[],"name":"ForbiddenTokenBalanceIncreasedException","type":"error"},{"inputs":[],"name":"ForbiddenTokenEnabledException","type":"error"},{"inputs":[],"name":"ForbiddenTokensException","type":"error"},{"inputs":[],"name":"IncorrectParameterException","type":"error"},{"inputs":[],"name":"InvalidCollateralHintException","type":"error"},{"inputs":[{"internalType":"uint256","name":"permission","type":"uint256"}],"name":"NoPermissionException","type":"error"},{"inputs":[],"name":"NotAllowedAfterExpirationException","type":"error"},{"inputs":[],"name":"NotAllowedWhenNotExpirableException","type":"error"},{"inputs":[],"name":"NotApprovedBotException","type":"error"},{"inputs":[],"name":"PriceFeedDoesNotExistException","type":"error"},{"inputs":[],"name":"RemainingTokenBalanceIncreasedException","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"TargetContractNotAllowedException","type":"error"},{"inputs":[],"name":"UnexpectedPermissionsException","type":"error"},{"inputs":[],"name":"UnknownMethodException","type":"error"},{"inputs":[],"name":"ZeroAddressException","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AddCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"}],"name":"CloseCreditAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DecreaseDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"targetContract","type":"address"}],"name":"Execute","type":"event"},{"anonymous":false,"inputs":[],"name":"FinishMultiCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreaseDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"remainingFunds","type":"uint256"}],"name":"LiquidateCreditAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newController","type":"address"}],"name":"NewController","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalfOf","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"referralCode","type":"uint256"}],"name":"OpenCreditAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"StartMultiCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creditAccount","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawCollateral","type":"event"},{"inputs":[],"name":"acl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"botList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct MultiCall[]","name":"calls","type":"tuple[]"}],"name":"botMulticall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"canLiquidateWhilePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct MultiCall[]","name":"calls","type":"tuple[]"}],"name":"closeCreditAccount","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtLimits","outputs":[{"internalType":"uint128","name":"minDebt","type":"uint128"},{"internalType":"uint128","name":"maxDebt","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"degenNFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expirable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expirationDate","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forbiddenTokenMask","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct MultiCall[]","name":"calls","type":"tuple[]"}],"name":"liquidateCreditAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lossParams","outputs":[{"internalType":"uint128","name":"currentCumulativeLoss","type":"uint128"},{"internalType":"uint128","name":"maxCumulativeLoss","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDebtPerBlockMultiplier","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxQuotaMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct MultiCall[]","name":"calls","type":"tuple[]"}],"name":"multicall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"onBehalfOf","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct MultiCall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"referralCode","type":"uint256"}],"name":"openCreditAccount","outputs":[{"internalType":"address","name":"creditAccount","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBotList","type":"address"}],"name":"setBotList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creditAccount","type":"address"},{"internalType":"address","name":"bot","type":"address"},{"internalType":"uint192","name":"permissions","type":"uint192"}],"name":"setBotPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newMaxCumulativeLoss","type":"uint128"},{"internalType":"bool","name":"resetCumulativeLoss","type":"bool"}],"name":"setCumulativeLossParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newMinDebt","type":"uint128"},{"internalType":"uint128","name":"newMaxDebt","type":"uint128"},{"internalType":"uint8","name":"newMaxDebtPerBlockMultiplier","type":"uint8"}],"name":"setDebtLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"enum AllowanceAction","name":"allowance","type":"uint8"}],"name":"setEmergencyLiquidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"newExpirationDate","type":"uint40"}],"name":"setExpirationDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"enum AllowanceAction","name":"allowance","type":"uint8"}],"name":"setTokenAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101206040526000805461ff0019166101001790553480156200002157600080fd5b506040516200561b3803806200561b8339810160408190526200004491620003bf565b826001600160a01b0316632954018c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000083573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000a9919062000411565b8080620000b68162000377565b604051632bdad0e360e11b8152621050d360ea1b6004820152600060248201526001600160a01b038316906357b5a1c690604401602060405180830381865afa15801562000108573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200012e919062000411565b6001600160a01b031660808190526000805460ff1916905560408051638da5cb5b60e01b81529051919350638da5cb5b92506004808201926020929091908290030181865afa15801562000186573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ac919062000411565b6000805462010000600160b01b031916620100006001600160a01b039384160217815590851660a081905260408051630a55006360e21b815290519293509091632954018c916004808201926020929091908290030181865afa15801562000218573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200023e919062000411565b604051632bdad0e360e11b8152692ba2aa242faa27a5a2a760b11b6004820152600060248201529091506001600160a01b038216906357b5a1c690604401602060405180830381865afa1580156200029a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002c0919062000411565b6001600160a01b0390811660e052604051632bdad0e360e11b8152671093d517d31254d560c21b600482015261012c6024820152908216906357b5a1c690604401602060405180830381865afa1580156200031f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000345919062000411565b600280546001600160a01b0319166001600160a01b039283161790559290921661010052151560c05250620004369050565b6001600160a01b0381166200039f57604051635919af9760e11b815260040160405180910390fd5b50565b80516001600160a01b0381168114620003ba57600080fd5b919050565b600080600060608486031215620003d557600080fd5b620003e084620003a2565b9250620003f060208501620003a2565b9150604084015180151581146200040657600080fd5b809150509250925092565b6000602082840312156200042457600080fd5b6200042f82620003a2565b9392505050565b60805160a05160c05160e051610100516150b262000569600039600081816104c701528181610bea0152610c98015260008181610309015281816117eb01526118690152600081816105110152818161148e0152612b1b015260008181610545015281816108800152818161092601528181610a4a01528181610d2d01528181610f8301528181611145015281816112fb015281816115810152818161166d015281816118cf01528181612123015281816123cf01528181612547015281816128ed01528181612abf01528181612ba3015281816130260152818161316f015281816132cd015281816134fe01528181613628015281816137a80152818161384f01528181613a7c0152613d950152600081816105b90152818161393701528181613a320152613b1301526150b26000f3fe6080604052600436106101d85760003560e01c80638ad1386e11610102578063c5b73ed011610095578063eb9606df11610064578063eb9606df146105fb578063ebe4107c1461061b578063f6722f621461062e578063f77c47911461064e57600080fd5b8063c5b73ed014610567578063c5d7ca3914610587578063de287359146105a7578063e3f46b26146105db57600080fd5b80639408b63f116100d15780639408b63f146104b55780639fd12b77146104e9578063b1836d32146104ff578063c12c21c01461053357600080fd5b80638ad1386e146104275780638f6204871461044757806392beab1d1461048257806392eefe9b1461049557600080fd5b80633fc8cef31161017a5780635c975abb116101495780635c975abb146103c55780637e2ca9db146103dd5780638456cb59146103fd578063874b2e021461041257600080fd5b80633fc8cef3146102f7578063478ade3614610343578063503931091461037657806354fd4d50146103a157600080fd5b806326f30692116101b657806326f306921461026f57806336b2ced31461028f57806338975bc4146102a25780633f4ba83a146102e257600080fd5b80630103dc6b146101dd5780631656af9d146101ff578063166bf9d91461021f575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004614151565b610674565b005b34801561020b57600080fd5b506101fd61021a36600461419b565b6106c9565b34801561022b57600080fd5b5060035461024a906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152015b60405180910390f35b34801561027b57600080fd5b506101fd61028a3660046141f7565b610758565b6101fd61029d366004614275565b61079f565b3480156102ae57600080fd5b506102d26102bd3660046142ca565b60066020526000908152604090205460ff1681565b6040519015158152602001610266565b3480156102ee57600080fd5b506101fd6109ce565b34801561030357600080fd5b5061032b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610266565b34801561034f57600080fd5b5060005461036490600160d81b900460ff1681565b60405160ff9091168152602001610266565b34801561038257600080fd5b5060055461024a906001600160801b0380821691600160801b90041682565b3480156103ad57600080fd5b506103b761012d81565b604051908152602001610266565b3480156103d157600080fd5b5060005460ff166102d2565b3480156103e957600080fd5b506101fd6103f8366004614275565b6109e0565b34801561040957600080fd5b506101fd610b65565b34801561041e57600080fd5b506103b7600281565b34801561043357600080fd5b506101fd6104423660046142ca565b610b75565b34801561045357600080fd5b5060005461046c90600160b01b900464ffffffffff1681565b60405164ffffffffff9091168152602001610266565b61032b6104903660046142e7565b610bb7565b3480156104a157600080fd5b506101fd6104b03660046142ca565b610e49565b3480156104c157600080fd5b5061032b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104f557600080fd5b506103b760045481565b34801561050b57600080fd5b506102d27f000000000000000000000000000000000000000000000000000000000000000081565b34801561053f57600080fd5b5061032b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561057357600080fd5b506101fd610582366004614358565b610ed5565b34801561059357600080fd5b506101fd6105a23660046141f7565b611066565b3480156105b357600080fd5b5061032b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105e757600080fd5b506101fd6105f63660046143a3565b6110ac565b34801561060757600080fd5b506101fd610616366004614408565b611484565b6101fd610629366004614275565b611522565b34801561063a57600080fd5b5060025461032b906001600160a01b031681565b34801561065a57600080fd5b5060005461032b906201000090046001600160a01b031681565b61067c61157f565b600580546001600160801b03808516600160801b02911617905580156106c557600580547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b5050565b6106d161157f565b6001600160801b036106e883821660ff8416614445565b1061071f576040517f47fbaa9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160801b03918216600160801b0291909216176003556000805460ff909216600160d81b0260ff60d81b19909216919091179055565b61076061157f565b600061076b83611632565b905060018260018111156107815761078161445c565b14610790576004548117610797565b6004548119165b600455505050565b826107a9816116e1565b6107b1611734565b6107b9611787565b6000805461ff0019166102001790556107d06117e3565b60006107db85611894565b905082156107fe5760006107f686868685620100fd86611900565b604001519150505b8015610836576040517f77349a6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600161084186612394565b1661ffff166000146108ee576002546040517f7bdfc8740000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152878116602483015290911690637bdfc87490604401600060405180830381600087803b1580156108d557600080fd5b505af11580156108e9573d6000803e3d6000fd5b505050505b6040517f7687f6700000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301527f00000000000000000000000000000000000000000000000000000000000000001690637687f67090602401600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040513392506001600160a01b03881691507f460ad03b1cf79b1d64d3aefa28475f110ab66e84649c52bb41ed796b9b39198190600090a350506000805461ff001916610100179055505050565b6109d661243c565b6109de61247b565b565b6109e8611734565b6109f06124cd565b6109f8611787565b6000805461ff001916610200179055610a108361250c565b506002546040517f68f8085c0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152858116604483015260009283928392909116906368f8085c90606401606060405180830381865afa158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd9190614472565b925092506001600160c01b031692508260001480610ae85750815b80610b0b575080158015610b0b57506001610b0287612394565b1661ffff166000145b15610b42576040517f8fd689c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b4e868686866125b5565b50506000805461ff00191661010017905550505050565b610b6d612626565b6109de612665565b610b7d61157f565b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000610bc1611734565b610bc96124cd565b610bd1611787565b6000805461ff001916610200179055610be86117e3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610cf557336001600160a01b03861614610c59576040517fd380b4d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152600160248301527f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac90604401600060405180830381600087803b158015610cdc57600080fd5b505af1158015610cf0573d6000803e3d6000fd5b505050505b6040517f43fe7bbe0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301527f000000000000000000000000000000000000000000000000000000000000000016906343fe7bbe906024016020604051808303816000875af1158015610d76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9a91906144bf565b9050336001600160a01b0316856001600160a01b0316826001600160a01b03167f6e4927aac3383b13ffc5b6f44447693caf351f2f7ca800c9b4463b76997911b085604051610deb91815260200190565b60405180910390a48215610e325760606000610e0786866126a2565b90506000610e1c84888884620100fb87611900565b9050610e2e84600083866004546128e9565b5050505b6000805461ff001916610100179055949350505050565b610e51612a4f565b6000546001600160a01b03828116620100009092041614610ed257600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b03841690810291909117825560405190917fe253457d9ad994ca9682fc3bbc38c890dca73a2d5ecee3809e548bac8b00d7c691a25b50565b82610edf816116e1565b610ee7611787565b6000805461ff00191661020017905577fffffffffffffffffffffffffffffffffffffffffffeff00821615610f48576040517f4b6a275600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517fc9c45fa00000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015286811660448301526001600160c01b0385166064830152600092169063c9c45fa0906084016020604051808303816000875af1158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101191906144dc565b90508060000361102d576110288560016000612a75565b611050565b600161103886612394565b1661ffff166000036110505761105085600180612a75565b50506000805461ff001916610100179055505050565b61106e61157f565b60018160018111156110825761108261445c565b6001600160a01b039093166000908152600660205260409020805460ff1916919093141790915550565b60005460ff1615806110cd57503360009081526006602052604090205460ff165b61111e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064015b60405180910390fd5b611126611787565b6000805461ff00191661020017815561113f83836126a2565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630d334ca68760036040518363ffffffff1660e01b81526004016111929291906144f5565b600060405180830381865afa1580156111af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111d79190810190614659565b60c08101516101208201518251929350109015806112035750801580156112035750611201612b17565b155b1561123a576040517f234b893b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014082018051600119169081905260009061125a908990612b71612bda565b90506000611283898888876101400151602060016201000017176001600160c01b03168a611900565b604081015161014086018051909116908190529091506000906112aa908b90856001612cf7565b9050806112e3576040517f393964ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610140850151600117856101400181815250506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e2f1490f8d898e8a156040518563ffffffff1660e01b815260040161134c94939291906147aa565b60408051808303816000875af115801561136a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138e91906148ae565b604080516001600160a01b038f811682526020820185905293955091935033928f16917f7dfecd8419723a9d3954585a30c2a270165d70aafa146c11c1e1b88ae1439064910160405180910390a38015611467576000805460ff60d81b191681556005805483929061140a9084906001600160801b03166148d2565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555061143a60005460ff1690565b15801561145a57506005546001600160801b03600160801b820481169116115b1561146757611467612665565b50506000805461ff00191661010017905550505050505050505050565b61148c61157f565b7f00000000000000000000000000000000000000000000000000000000000000006114e3576040517f50dd11fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805464ffffffffff909216600160b01b027fffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b8261152c816116e1565b611534611734565b61153c6124cd565b611544611787565b6000805461ff00191661020017905561155b6117e3565b61156a848484620100ff6125b5565b50506000805461ff0019166101001790555050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f9aa028a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160191906144bf565b6001600160a01b0316336001600160a01b0316146109de576040516361081c1560e01b815260040160405180910390fd5b6040517fd5c2f4860000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d5c2f486906024015b602060405180830381865afa1580156116b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db91906144dc565b92915050565b6116ea8161250c565b6001600160a01b0316336001600160a01b031614610ed2576040517f1e83c51100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff16156109de5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611115565b60005460011961010090910460ff16016109de5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611115565b34156109de577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561184457600080fd5b505af1158015611858573d6000803e3d6000fd5b506109de9350506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915033905034612da9565b6040517ff9f0ca660000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063f9f0ca669060240161169a565b6040805160a08101825260608082526000602083018190529282018390528101829052608081019190915260405133906001600160a01b038916907f6637691e02875fb5c598316278034ab86d133a75ab6d76491287290e0397928490600090a361271060208201526000606086845b8181101561230157368a8a8381811061198b5761198b6148f9565b905060200281019061199d919061490f565b9050306119ad60208301836142ca565b6001600160a01b0316036121085760006119ca602083018361492f565b6119d391614976565b90507fd0d35b65000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611a7d57845115611a3f576040517fe61eedf500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611a4e602084018461492f565b611a5c9160049082906149a4565b810190611a6991906149ce565b9050611a758e82612e10565b955050612102565b7f0bd51500000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611b57578451600003611ae9576040517f87a3f92f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611af58d866000612f5f565b611b12576040516307edf61760e01b815260040160405180910390fd5b6040805160008082526020820190925290611b4f565b6040805180820190915260008082526020820152815260200190600190039081611b285790505b509450612102565b7f928a4612000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611bd357611b93896001612fd7565b611b9c86613016565b9550611bcc611bc58e611bb2602086018661492f565b611bc09160049082906149a4565b6130ad565b87168b1790565b9950612102565b7fbc707034000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611c4157611c0f896001612fd7565b611c1886613016565b9550611bcc611bc58e611c2e602086018661492f565b611c3c9160049082906149a4565b613125565b7f8ed3ef53000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611cbd57611c7d896040612fd7565b600080611cad8f611c91602087018761492f565b611c9f9160049082906149a4565b600160c01b8f16151561326b565b199c179b909b169a506121029050565b7fe0ef7760000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611d4957611cf9896020612fd7565b60016060880181905260808801526000611d2d8e611d1a602086018661492f565b611d289160049082906149a4565b613407565b9050611d3887613016565b9650808716198b165b9a5050612102565b7fd48384ef000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611dc057611d85896002612fd7565b600160608801526000611db58e611d9f602086018661492f565b611dad9160049082906149a4565b8e60006135c1565b5090508a8117611d41565b7fd5845e09000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611e3157611dfc896004612fd7565b6000611e258e611e0f602086018661492f565b611e1d9160049082906149a4565b8e60016135c1565b91505080198b16611d41565b7ff8974402000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611f5e57611e6f602083018361492f565b611e7d9160049082906149a4565b810190611e8a9190614a9d565b61ffff16602089018190529088526127101115611ed3576040517f69bb881000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86515160005b81811015611f5757600089600001518281518110611ef957611ef96148f9565b602002602001015190508060001480611f1757506000198101811615155b15611f4e576040517fca2421ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101611ed9565b5050612102565b7f396f6f76000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611fe457611f9a896008612fd7565b6000611fa9602084018461492f565b611fb79160049082906149a4565b810190611fc491906142ca565b9050611fcf87613016565b9650611d41611fdd82611632565b88168c1790565b7fdc1d859c000000000000000000000000000000000000000000000000000000006001600160e01b031982160161206b57612020896010612fd7565b600061202f602084018461492f565b61203d9160049082906149a4565b81019061204a91906142ca565b905061205587613016565b9650611d4161206382611632565b8816198c1690565b7fa9a57df3000000000000000000000000000000000000000000000000000000006001600160e01b03198216016120d0576120a7896080612fd7565b6120cb8d6120b8602085018561492f565b6120c69160049082906149a4565b613767565b612102565b6040517f1e9e7e7a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506122f8565b6121158862010000612fd7565b606060006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663ff68754361215560208601866142ca565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121bd91906144bf565b90506001600160a01b0381166121ff576040517ffc1a554300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160c11b8a1660000361221f57600160c11b8a17995061221f8e613817565b61228061222f602085018561492f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122719250505060208601866142ca565b6001600160a01b0316906138ae565b9150806001600160a01b03168e6001600160a01b03167f1b835de7d84f000a333cdc5822ae62eb63b38d4c622ef96ac50f27db56d7c76860405160405180910390a350600080828060200190518101906122da91906148ae565b915091506122e788613016565b908116199181169b909b1716999550505b50600101611970565b50508051156123335761231689826000612f5f565b612333576040516307edf61760e01b815260040160405180910390fd5b60045486161561234557600160808401525b600160c11b851615612359576123596138f2565b6040808401879052517f9fe19f2060e67aed557c7d1bc297d4bd2d8a8b952e3545c658ec4bc00be7d6c490600090a150509695505050505050565b6040517f845104de0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063845104de90602401602060405180830381865afa158015612418573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db9190614b40565b612445336138fc565b6109de576040517f16e29ab700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6124836139a5565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6124d5612b17565b156109de576040517ffd956fa500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc53afb1e0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063c53afb1e906024015b602060405180830381865afa158015612591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db91906144bf565b60045460006125c386611894565b905060006125d687838516612b71612bda565b905060006125e487876126a2565b9050600061260c8989898787516000036125fe578a612606565b600160c01b8b175b87611900565b905061261b89858386896128e9565b505050505050505050565b61262f336139f7565b6109de576040517fd794b1e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61266d611734565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124b03390565b60008082815b818110156128e057368686838181106126c3576126c36148f9565b90506020028101906126d5919061490f565b9050306126e560208301836142ca565b6001600160a01b031614801561273957507f6c68e10900000000000000000000000000000000000000000000000000000000612724602083018361492f565b61272d91614976565b6001600160e01b031916145b156128cc576000808061274f602085018561492f565b61275d9160049082906149a4565b81019061276a9190614b5d565b92509250925061277987613a63565b6040517fff2998450000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152841515602483015291985060009189169063ff29984590604401602060405180830381865afa1580156127e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280a91906144bf565b90506001600160a01b03811661284c576040517f68d8c6d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f8736ec470000000000000000000000000000000000000000000000000000000081526001600160a01b03821690638736ec4790612891908590600401614c67565b600060405180830381600087803b1580156128ab57600080fd5b505af11580156128bf573d6000803e3d6000fd5b50505050505050506128d7565b5092506116db915050565b506001016126a8565b50949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633d7e5dc48786604001518760000151886020015189608001516040518663ffffffff1660e01b815260040161294f959493929190614c7a565b6020604051808303816000875af115801561296e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299291906144dc565b90508181168015612a46578460600151156129c0576040516310bc1b9560e21b815260040160405180910390fd5b85831680198216156129fe576040517f325b1ffe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a0d8984886001612cf7565b90508061261b576040517ff3d712f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b612a5833613ad8565b6109de576040516361081c1560e01b815260040160405180910390fd5b6040517fc544cf7d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015261ffff8416602483015282151560448301527f0000000000000000000000000000000000000000000000000000000000000000169063c544cf7d90606401600060405180830381600087803b158015612b0357600080fd5b505af1158015612a46573d6000803e3d6000fd5b60007f0000000000000000000000000000000000000000000000000000000000000000612b445750600090565b600054600160b01b900464ffffffffff168015801590612b6b57508064ffffffffff164210155b91505090565b6040517f4fc0e3a8000000000000000000000000000000000000000000000000000000008152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690634fc0e3a890602401612574565b60608215612cf057612beb83613b44565b67ffffffffffffffff811115612c0357612c03614522565b604051908082528060200260200182016040528015612c6157816020015b612c4e604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200190600190039081612c215790505b50905060005b8315612cee57600084810385169485189490612c868263ffffffff8716565b90506040518060600160405280826001600160a01b03168152602001838152602001612cc489846001600160a01b0316613b6390919063ffffffff16565b815250848481518110612cd957612cd96148f9565b60209081029190910101525050600101612c67565b505b9392505050565b600083600003612d0957506001612da1565b825160005b81811015612d9a57848181518110612d2857612d286148f9565b6020026020010151602001518616600014612d9257612d8387868381518110612d5357612d536148f9565b602002602001015160000151878481518110612d7157612d716148f9565b60200260200101516040015187613b9c565b612d9257600092505050612da1565b600101612d0e565b5050600190505b949350505050565b612dd5837fa9059cbb000000000000000000000000000000000000000000000000000000008484613c06565b612e0b576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b80516060908067ffffffffffffffff811115612e2e57612e2e614522565b604051908082528060200260200182016040528015612e7357816020015b6040805180820190915260008082526020820152815260200190600190039081612e4c5790505b50915060005b81811015612f57576000612ec4612ebf87878581518110612e9c57612e9c6148f9565b6020026020010151600001516001600160a01b0316613b6390919063ffffffff16565b613c55565b90506040518060400160405280868481518110612ee357612ee36148f9565b6020026020010151600001516001600160a01b03168152602001612f2e878581518110612f1257612f126148f9565b60200260200101516020015184612f299190614ceb565b613cf1565b815250848381518110612f4357612f436148f9565b602090810291909101015250600101612e79565b505092915050565b8151600090815b81811015612fcb57612fb486868381518110612f8457612f846148f9565b602002602001015160000151878481518110612fa257612fa26148f9565b60200260200101516020015187613b9c565b612fc357600092505050612cf0565b600101612f66565b50600195945050505050565b8082166000036106c5576040517f6b895d0400000000000000000000000000000000000000000000000000000000815260048101829052602401611115565b6000811561302457816116db565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e0f838246040518163ffffffff1660e01b8152600401602060405180830381865afa158015613082573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a691906144dc565b1992915050565b600080806130bd84860186614d0b565b915091506130cd33878484613d43565b9250816001600160a01b0316866001600160a01b03167fa32435755c235de2976ed44a75a2f85cb01faf0c894f639fe0c32bb9455fea8f8360405161311491815260200190565b60405180910390a350509392505050565b6000808080808080613139888a018a614d37565b6040517fd505accf0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018790526064820186905260ff8516608483015260a4820184905260c48201839052969c50949a50929850909650945092509087169063d505accf9060e401600060405180830381600087803b1580156131f157600080fd5b505af1925050508015613202575060015b5061320f338b8888613d43565b9650856001600160a01b03168a6001600160a01b03167fa32435755c235de2976ed44a75a2f85cb01faf0c894f639fe0c32bb9455fea8f8760405161325691815260200190565b60405180910390a35050505050509392505050565b60008080808061327d87890189614d91565b9250925092508580156132935750600082600b0b135b156132c3576004546132a484611632565b16156132c3576040516310bc1b9560e21b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663604ca15f8a856b800000000000000000000000600b87900b016133115785613328565b61271061331e8188614de9565b6133289190614e3a565b600354869061335f906bffffffffffffffffffffffff9061335a90600160801b90046001600160801b03166002614445565b613e0d565b6040516001600160e01b031960e088901b1681526001600160a01b039586166004820152949093166024850152600b9190910b60448401526bffffffffffffffffffffffff908116606484015216608482015260a40160408051808303816000875af11580156133d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f791906148ae565b909a909950975050505050505050565b600080808061341885870187614e5a565b92509250925060001982036134af576040516370a0823160e01b81526001600160a01b0388811660048301528416906370a0823190602401602060405180830381865afa15801561346d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349191906144dc565b9150600182116134a75760009350505050612cf0565b600019909101905b6040517f5a6f45de0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015284811660248301526044820184905282811660648301527f00000000000000000000000000000000000000000000000000000000000000001690635a6f45de906084016020604051808303816000875af1158015613547573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356b91906144dc565b604080518481526001600160a01b038481166020830152929650828616928a16917fe7655dfddd0226889710c711da4e725dd44525fb5717b2321017a97d32793ab8910160405180910390a35050509392505050565b600080806135d186880188614e91565b905060008460018111156135e7576135e761445c565b036135f5576135f581613e23565b6040517f432017e80000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063432017e890613663908c9086908b908b90600401614eaa565b6060604051808303816000875af1158015613682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a69190614ee7565b909550935090506136b681613f3f565b60008560018111156136ca576136ca61445c565b0361371757886001600160a01b03167fcb6767c6e25552f1ab37156882f03b9ba603ebf3814463bf5eb9b0d2bd8a19b58360405161370a91815260200190565b60405180910390a261375b565b886001600160a01b03167f9ddbe9792bb03a06eab016daae23f04ec25454c24b836da2361fc703037f77628360405161375291815260200190565b60405180910390a25b50509550959350505050565b600061377582840184614f15565b6040517f3031b01a0000000000000000000000000000000000000000000000000000000081529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633031b01a906137df9087908590600401614fd3565b600060405180830381600087803b1580156137f957600080fd5b505af115801561380d573d6000803e3d6000fd5b5050505050505050565b6040517fe09357a40000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e09357a490602401600060405180830381600087803b15801561389357600080fd5b505af11580156138a7573d6000803e3d6000fd5b5050505050565b6060612cf0838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250613f9e565b6109de6001613817565b6040517fd4eb5db00000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d4eb5db0906024015b602060405180830381865afa158015613981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db919061503a565b60005460ff166109de5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611115565b6040517f3a41ec640000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690633a41ec6490602401613964565b60006001600160a01b03821615613a7a57816116db565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612591573d6000803e3d6000fd5b6040517f5f259aba0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635f259aba90602401613964565b60005b8115613b5e57600019820190911690600101613b47565b919050565b6370a0823160e01b6000818152600483905290602082602481875afa600051925060203d1081151715612f57576040513d6000823e3d81fd5b600080613bb26001600160a01b03861687613b63565b90506000836001811115613bc857613bc861445c565b148015613bd55750838110155b80613bfc57506001836001811115613bef57613bef61445c565b148015613bfc5750838111155b9695505050505050565b60006040518481528360048201528260248201526020600060448360008a5af19150508015612da1573d8015613c4857600160005114601f3d111691506128e0565b50505050903b1515919050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115613ced5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401611115565b5090565b600080821215613ced5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401611115565b6040517f830aa7450000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015284811660248301528381166044830152606482018390526000917f00000000000000000000000000000000000000000000000000000000000000009091169063830aa745906084016020604051808303816000875af1158015613de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0491906144dc565b95945050505050565b6000818310613e1c5781612cf0565b5090919050565b600054600160d81b900460ff1660fe198101613e3d575050565b6001546000904367ffffffffffffffff90911603613e7e57600154613e77906801000000000000000090046001600160801b031684615057565b9050613e9e565b506001805467ffffffffffffffff19164367ffffffffffffffff16179055815b600354613ebe90600160801b90046001600160801b031660ff8416614445565b811115613ef7576040517f675f1a5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160801b0390921668010000000000000000027fffffffffffffffff00000000000000000000000000000000ffffffffffffffff9092169190911790555050565b6003546001600160801b0381169060801c8215801590613f67575081831080613f6757508083115b15612e0b576040517fce16799400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060824710156140165760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611115565b600080866001600160a01b03168587604051614032919061506a565b60006040518083038185875af1925050503d806000811461406f576040519150601f19603f3d011682016040523d82523d6000602084013e614074565b606091505b509150915061408587838387614090565b979650505050505050565b606083156140ff5782516000036140f8576001600160a01b0385163b6140f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611115565b5081612da1565b612da183838151156141145781518083602001fd5b8060405162461bcd60e51b81526004016111159190614c67565b6001600160801b0381168114610ed257600080fd5b8015158114610ed257600080fd5b6000806040838503121561416457600080fd5b823561416f8161412e565b9150602083013561417f81614143565b809150509250929050565b803560ff81168114613b5e57600080fd5b6000806000606084860312156141b057600080fd5b83356141bb8161412e565b925060208401356141cb8161412e565b91506141d96040850161418a565b90509250925092565b6001600160a01b0381168114610ed257600080fd5b6000806040838503121561420a57600080fd5b8235614215816141e2565b915060208301356002811061417f57600080fd5b60008083601f84011261423b57600080fd5b50813567ffffffffffffffff81111561425357600080fd5b6020830191508360208260051b850101111561426e57600080fd5b9250929050565b60008060006040848603121561428a57600080fd5b8335614295816141e2565b9250602084013567ffffffffffffffff8111156142b157600080fd5b6142bd86828701614229565b9497909650939450505050565b6000602082840312156142dc57600080fd5b8135612cf0816141e2565b600080600080606085870312156142fd57600080fd5b8435614308816141e2565b9350602085013567ffffffffffffffff81111561432457600080fd5b61433087828801614229565b9598909750949560400135949350505050565b6001600160c01b0381168114610ed257600080fd5b60008060006060848603121561436d57600080fd5b8335614378816141e2565b92506020840135614388816141e2565b9150604084013561439881614343565b809150509250925092565b600080600080606085870312156143b957600080fd5b84356143c4816141e2565b935060208501356143d4816141e2565b9250604085013567ffffffffffffffff8111156143f057600080fd5b6143fc87828801614229565b95989497509550505050565b60006020828403121561441a57600080fd5b813564ffffffffff81168114612cf057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176116db576116db61442f565b634e487b7160e01b600052602160045260246000fd5b60008060006060848603121561448757600080fd5b835161449281614343565b60208501519093506144a381614143565b604085015190925061439881614143565b8051613b5e816141e2565b6000602082840312156144d157600080fd5b8151612cf0816141e2565b6000602082840312156144ee57600080fd5b5051919050565b6001600160a01b038316815260408101600583106145155761451561445c565b8260208301529392505050565b634e487b7160e01b600052604160045260246000fd5b6040516101c0810167ffffffffffffffff8111828210171561455c5761455c614522565b60405290565b6040805190810167ffffffffffffffff8111828210171561455c5761455c614522565b604051601f8201601f1916810167ffffffffffffffff811182821017156145ae576145ae614522565b604052919050565b8051613b5e8161412e565b600067ffffffffffffffff8211156145db576145db614522565b5060051b60200190565b600082601f8301126145f657600080fd5b8151602061460b614606836145c1565b614585565b82815260059290921b8401810191818101908684111561462a57600080fd5b8286015b8481101561464e578051614641816141e2565b835291830191830161462e565b509695505050505050565b60006020828403121561466b57600080fd5b815167ffffffffffffffff8082111561468357600080fd5b908301906101c0828603121561469857600080fd5b6146a0614538565b8251815260208301516020820152604083015160408201526146c4606084016145b6565b60608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250610140808401518183015250610160808401518183015250610180808401518381111561473557600080fd5b614741888287016145e5565b8284015250506101a091506147578284016144b4565b91810191909152949350505050565b600081518084526020808501945080840160005b8381101561479f5781516001600160a01b03168752958201959082019060010161477a565b509495945050505050565b6001600160a01b03851681526080602082015283516080820152602084015160a0820152604084015160c0820152600060608501516147f460e08401826001600160801b03169052565b5060808501516101008381019190915260a08601516101208085019190915260c08701516101408086019190915260e0880151610160808701919091529288015161018080870191909152918801516101a080870191909152908801516101c080870191909152928801516101e086015281880151610200860193909352614880610240860184614766565b908801516001600160a01b039081166102208701528716604086015285151560608601529250613e04915050565b600080604083850312156148c157600080fd5b505080516020909101519092909150565b6001600160801b038181168382160190808211156148f2576148f261442f565b5092915050565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261492557600080fd5b9190910192915050565b6000808335601e1984360301811261494657600080fd5b83018035915067ffffffffffffffff82111561496157600080fd5b60200191503681900382131561426e57600080fd5b6001600160e01b03198135818116916004851015612f575760049490940360031b84901b1690921692915050565b600080858511156149b457600080fd5b838611156149c157600080fd5b5050820193919092039150565b600060208083850312156149e157600080fd5b823567ffffffffffffffff8111156149f857600080fd5b8301601f81018513614a0957600080fd5b8035614a17614606826145c1565b81815260069190911b82018301908381019087831115614a3657600080fd5b928401925b828410156140855760408489031215614a545760008081fd5b614a5c614562565b8435614a67816141e2565b81528486013586820152825260409093019290840190614a3b565b61ffff81168114610ed257600080fd5b8035613b5e81614a82565b60008060408385031215614ab057600080fd5b823567ffffffffffffffff811115614ac757600080fd5b8301601f81018513614ad857600080fd5b80356020614ae8614606836145c1565b82815260059290921b83018101918181019088841115614b0757600080fd5b938201935b83851015614b2557843582529382019390820190614b0c565b9550614b349050868201614a92565b93505050509250929050565b600060208284031215614b5257600080fd5b8151612cf081614a82565b600080600060608486031215614b7257600080fd5b8335614b7d816141e2565b9250602084810135614b8e81614143565b9250604085013567ffffffffffffffff80821115614bab57600080fd5b818701915087601f830112614bbf57600080fd5b813581811115614bd157614bd1614522565b614be3601f8201601f19168501614585565b91508082528884828501011115614bf957600080fd5b80848401858401376000848284010152508093505050509250925092565b60005b83811015614c32578181015183820152602001614c1a565b50506000910152565b60008151808452614c53816020860160208601614c17565b601f01601f19169290920160200192915050565b602081526000612cf06020830184614c3b565b600060a082016001600160a01b03881683526020878185015260a0604085015281875180845260c086019150828901935060005b81811015614cca57845183529383019391830191600101614cae565b505061ffff9690961660608501525050509015156080909101529392505050565b8082018281126000831280158216821582161715612f5757612f5761442f565b60008060408385031215614d1e57600080fd5b8235614d29816141e2565b946020939093013593505050565b60008060008060008060c08789031215614d5057600080fd5b8635614d5b816141e2565b95506020870135945060408701359350614d776060880161418a565b92506080870135915060a087013590509295509295509295565b600080600060608486031215614da657600080fd5b8335614db1816141e2565b92506020840135600b81900b8114614dc857600080fd5b915060408401356bffffffffffffffffffffffff8116811461439857600080fd5b600081600b0b83600b0b80614e0e57634e487b7160e01b600052601260045260246000fd5b6b7fffffffffffffffffffffff19821460001982141615614e3157614e3161442f565b90059392505050565b600082600b0b82600b0b0280600b0b91508082146148f2576148f261442f565b600080600060608486031215614e6f57600080fd5b8335614e7a816141e2565b9250602084013591506040840135614398816141e2565b600060208284031215614ea357600080fd5b5035919050565b6001600160a01b038516815260208101849052604081018390526080810160028310614ed857614ed861445c565b82606083015295945050505050565b600080600060608486031215614efc57600080fd5b8351925060208401519150604084015190509250925092565b60006020808385031215614f2857600080fd5b823567ffffffffffffffff811115614f3f57600080fd5b8301601f81018513614f5057600080fd5b8035614f5e614606826145c1565b81815260069190911b82018301908381019087831115614f7d57600080fd5b928401925b828410156140855760408489031215614f9b5760008081fd5b614fa3614562565b8435614fae816141e2565b815284860135614fbd816141e2565b8187015282526040939093019290840190614f82565b600060408083016001600160a01b03808716855260208381870152828751808552606088019150828901945060005b8181101561502b5785518051861684528401518516848401529483019491860191600101615002565b50909998505050505050505050565b60006020828403121561504c57600080fd5b8151612cf081614143565b808201808211156116db576116db61442f565b60008251614925818460208701614c1756fea264697066735822122036f7b207925b1e86f09f35200705d9729576765715a7e0fa64573f5a3ba7f4cd64736f6c63430008110033000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101d85760003560e01c80638ad1386e11610102578063c5b73ed011610095578063eb9606df11610064578063eb9606df146105fb578063ebe4107c1461061b578063f6722f621461062e578063f77c47911461064e57600080fd5b8063c5b73ed014610567578063c5d7ca3914610587578063de287359146105a7578063e3f46b26146105db57600080fd5b80639408b63f116100d15780639408b63f146104b55780639fd12b77146104e9578063b1836d32146104ff578063c12c21c01461053357600080fd5b80638ad1386e146104275780638f6204871461044757806392beab1d1461048257806392eefe9b1461049557600080fd5b80633fc8cef31161017a5780635c975abb116101495780635c975abb146103c55780637e2ca9db146103dd5780638456cb59146103fd578063874b2e021461041257600080fd5b80633fc8cef3146102f7578063478ade3614610343578063503931091461037657806354fd4d50146103a157600080fd5b806326f30692116101b657806326f306921461026f57806336b2ced31461028f57806338975bc4146102a25780633f4ba83a146102e257600080fd5b80630103dc6b146101dd5780631656af9d146101ff578063166bf9d91461021f575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004614151565b610674565b005b34801561020b57600080fd5b506101fd61021a36600461419b565b6106c9565b34801561022b57600080fd5b5060035461024a906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152015b60405180910390f35b34801561027b57600080fd5b506101fd61028a3660046141f7565b610758565b6101fd61029d366004614275565b61079f565b3480156102ae57600080fd5b506102d26102bd3660046142ca565b60066020526000908152604090205460ff1681565b6040519015158152602001610266565b3480156102ee57600080fd5b506101fd6109ce565b34801561030357600080fd5b5061032b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3881565b6040516001600160a01b039091168152602001610266565b34801561034f57600080fd5b5060005461036490600160d81b900460ff1681565b60405160ff9091168152602001610266565b34801561038257600080fd5b5060055461024a906001600160801b0380821691600160801b90041682565b3480156103ad57600080fd5b506103b761012d81565b604051908152602001610266565b3480156103d157600080fd5b5060005460ff166102d2565b3480156103e957600080fd5b506101fd6103f8366004614275565b6109e0565b34801561040957600080fd5b506101fd610b65565b34801561041e57600080fd5b506103b7600281565b34801561043357600080fd5b506101fd6104423660046142ca565b610b75565b34801561045357600080fd5b5060005461046c90600160b01b900464ffffffffff1681565b60405164ffffffffff9091168152602001610266565b61032b6104903660046142e7565b610bb7565b3480156104a157600080fd5b506101fd6104b03660046142ca565b610e49565b3480156104c157600080fd5b5061032b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104f557600080fd5b506103b760045481565b34801561050b57600080fd5b506102d27f000000000000000000000000000000000000000000000000000000000000000081565b34801561053f57600080fd5b5061032b7f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b281565b34801561057357600080fd5b506101fd610582366004614358565b610ed5565b34801561059357600080fd5b506101fd6105a23660046141f7565b611066565b3480156105b357600080fd5b5061032b7f000000000000000000000000ad131da4bddb40ebb5ceeaea87067553d431389581565b3480156105e757600080fd5b506101fd6105f63660046143a3565b6110ac565b34801561060757600080fd5b506101fd610616366004614408565b611484565b6101fd610629366004614275565b611522565b34801561063a57600080fd5b5060025461032b906001600160a01b031681565b34801561065a57600080fd5b5060005461032b906201000090046001600160a01b031681565b61067c61157f565b600580546001600160801b03808516600160801b02911617905580156106c557600580547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b5050565b6106d161157f565b6001600160801b036106e883821660ff8416614445565b1061071f576040517f47fbaa9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160801b03918216600160801b0291909216176003556000805460ff909216600160d81b0260ff60d81b19909216919091179055565b61076061157f565b600061076b83611632565b905060018260018111156107815761078161445c565b14610790576004548117610797565b6004548119165b600455505050565b826107a9816116e1565b6107b1611734565b6107b9611787565b6000805461ff0019166102001790556107d06117e3565b60006107db85611894565b905082156107fe5760006107f686868685620100fd86611900565b604001519150505b8015610836576040517f77349a6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600161084186612394565b1661ffff166000146108ee576002546040517f7bdfc8740000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b281166004830152878116602483015290911690637bdfc87490604401600060405180830381600087803b1580156108d557600080fd5b505af11580156108e9573d6000803e3d6000fd5b505050505b6040517f7687f6700000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b21690637687f67090602401600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040513392506001600160a01b03881691507f460ad03b1cf79b1d64d3aefa28475f110ab66e84649c52bb41ed796b9b39198190600090a350506000805461ff001916610100179055505050565b6109d661243c565b6109de61247b565b565b6109e8611734565b6109f06124cd565b6109f8611787565b6000805461ff001916610200179055610a108361250c565b506002546040517f68f8085c0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b281166024830152858116604483015260009283928392909116906368f8085c90606401606060405180830381865afa158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd9190614472565b925092506001600160c01b031692508260001480610ae85750815b80610b0b575080158015610b0b57506001610b0287612394565b1661ffff166000145b15610b42576040517f8fd689c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b4e868686866125b5565b50506000805461ff00191661010017905550505050565b610b6d612626565b6109de612665565b610b7d61157f565b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000610bc1611734565b610bc96124cd565b610bd1611787565b6000805461ff001916610200179055610be86117e3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610cf557336001600160a01b03861614610c59576040517fd380b4d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152600160248301527f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac90604401600060405180830381600087803b158015610cdc57600080fd5b505af1158015610cf0573d6000803e3d6000fd5b505050505b6040517f43fe7bbe0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b216906343fe7bbe906024016020604051808303816000875af1158015610d76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9a91906144bf565b9050336001600160a01b0316856001600160a01b0316826001600160a01b03167f6e4927aac3383b13ffc5b6f44447693caf351f2f7ca800c9b4463b76997911b085604051610deb91815260200190565b60405180910390a48215610e325760606000610e0786866126a2565b90506000610e1c84888884620100fb87611900565b9050610e2e84600083866004546128e9565b5050505b6000805461ff001916610100179055949350505050565b610e51612a4f565b6000546001600160a01b03828116620100009092041614610ed257600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b03841690810291909117825560405190917fe253457d9ad994ca9682fc3bbc38c890dca73a2d5ecee3809e548bac8b00d7c691a25b50565b82610edf816116e1565b610ee7611787565b6000805461ff00191661020017905577fffffffffffffffffffffffffffffffffffffffffffeff00821615610f48576040517f4b6a275600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517fc9c45fa00000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b28116602483015286811660448301526001600160c01b0385166064830152600092169063c9c45fa0906084016020604051808303816000875af1158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101191906144dc565b90508060000361102d576110288560016000612a75565b611050565b600161103886612394565b1661ffff166000036110505761105085600180612a75565b50506000805461ff001916610100179055505050565b61106e61157f565b60018160018111156110825761108261445c565b6001600160a01b039093166000908152600660205260409020805460ff1916919093141790915550565b60005460ff1615806110cd57503360009081526006602052604090205460ff165b61111e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064015b60405180910390fd5b611126611787565b6000805461ff00191661020017815561113f83836126a2565b905060007f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b0316630d334ca68760036040518363ffffffff1660e01b81526004016111929291906144f5565b600060405180830381865afa1580156111af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111d79190810190614659565b60c08101516101208201518251929350109015806112035750801580156112035750611201612b17565b155b1561123a576040517f234b893b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014082018051600119169081905260009061125a908990612b71612bda565b90506000611283898888876101400151602060016201000017176001600160c01b03168a611900565b604081015161014086018051909116908190529091506000906112aa908b90856001612cf7565b9050806112e3576040517f393964ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610140850151600117856101400181815250506000807f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b031663e2f1490f8d898e8a156040518563ffffffff1660e01b815260040161134c94939291906147aa565b60408051808303816000875af115801561136a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138e91906148ae565b604080516001600160a01b038f811682526020820185905293955091935033928f16917f7dfecd8419723a9d3954585a30c2a270165d70aafa146c11c1e1b88ae1439064910160405180910390a38015611467576000805460ff60d81b191681556005805483929061140a9084906001600160801b03166148d2565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555061143a60005460ff1690565b15801561145a57506005546001600160801b03600160801b820481169116115b1561146757611467612665565b50506000805461ff00191661010017905550505050505050505050565b61148c61157f565b7f00000000000000000000000000000000000000000000000000000000000000006114e3576040517f50dd11fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805464ffffffffff909216600160b01b027fffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b8261152c816116e1565b611534611734565b61153c6124cd565b611544611787565b6000805461ff00191661020017905561155b6117e3565b61156a848484620100ff6125b5565b50506000805461ff0019166101001790555050565b7f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b031663f9aa028a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160191906144bf565b6001600160a01b0316336001600160a01b0316146109de576040516361081c1560e01b815260040160405180910390fd5b6040517fd5c2f4860000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b29091169063d5c2f486906024015b602060405180830381865afa1580156116b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db91906144dc565b92915050565b6116ea8161250c565b6001600160a01b0316336001600160a01b031614610ed2576040517f1e83c51100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005460ff16156109de5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611115565b60005460011961010090910460ff16016109de5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611115565b34156109de577f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561184457600080fd5b505af1158015611858573d6000803e3d6000fd5b506109de9350506001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816915033905034612da9565b6040517ff9f0ca660000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b29091169063f9f0ca669060240161169a565b6040805160a08101825260608082526000602083018190529282018390528101829052608081019190915260405133906001600160a01b038916907f6637691e02875fb5c598316278034ab86d133a75ab6d76491287290e0397928490600090a361271060208201526000606086845b8181101561230157368a8a8381811061198b5761198b6148f9565b905060200281019061199d919061490f565b9050306119ad60208301836142ca565b6001600160a01b0316036121085760006119ca602083018361492f565b6119d391614976565b90507fd0d35b65000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611a7d57845115611a3f576040517fe61eedf500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611a4e602084018461492f565b611a5c9160049082906149a4565b810190611a6991906149ce565b9050611a758e82612e10565b955050612102565b7f0bd51500000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611b57578451600003611ae9576040517f87a3f92f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611af58d866000612f5f565b611b12576040516307edf61760e01b815260040160405180910390fd5b6040805160008082526020820190925290611b4f565b6040805180820190915260008082526020820152815260200190600190039081611b285790505b509450612102565b7f928a4612000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611bd357611b93896001612fd7565b611b9c86613016565b9550611bcc611bc58e611bb2602086018661492f565b611bc09160049082906149a4565b6130ad565b87168b1790565b9950612102565b7fbc707034000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611c4157611c0f896001612fd7565b611c1886613016565b9550611bcc611bc58e611c2e602086018661492f565b611c3c9160049082906149a4565b613125565b7f8ed3ef53000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611cbd57611c7d896040612fd7565b600080611cad8f611c91602087018761492f565b611c9f9160049082906149a4565b600160c01b8f16151561326b565b199c179b909b169a506121029050565b7fe0ef7760000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611d4957611cf9896020612fd7565b60016060880181905260808801526000611d2d8e611d1a602086018661492f565b611d289160049082906149a4565b613407565b9050611d3887613016565b9650808716198b165b9a5050612102565b7fd48384ef000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611dc057611d85896002612fd7565b600160608801526000611db58e611d9f602086018661492f565b611dad9160049082906149a4565b8e60006135c1565b5090508a8117611d41565b7fd5845e09000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611e3157611dfc896004612fd7565b6000611e258e611e0f602086018661492f565b611e1d9160049082906149a4565b8e60016135c1565b91505080198b16611d41565b7ff8974402000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611f5e57611e6f602083018361492f565b611e7d9160049082906149a4565b810190611e8a9190614a9d565b61ffff16602089018190529088526127101115611ed3576040517f69bb881000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86515160005b81811015611f5757600089600001518281518110611ef957611ef96148f9565b602002602001015190508060001480611f1757506000198101811615155b15611f4e576040517fca2421ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101611ed9565b5050612102565b7f396f6f76000000000000000000000000000000000000000000000000000000006001600160e01b0319821601611fe457611f9a896008612fd7565b6000611fa9602084018461492f565b611fb79160049082906149a4565b810190611fc491906142ca565b9050611fcf87613016565b9650611d41611fdd82611632565b88168c1790565b7fdc1d859c000000000000000000000000000000000000000000000000000000006001600160e01b031982160161206b57612020896010612fd7565b600061202f602084018461492f565b61203d9160049082906149a4565b81019061204a91906142ca565b905061205587613016565b9650611d4161206382611632565b8816198c1690565b7fa9a57df3000000000000000000000000000000000000000000000000000000006001600160e01b03198216016120d0576120a7896080612fd7565b6120cb8d6120b8602085018561492f565b6120c69160049082906149a4565b613767565b612102565b6040517f1e9e7e7a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506122f8565b6121158862010000612fd7565b606060006001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b21663ff68754361215560208601866142ca565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121bd91906144bf565b90506001600160a01b0381166121ff576040517ffc1a554300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160c11b8a1660000361221f57600160c11b8a17995061221f8e613817565b61228061222f602085018561492f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122719250505060208601866142ca565b6001600160a01b0316906138ae565b9150806001600160a01b03168e6001600160a01b03167f1b835de7d84f000a333cdc5822ae62eb63b38d4c622ef96ac50f27db56d7c76860405160405180910390a350600080828060200190518101906122da91906148ae565b915091506122e788613016565b908116199181169b909b1716999550505b50600101611970565b50508051156123335761231689826000612f5f565b612333576040516307edf61760e01b815260040160405180910390fd5b60045486161561234557600160808401525b600160c11b851615612359576123596138f2565b6040808401879052517f9fe19f2060e67aed557c7d1bc297d4bd2d8a8b952e3545c658ec4bc00be7d6c490600090a150509695505050505050565b6040517f845104de0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b29091169063845104de90602401602060405180830381865afa158015612418573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db9190614b40565b612445336138fc565b6109de576040517f16e29ab700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6124836139a5565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6124d5612b17565b156109de576040517ffd956fa500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc53afb1e0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b29091169063c53afb1e906024015b602060405180830381865afa158015612591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db91906144bf565b60045460006125c386611894565b905060006125d687838516612b71612bda565b905060006125e487876126a2565b9050600061260c8989898787516000036125fe578a612606565b600160c01b8b175b87611900565b905061261b89858386896128e9565b505050505050505050565b61262f336139f7565b6109de576040517fd794b1e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61266d611734565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124b03390565b60008082815b818110156128e057368686838181106126c3576126c36148f9565b90506020028101906126d5919061490f565b9050306126e560208301836142ca565b6001600160a01b031614801561273957507f6c68e10900000000000000000000000000000000000000000000000000000000612724602083018361492f565b61272d91614976565b6001600160e01b031916145b156128cc576000808061274f602085018561492f565b61275d9160049082906149a4565b81019061276a9190614b5d565b92509250925061277987613a63565b6040517fff2998450000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152841515602483015291985060009189169063ff29984590604401602060405180830381865afa1580156127e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280a91906144bf565b90506001600160a01b03811661284c576040517f68d8c6d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f8736ec470000000000000000000000000000000000000000000000000000000081526001600160a01b03821690638736ec4790612891908590600401614c67565b600060405180830381600087803b1580156128ab57600080fd5b505af11580156128bf573d6000803e3d6000fd5b50505050505050506128d7565b5092506116db915050565b506001016126a8565b50949350505050565b60007f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b0316633d7e5dc48786604001518760000151886020015189608001516040518663ffffffff1660e01b815260040161294f959493929190614c7a565b6020604051808303816000875af115801561296e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299291906144dc565b90508181168015612a46578460600151156129c0576040516310bc1b9560e21b815260040160405180910390fd5b85831680198216156129fe576040517f325b1ffe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a0d8984886001612cf7565b90508061261b576040517ff3d712f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b612a5833613ad8565b6109de576040516361081c1560e01b815260040160405180910390fd5b6040517fc544cf7d0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015261ffff8416602483015282151560448301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b2169063c544cf7d90606401600060405180830381600087803b158015612b0357600080fd5b505af1158015612a46573d6000803e3d6000fd5b60007f0000000000000000000000000000000000000000000000000000000000000000612b445750600090565b600054600160b01b900464ffffffffff168015801590612b6b57508064ffffffffff164210155b91505090565b6040517f4fc0e3a8000000000000000000000000000000000000000000000000000000008152600481018290526000907f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b031690634fc0e3a890602401612574565b60608215612cf057612beb83613b44565b67ffffffffffffffff811115612c0357612c03614522565b604051908082528060200260200182016040528015612c6157816020015b612c4e604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200190600190039081612c215790505b50905060005b8315612cee57600084810385169485189490612c868263ffffffff8716565b90506040518060600160405280826001600160a01b03168152602001838152602001612cc489846001600160a01b0316613b6390919063ffffffff16565b815250848481518110612cd957612cd96148f9565b60209081029190910101525050600101612c67565b505b9392505050565b600083600003612d0957506001612da1565b825160005b81811015612d9a57848181518110612d2857612d286148f9565b6020026020010151602001518616600014612d9257612d8387868381518110612d5357612d536148f9565b602002602001015160000151878481518110612d7157612d716148f9565b60200260200101516040015187613b9c565b612d9257600092505050612da1565b600101612d0e565b5050600190505b949350505050565b612dd5837fa9059cbb000000000000000000000000000000000000000000000000000000008484613c06565b612e0b576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b80516060908067ffffffffffffffff811115612e2e57612e2e614522565b604051908082528060200260200182016040528015612e7357816020015b6040805180820190915260008082526020820152815260200190600190039081612e4c5790505b50915060005b81811015612f57576000612ec4612ebf87878581518110612e9c57612e9c6148f9565b6020026020010151600001516001600160a01b0316613b6390919063ffffffff16565b613c55565b90506040518060400160405280868481518110612ee357612ee36148f9565b6020026020010151600001516001600160a01b03168152602001612f2e878581518110612f1257612f126148f9565b60200260200101516020015184612f299190614ceb565b613cf1565b815250848381518110612f4357612f436148f9565b602090810291909101015250600101612e79565b505092915050565b8151600090815b81811015612fcb57612fb486868381518110612f8457612f846148f9565b602002602001015160000151878481518110612fa257612fa26148f9565b60200260200101516020015187613b9c565b612fc357600092505050612cf0565b600101612f66565b50600195945050505050565b8082166000036106c5576040517f6b895d0400000000000000000000000000000000000000000000000000000000815260048101829052602401611115565b6000811561302457816116db565b7f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b031663e0f838246040518163ffffffff1660e01b8152600401602060405180830381865afa158015613082573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a691906144dc565b1992915050565b600080806130bd84860186614d0b565b915091506130cd33878484613d43565b9250816001600160a01b0316866001600160a01b03167fa32435755c235de2976ed44a75a2f85cb01faf0c894f639fe0c32bb9455fea8f8360405161311491815260200190565b60405180910390a350509392505050565b6000808080808080613139888a018a614d37565b6040517fd505accf0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b281166024830152604482018790526064820186905260ff8516608483015260a4820184905260c48201839052969c50949a50929850909650945092509087169063d505accf9060e401600060405180830381600087803b1580156131f157600080fd5b505af1925050508015613202575060015b5061320f338b8888613d43565b9650856001600160a01b03168a6001600160a01b03167fa32435755c235de2976ed44a75a2f85cb01faf0c894f639fe0c32bb9455fea8f8760405161325691815260200190565b60405180910390a35050505050509392505050565b60008080808061327d87890189614d91565b9250925092508580156132935750600082600b0b135b156132c3576004546132a484611632565b16156132c3576040516310bc1b9560e21b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b21663604ca15f8a856b800000000000000000000000600b87900b016133115785613328565b61271061331e8188614de9565b6133289190614e3a565b600354869061335f906bffffffffffffffffffffffff9061335a90600160801b90046001600160801b03166002614445565b613e0d565b6040516001600160e01b031960e088901b1681526001600160a01b039586166004820152949093166024850152600b9190910b60448401526bffffffffffffffffffffffff908116606484015216608482015260a40160408051808303816000875af11580156133d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f791906148ae565b909a909950975050505050505050565b600080808061341885870187614e5a565b92509250925060001982036134af576040516370a0823160e01b81526001600160a01b0388811660048301528416906370a0823190602401602060405180830381865afa15801561346d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349191906144dc565b9150600182116134a75760009350505050612cf0565b600019909101905b6040517f5a6f45de0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015284811660248301526044820184905282811660648301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b21690635a6f45de906084016020604051808303816000875af1158015613547573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356b91906144dc565b604080518481526001600160a01b038481166020830152929650828616928a16917fe7655dfddd0226889710c711da4e725dd44525fb5717b2321017a97d32793ab8910160405180910390a35050509392505050565b600080806135d186880188614e91565b905060008460018111156135e7576135e761445c565b036135f5576135f581613e23565b6040517f432017e80000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b2169063432017e890613663908c9086908b908b90600401614eaa565b6060604051808303816000875af1158015613682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a69190614ee7565b909550935090506136b681613f3f565b60008560018111156136ca576136ca61445c565b0361371757886001600160a01b03167fcb6767c6e25552f1ab37156882f03b9ba603ebf3814463bf5eb9b0d2bd8a19b58360405161370a91815260200190565b60405180910390a261375b565b886001600160a01b03167f9ddbe9792bb03a06eab016daae23f04ec25454c24b836da2361fc703037f77628360405161375291815260200190565b60405180910390a25b50509550959350505050565b600061377582840184614f15565b6040517f3031b01a0000000000000000000000000000000000000000000000000000000081529091506001600160a01b037f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b21690633031b01a906137df9087908590600401614fd3565b600060405180830381600087803b1580156137f957600080fd5b505af115801561380d573d6000803e3d6000fd5b5050505050505050565b6040517fe09357a40000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301527f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b2169063e09357a490602401600060405180830381600087803b15801561389357600080fd5b505af11580156138a7573d6000803e3d6000fd5b5050505050565b6060612cf0838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250613f9e565b6109de6001613817565b6040517fd4eb5db00000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000ad131da4bddb40ebb5ceeaea87067553d43138959091169063d4eb5db0906024015b602060405180830381865afa158015613981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116db919061503a565b60005460ff166109de5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611115565b6040517f3a41ec640000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000ad131da4bddb40ebb5ceeaea87067553d431389590911690633a41ec6490602401613964565b60006001600160a01b03821615613a7a57816116db565b7f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b26001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612591573d6000803e3d6000fd5b6040517f5f259aba0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f000000000000000000000000ad131da4bddb40ebb5ceeaea87067553d431389590911690635f259aba90602401613964565b60005b8115613b5e57600019820190911690600101613b47565b919050565b6370a0823160e01b6000818152600483905290602082602481875afa600051925060203d1081151715612f57576040513d6000823e3d81fd5b600080613bb26001600160a01b03861687613b63565b90506000836001811115613bc857613bc861445c565b148015613bd55750838110155b80613bfc57506001836001811115613bef57613bef61445c565b148015613bfc5750838111155b9695505050505050565b60006040518481528360048201528260248201526020600060448360008a5af19150508015612da1573d8015613c4857600160005114601f3d111691506128e0565b50505050903b1515919050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115613ced5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401611115565b5090565b600080821215613ced5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401611115565b6040517f830aa7450000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015284811660248301528381166044830152606482018390526000917f000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b29091169063830aa745906084016020604051808303816000875af1158015613de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0491906144dc565b95945050505050565b6000818310613e1c5781612cf0565b5090919050565b600054600160d81b900460ff1660fe198101613e3d575050565b6001546000904367ffffffffffffffff90911603613e7e57600154613e77906801000000000000000090046001600160801b031684615057565b9050613e9e565b506001805467ffffffffffffffff19164367ffffffffffffffff16179055815b600354613ebe90600160801b90046001600160801b031660ff8416614445565b811115613ef7576040517f675f1a5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160801b0390921668010000000000000000027fffffffffffffffff00000000000000000000000000000000ffffffffffffffff9092169190911790555050565b6003546001600160801b0381169060801c8215801590613f67575081831080613f6757508083115b15612e0b576040517fce16799400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060824710156140165760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611115565b600080866001600160a01b03168587604051614032919061506a565b60006040518083038185875af1925050503d806000811461406f576040519150601f19603f3d011682016040523d82523d6000602084013e614074565b606091505b509150915061408587838387614090565b979650505050505050565b606083156140ff5782516000036140f8576001600160a01b0385163b6140f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611115565b5081612da1565b612da183838151156141145781518083602001fd5b8060405162461bcd60e51b81526004016111159190614c67565b6001600160801b0381168114610ed257600080fd5b8015158114610ed257600080fd5b6000806040838503121561416457600080fd5b823561416f8161412e565b9150602083013561417f81614143565b809150509250929050565b803560ff81168114613b5e57600080fd5b6000806000606084860312156141b057600080fd5b83356141bb8161412e565b925060208401356141cb8161412e565b91506141d96040850161418a565b90509250925092565b6001600160a01b0381168114610ed257600080fd5b6000806040838503121561420a57600080fd5b8235614215816141e2565b915060208301356002811061417f57600080fd5b60008083601f84011261423b57600080fd5b50813567ffffffffffffffff81111561425357600080fd5b6020830191508360208260051b850101111561426e57600080fd5b9250929050565b60008060006040848603121561428a57600080fd5b8335614295816141e2565b9250602084013567ffffffffffffffff8111156142b157600080fd5b6142bd86828701614229565b9497909650939450505050565b6000602082840312156142dc57600080fd5b8135612cf0816141e2565b600080600080606085870312156142fd57600080fd5b8435614308816141e2565b9350602085013567ffffffffffffffff81111561432457600080fd5b61433087828801614229565b9598909750949560400135949350505050565b6001600160c01b0381168114610ed257600080fd5b60008060006060848603121561436d57600080fd5b8335614378816141e2565b92506020840135614388816141e2565b9150604084013561439881614343565b809150509250925092565b600080600080606085870312156143b957600080fd5b84356143c4816141e2565b935060208501356143d4816141e2565b9250604085013567ffffffffffffffff8111156143f057600080fd5b6143fc87828801614229565b95989497509550505050565b60006020828403121561441a57600080fd5b813564ffffffffff81168114612cf057600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176116db576116db61442f565b634e487b7160e01b600052602160045260246000fd5b60008060006060848603121561448757600080fd5b835161449281614343565b60208501519093506144a381614143565b604085015190925061439881614143565b8051613b5e816141e2565b6000602082840312156144d157600080fd5b8151612cf0816141e2565b6000602082840312156144ee57600080fd5b5051919050565b6001600160a01b038316815260408101600583106145155761451561445c565b8260208301529392505050565b634e487b7160e01b600052604160045260246000fd5b6040516101c0810167ffffffffffffffff8111828210171561455c5761455c614522565b60405290565b6040805190810167ffffffffffffffff8111828210171561455c5761455c614522565b604051601f8201601f1916810167ffffffffffffffff811182821017156145ae576145ae614522565b604052919050565b8051613b5e8161412e565b600067ffffffffffffffff8211156145db576145db614522565b5060051b60200190565b600082601f8301126145f657600080fd5b8151602061460b614606836145c1565b614585565b82815260059290921b8401810191818101908684111561462a57600080fd5b8286015b8481101561464e578051614641816141e2565b835291830191830161462e565b509695505050505050565b60006020828403121561466b57600080fd5b815167ffffffffffffffff8082111561468357600080fd5b908301906101c0828603121561469857600080fd5b6146a0614538565b8251815260208301516020820152604083015160408201526146c4606084016145b6565b60608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250610140808401518183015250610160808401518183015250610180808401518381111561473557600080fd5b614741888287016145e5565b8284015250506101a091506147578284016144b4565b91810191909152949350505050565b600081518084526020808501945080840160005b8381101561479f5781516001600160a01b03168752958201959082019060010161477a565b509495945050505050565b6001600160a01b03851681526080602082015283516080820152602084015160a0820152604084015160c0820152600060608501516147f460e08401826001600160801b03169052565b5060808501516101008381019190915260a08601516101208085019190915260c08701516101408086019190915260e0880151610160808701919091529288015161018080870191909152918801516101a080870191909152908801516101c080870191909152928801516101e086015281880151610200860193909352614880610240860184614766565b908801516001600160a01b039081166102208701528716604086015285151560608601529250613e04915050565b600080604083850312156148c157600080fd5b505080516020909101519092909150565b6001600160801b038181168382160190808211156148f2576148f261442f565b5092915050565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261492557600080fd5b9190910192915050565b6000808335601e1984360301811261494657600080fd5b83018035915067ffffffffffffffff82111561496157600080fd5b60200191503681900382131561426e57600080fd5b6001600160e01b03198135818116916004851015612f575760049490940360031b84901b1690921692915050565b600080858511156149b457600080fd5b838611156149c157600080fd5b5050820193919092039150565b600060208083850312156149e157600080fd5b823567ffffffffffffffff8111156149f857600080fd5b8301601f81018513614a0957600080fd5b8035614a17614606826145c1565b81815260069190911b82018301908381019087831115614a3657600080fd5b928401925b828410156140855760408489031215614a545760008081fd5b614a5c614562565b8435614a67816141e2565b81528486013586820152825260409093019290840190614a3b565b61ffff81168114610ed257600080fd5b8035613b5e81614a82565b60008060408385031215614ab057600080fd5b823567ffffffffffffffff811115614ac757600080fd5b8301601f81018513614ad857600080fd5b80356020614ae8614606836145c1565b82815260059290921b83018101918181019088841115614b0757600080fd5b938201935b83851015614b2557843582529382019390820190614b0c565b9550614b349050868201614a92565b93505050509250929050565b600060208284031215614b5257600080fd5b8151612cf081614a82565b600080600060608486031215614b7257600080fd5b8335614b7d816141e2565b9250602084810135614b8e81614143565b9250604085013567ffffffffffffffff80821115614bab57600080fd5b818701915087601f830112614bbf57600080fd5b813581811115614bd157614bd1614522565b614be3601f8201601f19168501614585565b91508082528884828501011115614bf957600080fd5b80848401858401376000848284010152508093505050509250925092565b60005b83811015614c32578181015183820152602001614c1a565b50506000910152565b60008151808452614c53816020860160208601614c17565b601f01601f19169290920160200192915050565b602081526000612cf06020830184614c3b565b600060a082016001600160a01b03881683526020878185015260a0604085015281875180845260c086019150828901935060005b81811015614cca57845183529383019391830191600101614cae565b505061ffff9690961660608501525050509015156080909101529392505050565b8082018281126000831280158216821582161715612f5757612f5761442f565b60008060408385031215614d1e57600080fd5b8235614d29816141e2565b946020939093013593505050565b60008060008060008060c08789031215614d5057600080fd5b8635614d5b816141e2565b95506020870135945060408701359350614d776060880161418a565b92506080870135915060a087013590509295509295509295565b600080600060608486031215614da657600080fd5b8335614db1816141e2565b92506020840135600b81900b8114614dc857600080fd5b915060408401356bffffffffffffffffffffffff8116811461439857600080fd5b600081600b0b83600b0b80614e0e57634e487b7160e01b600052601260045260246000fd5b6b7fffffffffffffffffffffff19821460001982141615614e3157614e3161442f565b90059392505050565b600082600b0b82600b0b0280600b0b91508082146148f2576148f261442f565b600080600060608486031215614e6f57600080fd5b8335614e7a816141e2565b9250602084013591506040840135614398816141e2565b600060208284031215614ea357600080fd5b5035919050565b6001600160a01b038516815260208101849052604081018390526080810160028310614ed857614ed861445c565b82606083015295945050505050565b600080600060608486031215614efc57600080fd5b8351925060208401519150604084015190509250925092565b60006020808385031215614f2857600080fd5b823567ffffffffffffffff811115614f3f57600080fd5b8301601f81018513614f5057600080fd5b8035614f5e614606826145c1565b81815260069190911b82018301908381019087831115614f7d57600080fd5b928401925b828410156140855760408489031215614f9b5760008081fd5b614fa3614562565b8435614fae816141e2565b815284860135614fbd816141e2565b8187015282526040939093019290840190614f82565b600060408083016001600160a01b03808716855260208381870152828751808552606088019150828901945060005b8181101561502b5785518051861684528401518516848401529483019491860191600101615002565b50909998505050505050505050565b60006020828403121561504c57600080fd5b8151612cf081614143565b808201808211156116db576116db61442f565b60008251614925818460208701614c1756fea264697066735822122036f7b207925b1e86f09f35200705d9729576765715a7e0fa64573f5a3ba7f4cd64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _creditManager (address): 0xfd8e94a216C80dB2e892b59cCCa668Df5Ee589b2
Arg [1] : _degenNFT (address): 0x0000000000000000000000000000000000000000
Arg [2] : _expirable (bool): False
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000fd8e94a216c80db2e892b59ccca668df5ee589b2
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.