Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
VaultManagerLiquidationBoost
Compiler Version
v0.8.12+commit.f00d7308
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./VaultManager.sol"; /// @title VaultManagerLiquidationBoost /// @author Angle Labs, Inc. /// @notice Liquidation discount depending also on the liquidator veANGLE balance contract VaultManagerLiquidationBoost is VaultManager { using SafeERC20 for IERC20; using Address for address; // =================================== SETTER ================================== /// @inheritdoc VaultManager /// @param _veBoostProxy Address which queries veANGLE balances and adjusted balances from delegation /// @param xBoost Threshold values of veANGLE adjusted balances /// @param yBoost Values of the liquidation boost at the threshold values of x /// @dev There are 2 modes: /// When boost is enabled, `xBoost` and `yBoost` should have a length of 2, but if they have a /// higher length contract will still work as expected. Contract will also work as expected if their /// length differ /// When boost is disabled, `_veBoostProxy` needs to be zero address and `yBoost[0]` is the base boost function setLiquidationBoostParameters( address _veBoostProxy, uint256[] memory xBoost, uint256[] memory yBoost ) external override onlyGovernorOrGuardian { if ( (xBoost.length != yBoost.length) || (yBoost[0] == 0) || ((_veBoostProxy != address(0)) && (xBoost[1] <= xBoost[0] || yBoost[1] < yBoost[0])) ) revert InvalidSetOfParameters(); veBoostProxy = IVeBoostProxy(_veBoostProxy); xLiquidationBoost = xBoost; yLiquidationBoost = yBoost; emit LiquidationBoostParametersUpdated(_veBoostProxy, xBoost, yBoost); } // ======================== OVERRIDEN VIRTUAL FUNCTIONS ======================== /// @inheritdoc VaultManager function _computeLiquidationBoost(address liquidator) internal view override returns (uint256) { if (address(veBoostProxy) == address(0)) { return yLiquidationBoost[0]; } else { uint256 adjustedBalance = veBoostProxy.adjusted_balance_of(liquidator); if (adjustedBalance >= xLiquidationBoost[1]) return yLiquidationBoost[1]; else if (adjustedBalance <= xLiquidationBoost[0]) return yLiquidationBoost[0]; else return yLiquidationBoost[0] + ((yLiquidationBoost[1] - yLiquidationBoost[0]) * (adjustedBalance - xLiquidationBoost[0])) / (xLiquidationBoost[1] - xLiquidationBoost[0]); } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./VaultManagerPermit.sol"; /// @title VaultManager /// @author Angle Labs, Inc. /// @notice This contract allows people to deposit collateral and open up loans of a given AgToken. It handles all the loan /// logic (fees and interest rate) as well as the liquidation logic /// @dev This implementation only supports non-rebasing ERC20 tokens as collateral /// @dev This contract is encoded as a NFT contract contract VaultManager is VaultManagerPermit, IVaultManagerFunctions { using SafeERC20 for IERC20; using Address for address; /// @inheritdoc IVaultManagerFunctions uint256 public dust; /// @notice Minimum amount of collateral (in stablecoin value, e.g in `BASE_TOKENS = 10**18`) that can be left /// in a vault during a liquidation where the health factor function is decreasing uint256 internal _dustCollateral; uint256[48] private __gapVaultManager; /// @inheritdoc IVaultManagerFunctions function initialize( ITreasury _treasury, IERC20 _collateral, IOracle _oracle, VaultParameters calldata params, string memory _symbol ) external initializer { if (_oracle.treasury() != _treasury) revert InvalidTreasury(); treasury = _treasury; collateral = _collateral; _collatBase = 10**(IERC20Metadata(address(collateral)).decimals()); stablecoin = IAgToken(_treasury.stablecoin()); oracle = _oracle; string memory _name = string.concat("Angle Protocol ", _symbol, " Vault"); name = _name; __ERC721Permit_init(_name); symbol = string.concat(_symbol, "-vault"); interestAccumulator = BASE_INTEREST; lastInterestAccumulatorUpdated = block.timestamp; // Checking if the parameters have been correctly initialized if ( params.collateralFactor > params.liquidationSurcharge || params.liquidationSurcharge > BASE_PARAMS || BASE_PARAMS > params.targetHealthFactor || params.maxLiquidationDiscount >= BASE_PARAMS || params.baseBoost == 0 ) revert InvalidSetOfParameters(); debtCeiling = params.debtCeiling; collateralFactor = params.collateralFactor; targetHealthFactor = params.targetHealthFactor; interestRate = params.interestRate; liquidationSurcharge = params.liquidationSurcharge; maxLiquidationDiscount = params.maxLiquidationDiscount; whitelistingActivated = params.whitelistingActivated; yLiquidationBoost = [params.baseBoost]; paused = true; } // ================================= MODIFIERS ================================= /// @notice Checks whether the `msg.sender` has the governor role or not modifier onlyGovernor() { if (!treasury.isGovernor(msg.sender)) revert NotGovernor(); _; } /// @notice Checks whether the `msg.sender` has the governor role or the guardian role modifier onlyGovernorOrGuardian() { if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian(); _; } /// @notice Checks whether the `msg.sender` is the treasury contract modifier onlyTreasury() { if (msg.sender != address(treasury)) revert NotTreasury(); _; } /// @notice Checks whether the contract is paused modifier whenNotPaused() { if (paused) revert Paused(); _; } // ============================== VAULT FUNCTIONS ============================== /// @inheritdoc IVaultManagerFunctions function createVault(address toVault) external whenNotPaused returns (uint256) { return _mint(toVault); } /// @inheritdoc IVaultManagerFunctions function angle( ActionType[] memory actions, bytes[] memory datas, address from, address to ) external returns (PaymentData memory) { return angle(actions, datas, from, to, address(0), new bytes(0)); } /// @inheritdoc IVaultManagerFunctions function angle( ActionType[] memory actions, bytes[] memory datas, address from, address to, address who, bytes memory repayData ) public whenNotPaused nonReentrant returns (PaymentData memory paymentData) { if (actions.length != datas.length || actions.length == 0) revert IncompatibleLengths(); // `newInterestAccumulator` and `oracleValue` are expensive to compute. Therefore, they are computed // only once inside the first action where they are necessary, then they are passed forward to further actions uint256 newInterestAccumulator; uint256 oracleValue; uint256 collateralAmount; uint256 stablecoinAmount; uint256 vaultID; for (uint256 i; i < actions.length; ++i) { ActionType action = actions[i]; // Processing actions which do not need the value of the oracle or of the `interestAccumulator` if (action == ActionType.createVault) { _mint(abi.decode(datas[i], (address))); } else if (action == ActionType.addCollateral) { (vaultID, collateralAmount) = abi.decode(datas[i], (uint256, uint256)); if (vaultID == 0) vaultID = vaultIDCount; _addCollateral(vaultID, collateralAmount); paymentData.collateralAmountToReceive += collateralAmount; } else if (action == ActionType.permit) { address owner; bytes32 r; bytes32 s; // Watch out naming conventions for permit are not respected to save some space and reduce the stack size // `vaultID` is used in place of the `deadline` parameter // Same for `collateralAmount` used in place of `value` // `stablecoinAmount` is used in place of the `v` (owner, collateralAmount, vaultID, stablecoinAmount, r, s) = abi.decode( datas[i], (address, uint256, uint256, uint256, bytes32, bytes32) ); IERC20PermitUpgradeable(address(collateral)).permit( owner, address(this), collateralAmount, vaultID, uint8(stablecoinAmount), r, s ); } else { // Processing actions which rely on the `interestAccumulator`: first accruing it to make // sure surplus is correctly taken into account between debt changes if (newInterestAccumulator == 0) newInterestAccumulator = _accrue(); if (action == ActionType.repayDebt) { (vaultID, stablecoinAmount) = abi.decode(datas[i], (uint256, uint256)); if (vaultID == 0) vaultID = vaultIDCount; stablecoinAmount = _repayDebt(vaultID, stablecoinAmount, newInterestAccumulator); uint256 stablecoinAmountPlusRepayFee = (stablecoinAmount * BASE_PARAMS) / (BASE_PARAMS - repayFee); surplus += stablecoinAmountPlusRepayFee - stablecoinAmount; paymentData.stablecoinAmountToReceive += stablecoinAmountPlusRepayFee; } else { // Processing actions which need the oracle value if (oracleValue == 0) oracleValue = oracle.read(); if (action == ActionType.closeVault) { vaultID = abi.decode(datas[i], (uint256)); if (vaultID == 0) vaultID = vaultIDCount; (stablecoinAmount, collateralAmount) = _closeVault( vaultID, oracleValue, newInterestAccumulator ); paymentData.collateralAmountToGive += collateralAmount; paymentData.stablecoinAmountToReceive += stablecoinAmount; } else if (action == ActionType.removeCollateral) { (vaultID, collateralAmount) = abi.decode(datas[i], (uint256, uint256)); if (vaultID == 0) vaultID = vaultIDCount; _removeCollateral(vaultID, collateralAmount, oracleValue, newInterestAccumulator); paymentData.collateralAmountToGive += collateralAmount; } else if (action == ActionType.borrow) { (vaultID, stablecoinAmount) = abi.decode(datas[i], (uint256, uint256)); if (vaultID == 0) vaultID = vaultIDCount; stablecoinAmount = _borrow(vaultID, stablecoinAmount, oracleValue, newInterestAccumulator); paymentData.stablecoinAmountToGive += stablecoinAmount; } else if (action == ActionType.getDebtIn) { address vaultManager; uint256 dstVaultID; (vaultID, vaultManager, dstVaultID, stablecoinAmount) = abi.decode( datas[i], (uint256, address, uint256, uint256) ); if (vaultID == 0) vaultID = vaultIDCount; _getDebtIn( vaultID, IVaultManager(vaultManager), dstVaultID, stablecoinAmount, oracleValue, newInterestAccumulator ); } } } } // Processing the different cases for the repayment, there are 4 of them: // - (1) Stablecoins to receive + collateral to send // - (2) Stablecoins to receive + collateral to receive // - (3) Stablecoins to send + collateral to send // - (4) Stablecoins to send + collateral to receive if (paymentData.stablecoinAmountToReceive >= paymentData.stablecoinAmountToGive) { uint256 stablecoinPayment = paymentData.stablecoinAmountToReceive - paymentData.stablecoinAmountToGive; if (paymentData.collateralAmountToGive >= paymentData.collateralAmountToReceive) { // In the case where all amounts are null, the function will enter here and nothing will be done // for the repayment _handleRepay( // Collateral payment is the difference between what to give and what to receive paymentData.collateralAmountToGive - paymentData.collateralAmountToReceive, stablecoinPayment, from, to, who, repayData ); } else { if (stablecoinPayment != 0) stablecoin.burnFrom(stablecoinPayment, from, msg.sender); // In this case the collateral amount is necessarily non null collateral.safeTransferFrom( msg.sender, address(this), paymentData.collateralAmountToReceive - paymentData.collateralAmountToGive ); } } else { uint256 stablecoinPayment = paymentData.stablecoinAmountToGive - paymentData.stablecoinAmountToReceive; // `stablecoinPayment` is strictly positive in this case stablecoin.mint(to, stablecoinPayment); if (paymentData.collateralAmountToGive > paymentData.collateralAmountToReceive) { collateral.safeTransfer(to, paymentData.collateralAmountToGive - paymentData.collateralAmountToReceive); } else { uint256 collateralPayment = paymentData.collateralAmountToReceive - paymentData.collateralAmountToGive; if (collateralPayment != 0) { if (repayData.length != 0) { ISwapper(who).swap( IERC20(address(stablecoin)), collateral, msg.sender, // As per the `ISwapper` interface, we must first give the amount of token owed by the address before // the amount of token it (or another related address) obtained collateralPayment, stablecoinPayment, repayData ); } collateral.safeTransferFrom(msg.sender, address(this), collateralPayment); } } } } /// @inheritdoc IVaultManagerFunctions function getDebtOut( uint256 vaultID, uint256 stablecoinAmount, uint256 senderBorrowFee, uint256 senderRepayFee ) external whenNotPaused { if (!treasury.isVaultManager(msg.sender)) revert NotVaultManager(); // Getting debt out of a vault is equivalent to repaying a portion of your debt, and this could leave exploits: // someone could borrow from a vault and transfer its debt to a `VaultManager` contract where debt repayment will // be cheaper: in which case we're making people pay the delta uint256 _repayFee; if (repayFee > senderRepayFee) { _repayFee = repayFee - senderRepayFee; } // Checking the delta of borrow fees to eliminate the risk of exploits here: a similar thing could happen: people // could mint from where it is cheap to mint and then transfer their debt to places where it is more expensive // to mint uint256 _borrowFee; if (senderBorrowFee > borrowFee) { _borrowFee = senderBorrowFee - borrowFee; } uint256 stablecoinAmountLessFeePaid = (stablecoinAmount * (BASE_PARAMS - _repayFee) * (BASE_PARAMS - _borrowFee)) / (BASE_PARAMS**2); surplus += stablecoinAmount - stablecoinAmountLessFeePaid; _repayDebt(vaultID, stablecoinAmountLessFeePaid, 0); } // =============================== VIEW FUNCTIONS ============================== /// @inheritdoc IVaultManagerFunctions function getVaultDebt(uint256 vaultID) external view returns (uint256) { return (vaultData[vaultID].normalizedDebt * _calculateCurrentInterestAccumulator()) / BASE_INTEREST; } /// @inheritdoc IVaultManagerFunctions function getTotalDebt() external view returns (uint256) { return (totalNormalizedDebt * _calculateCurrentInterestAccumulator()) / BASE_INTEREST; } /// @notice Checks whether a given vault is liquidable and if yes gives information regarding its liquidation /// @param vaultID ID of the vault to check /// @param liquidator Address of the liquidator which will be performing the liquidation /// @return liqOpp Description of the opportunity of liquidation /// @dev This function will revert if it's called on a vault that does not exist function checkLiquidation(uint256 vaultID, address liquidator) external view returns (LiquidationOpportunity memory liqOpp) { liqOpp = _checkLiquidation( vaultData[vaultID], liquidator, oracle.read(), _calculateCurrentInterestAccumulator() ); } // ====================== INTERNAL UTILITY VIEW FUNCTIONS ====================== /// @notice Computes the health factor of a given vault. This can later be used to check whether a given vault is solvent /// (i.e. should be liquidated or not) /// @param vault Data of the vault to check /// @param oracleValue Oracle value at the time of the call (it is in the base of the stablecoin, that is for agTokens 10**18) /// @param newInterestAccumulator Value of the `interestAccumulator` at the time of the call /// @return healthFactor Health factor of the vault: if it's inferior to 1 (`BASE_PARAMS` in fact) this means that the vault can be liquidated /// @return currentDebt Current value of the debt of the vault (taking into account interest) /// @return collateralAmountInStable Collateral in the vault expressed in stablecoin value function _isSolvent( Vault memory vault, uint256 oracleValue, uint256 newInterestAccumulator ) internal view returns ( uint256 healthFactor, uint256 currentDebt, uint256 collateralAmountInStable ) { currentDebt = (vault.normalizedDebt * newInterestAccumulator) / BASE_INTEREST; collateralAmountInStable = (vault.collateralAmount * oracleValue) / _collatBase; if (currentDebt == 0) healthFactor = type(uint256).max; else healthFactor = (collateralAmountInStable * collateralFactor) / currentDebt; } /// @notice Calculates the current value of the `interestAccumulator` without updating the value /// in storage /// @dev This function avoids expensive exponentiation and the calculation is performed using a binomial approximation /// (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3... /// @dev The approximation slightly undercharges borrowers with the advantage of a great gas cost reduction /// @dev This function was mostly inspired from Aave implementation function _calculateCurrentInterestAccumulator() internal view returns (uint256) { uint256 exp = block.timestamp - lastInterestAccumulatorUpdated; uint256 ratePerSecond = interestRate; if (exp == 0 || ratePerSecond == 0) return interestAccumulator; uint256 expMinusOne = exp - 1; uint256 expMinusTwo = exp > 2 ? exp - 2 : 0; uint256 basePowerTwo = (ratePerSecond * ratePerSecond + HALF_BASE_INTEREST) / BASE_INTEREST; uint256 basePowerThree = (basePowerTwo * ratePerSecond + HALF_BASE_INTEREST) / BASE_INTEREST; uint256 secondTerm = (exp * expMinusOne * basePowerTwo) / 2; uint256 thirdTerm = (exp * expMinusOne * expMinusTwo * basePowerThree) / 6; return (interestAccumulator * (BASE_INTEREST + ratePerSecond * exp + secondTerm + thirdTerm)) / BASE_INTEREST; } // ================= INTERNAL UTILITY STATE-MODIFYING FUNCTIONS ================ /// @notice Closes a vault without handling the repayment of the concerned address /// @param vaultID ID of the vault to close /// @param oracleValue Oracle value at the start of the call /// @param newInterestAccumulator Interest rate accumulator value at the start of the call /// @return Current debt of the vault to be repaid /// @return Value of the collateral in the vault to reimburse /// @dev The returned values are here to facilitate composability between calls function _closeVault( uint256 vaultID, uint256 oracleValue, uint256 newInterestAccumulator ) internal onlyApprovedOrOwner(msg.sender, vaultID) returns (uint256, uint256) { Vault memory vault = vaultData[vaultID]; (uint256 healthFactor, uint256 currentDebt, ) = _isSolvent(vault, oracleValue, newInterestAccumulator); if (healthFactor <= BASE_PARAMS) revert InsolventVault(); totalNormalizedDebt -= vault.normalizedDebt; _burn(vaultID); uint256 currentDebtPlusRepayFee = (currentDebt * BASE_PARAMS) / (BASE_PARAMS - repayFee); surplus += currentDebtPlusRepayFee - currentDebt; return (currentDebtPlusRepayFee, vault.collateralAmount); } /// @notice Increases the collateral balance of a vault /// @param vaultID ID of the vault to increase the collateral balance of /// @param collateralAmount Amount by which increasing the collateral balance of function _addCollateral(uint256 vaultID, uint256 collateralAmount) internal { if (!_exists(vaultID)) revert NonexistentVault(); _checkpointCollateral(vaultID, collateralAmount, true); vaultData[vaultID].collateralAmount += collateralAmount; emit CollateralAmountUpdated(vaultID, collateralAmount, 1); } /// @notice Decreases the collateral balance from a vault (without proceeding to collateral transfers) /// @param vaultID ID of the vault to decrease the collateral balance of /// @param collateralAmount Amount of collateral to reduce the balance of /// @param oracleValue Oracle value at the start of the call (given here to avoid double computations) /// @param interestAccumulator_ Value of the interest rate accumulator (potentially zero if it has not been /// computed yet) function _removeCollateral( uint256 vaultID, uint256 collateralAmount, uint256 oracleValue, uint256 interestAccumulator_ ) internal onlyApprovedOrOwner(msg.sender, vaultID) { _checkpointCollateral(vaultID, collateralAmount, false); vaultData[vaultID].collateralAmount -= collateralAmount; (uint256 healthFactor, , ) = _isSolvent(vaultData[vaultID], oracleValue, interestAccumulator_); if (healthFactor <= BASE_PARAMS) revert InsolventVault(); emit CollateralAmountUpdated(vaultID, collateralAmount, 0); } /// @notice Increases the debt balance of a vault and takes into account borrowing fees /// @param vaultID ID of the vault to increase borrow balance of /// @param stablecoinAmount Amount of stablecoins to borrow /// @param oracleValue Oracle value at the start of the call /// @param newInterestAccumulator Value of the interest rate accumulator /// @return toMint Amount of stablecoins to mint function _borrow( uint256 vaultID, uint256 stablecoinAmount, uint256 oracleValue, uint256 newInterestAccumulator ) internal onlyApprovedOrOwner(msg.sender, vaultID) returns (uint256 toMint) { stablecoinAmount = _increaseDebt(vaultID, stablecoinAmount, oracleValue, newInterestAccumulator); uint256 borrowFeePaid = (borrowFee * stablecoinAmount) / BASE_PARAMS; surplus += borrowFeePaid; toMint = stablecoinAmount - borrowFeePaid; } /// @notice Gets debt in a vault from another vault potentially in another `VaultManager` contract /// @param srcVaultID ID of the vault from this contract for which growing debt /// @param vaultManager Address of the `VaultManager` where the targeted vault is /// @param dstVaultID ID of the vault in the target contract /// @param stablecoinAmount Amount of stablecoins to grow the debt of. This amount will be converted /// to a normalized value in both `VaultManager` contracts /// @param oracleValue Oracle value at the start of the call (potentially zero if it has not been computed yet) /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been /// computed yet) /// @dev A solvency check is performed after the debt increase in the source `vaultID` /// @dev Only approved addresses by the source vault owner can perform this action, however any vault /// from any vaultManager contract can see its debt reduced by this means function _getDebtIn( uint256 srcVaultID, IVaultManager vaultManager, uint256 dstVaultID, uint256 stablecoinAmount, uint256 oracleValue, uint256 newInterestAccumulator ) internal onlyApprovedOrOwner(msg.sender, srcVaultID) { emit DebtTransferred(srcVaultID, dstVaultID, address(vaultManager), stablecoinAmount); // The `stablecoinAmount` needs to be rounded down in the `_increaseDebt` function to reduce the room for exploits stablecoinAmount = _increaseDebt(srcVaultID, stablecoinAmount, oracleValue, newInterestAccumulator); if (address(vaultManager) == address(this)) { // No repayFees taken in this case, otherwise the same stablecoin may end up paying fees twice _repayDebt(dstVaultID, stablecoinAmount, newInterestAccumulator); } else { // No need to check the integrity of `VaultManager` here because `_getDebtIn` can be entered only through the // `angle` function which is non reentrant. Also, `getDebtOut` failing would be at the attacker loss, as they // would get their debt increasing in the current vault without decreasing it in the remote vault. vaultManager.getDebtOut(dstVaultID, stablecoinAmount, borrowFee, repayFee); } } /// @notice Increases the debt of a given vault and verifies that this vault is still solvent /// @param vaultID ID of the vault to increase the debt of /// @param stablecoinAmount Amount of stablecoin to increase the debt of: this amount is converted in /// normalized debt using the pre-computed (or not) `newInterestAccumulator` value /// @param oracleValue Oracle value at the start of the call (given here to avoid double computations) /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been /// computed yet) /// @return Amount of stablecoins to issue from this debt increase /// @dev The `stablecoinAmount` outputted need to be rounded down with respect to the change amount so that /// amount of stablecoins minted is smaller than the debt increase function _increaseDebt( uint256 vaultID, uint256 stablecoinAmount, uint256 oracleValue, uint256 newInterestAccumulator ) internal returns (uint256) { // We normalize the amount by dividing it by `newInterestAccumulator`. This makes accounting easier, since // it allows us to process all (past and future) debts like debts created at the inception of the contract. uint256 changeAmount = (stablecoinAmount * BASE_INTEREST) / newInterestAccumulator; // if there was no previous debt, we have to check that the debt creation will be higher than `dust` if (vaultData[vaultID].normalizedDebt == 0) if (stablecoinAmount <= dust) revert DustyLeftoverAmount(); vaultData[vaultID].normalizedDebt += changeAmount; totalNormalizedDebt += changeAmount; if (totalNormalizedDebt * newInterestAccumulator > debtCeiling * BASE_INTEREST) revert DebtCeilingExceeded(); (uint256 healthFactor, , ) = _isSolvent(vaultData[vaultID], oracleValue, newInterestAccumulator); if (healthFactor <= BASE_PARAMS) revert InsolventVault(); emit InternalDebtUpdated(vaultID, changeAmount, 1); return (changeAmount * newInterestAccumulator) / BASE_INTEREST; } /// @notice Decreases the debt of a given vault and verifies that this vault still has an amount of debt superior /// to a dusty amount or no debt at all /// @param vaultID ID of the vault to decrease the debt of /// @param stablecoinAmount Amount of stablecoin to decrease the debt of: this amount is converted in /// normalized debt using the pre-computed (or not) `newInterestAccumulator` value /// To repay the whole debt, one can pass `type(uint256).max` /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been /// computed yet, like in `getDebtOut`) /// @return Amount of stablecoins to be burnt to correctly repay the debt /// @dev If `stablecoinAmount` is `type(uint256).max`, this function will repay all the debt of the vault function _repayDebt( uint256 vaultID, uint256 stablecoinAmount, uint256 newInterestAccumulator ) internal returns (uint256) { if (newInterestAccumulator == 0) newInterestAccumulator = _accrue(); uint256 newVaultNormalizedDebt = vaultData[vaultID].normalizedDebt; // To save one variable declaration, `changeAmount` is first expressed in stablecoin amount before being converted // to a normalized amount. Here we first store the maximum amount that can be repaid given the current debt uint256 changeAmount = (newVaultNormalizedDebt * newInterestAccumulator) / BASE_INTEREST; // In some situations (e.g. liquidations), the `stablecoinAmount` is rounded above and we want to make // sure to avoid underflows in all situations if (stablecoinAmount >= changeAmount) { stablecoinAmount = changeAmount; changeAmount = newVaultNormalizedDebt; } else { changeAmount = (stablecoinAmount * BASE_INTEREST) / newInterestAccumulator; } newVaultNormalizedDebt -= changeAmount; totalNormalizedDebt -= changeAmount; if (newVaultNormalizedDebt != 0 && newVaultNormalizedDebt * newInterestAccumulator <= dust * BASE_INTEREST) revert DustyLeftoverAmount(); vaultData[vaultID].normalizedDebt = newVaultNormalizedDebt; emit InternalDebtUpdated(vaultID, changeAmount, 0); return stablecoinAmount; } /// @notice Handles the simultaneous repayment of stablecoins with a transfer of collateral /// @param collateralAmountToGive Amount of collateral the contract should give /// @param stableAmountToRepay Amount of stablecoins the contract should burn from the call /// @param from Address from which stablecoins should be burnt: it should be the `msg.sender` or at least /// approved by it /// @param to Address to which collateral should be sent /// @param who Address which should be notified if needed of the transfer /// @param data Data to pass to the `who` contract for it to successfully give the correct amount of stablecoins /// to the `from` address /// @dev This function allows for capital-efficient liquidations and repayments of loans function _handleRepay( uint256 collateralAmountToGive, uint256 stableAmountToRepay, address from, address to, address who, bytes memory data ) internal { if (collateralAmountToGive != 0) collateral.safeTransfer(to, collateralAmountToGive); if (stableAmountToRepay != 0) { if (data.length != 0) { ISwapper(who).swap( collateral, IERC20(address(stablecoin)), from, stableAmountToRepay, collateralAmountToGive, data ); } stablecoin.burnFrom(stableAmountToRepay, from, msg.sender); } } // ====================== TREASURY RELATIONSHIP FUNCTIONS ====================== /// @inheritdoc IVaultManagerFunctions function accrueInterestToTreasury() external onlyTreasury returns (uint256 surplusValue, uint256 badDebtValue) { _accrue(); surplusValue = surplus; badDebtValue = badDebt; surplus = 0; badDebt = 0; if (surplusValue >= badDebtValue) { surplusValue -= badDebtValue; badDebtValue = 0; stablecoin.mint(address(treasury), surplusValue); } else { badDebtValue -= surplusValue; surplusValue = 0; } emit AccruedToTreasury(surplusValue, badDebtValue); } /// @notice Accrues interest accumulated across all vaults to the surplus and updates the `interestAccumulator` /// @return newInterestAccumulator Computed value of the interest accumulator /// @dev It should also be called when updating the value of the per second interest rate or when the `totalNormalizedDebt` /// value is about to change function _accrue() internal returns (uint256 newInterestAccumulator) { newInterestAccumulator = _calculateCurrentInterestAccumulator(); uint256 interestAccrued = (totalNormalizedDebt * (newInterestAccumulator - interestAccumulator)) / BASE_INTEREST; surplus += interestAccrued; interestAccumulator = newInterestAccumulator; lastInterestAccumulatorUpdated = block.timestamp; emit InterestAccumulatorUpdated(newInterestAccumulator, block.timestamp); return newInterestAccumulator; } // ================================ LIQUIDATIONS =============================== /// @notice Liquidates an ensemble of vaults specified by their IDs /// @dev This function is a simplified wrapper of the function below. It is built to remove for liquidators the need to specify /// a `who` and a `data` parameter function liquidate( uint256[] memory vaultIDs, uint256[] memory amounts, address from, address to ) external returns (LiquidatorData memory) { return liquidate(vaultIDs, amounts, from, to, address(0), new bytes(0)); } /// @notice Liquidates an ensemble of vaults specified by their IDs /// @param vaultIDs List of the vaults to liquidate /// @param amounts Amount of stablecoin to bring for the liquidation of each vault /// @param from Address from which the stablecoins for the liquidation should be taken: this address should be the `msg.sender` /// or have received an approval /// @param to Address to which discounted collateral should be sent /// @param who Address of the contract to handle repayment of stablecoins from received collateral /// @param data Data to pass to the repayment contract in case of. If empty, liquidators simply have to bring the exact amount of /// stablecoins to get the discounted collateral. If not, it is used by the repayment contract to swap a portion or all /// of the collateral received to stablecoins to be sent to the `from` address. More details in the `_handleRepay` function /// @return liqData Data about the liquidation process for the liquidator to track everything that has been going on (like how much /// stablecoins have been repaid, how much collateral has been received) /// @dev This function will revert if it's called on a vault that cannot be liquidated or that does not exist function liquidate( uint256[] memory vaultIDs, uint256[] memory amounts, address from, address to, address who, bytes memory data ) public whenNotPaused nonReentrant returns (LiquidatorData memory liqData) { uint256 vaultIDsLength = vaultIDs.length; if (vaultIDsLength != amounts.length || vaultIDsLength == 0) revert IncompatibleLengths(); // Stores all the data about an ongoing liquidation of multiple vaults liqData.oracleValue = oracle.read(); liqData.newInterestAccumulator = _accrue(); emit LiquidatedVaults(vaultIDs); for (uint256 i; i < vaultIDsLength; ++i) { Vault memory vault = vaultData[vaultIDs[i]]; // Computing if liquidation can take place for a vault LiquidationOpportunity memory liqOpp = _checkLiquidation( vault, msg.sender, liqData.oracleValue, liqData.newInterestAccumulator ); // Makes sure not to leave a dusty amount in the vault by either not liquidating too much // or everything if ( (liqOpp.thresholdRepayAmount != 0 && amounts[i] >= liqOpp.thresholdRepayAmount) || amounts[i] > liqOpp.maxStablecoinAmountToRepay ) amounts[i] = liqOpp.maxStablecoinAmountToRepay; // liqOpp.discount stores in fact `1-discount` uint256 collateralReleased = (amounts[i] * BASE_PARAMS * _collatBase) / (liqOpp.discount * liqData.oracleValue); _checkpointCollateral( vaultIDs[i], vault.collateralAmount <= collateralReleased ? vault.collateralAmount : collateralReleased, false ); // Because we're rounding up in some divisions, `collateralReleased` can be greater than the `collateralAmount` of the vault // In this case, `stablecoinAmountToReceive` is still rounded up if (vault.collateralAmount <= collateralReleased) { collateralReleased = vault.collateralAmount; // Remove all the vault's debt (debt repayed + bad debt) from VaultManager totalDebt totalNormalizedDebt -= vault.normalizedDebt; // Reinitializing the `vaultID`: we're not burning the vault in this case for integration purposes delete vaultData[vaultIDs[i]]; { uint256 debtReimbursed = (amounts[i] * liquidationSurcharge) / BASE_PARAMS; liqData.badDebtFromLiquidation += debtReimbursed < liqOpp.currentDebt ? liqOpp.currentDebt - debtReimbursed : 0; } // There may be an edge case in which: `amounts[i] = (currentDebt * BASE_PARAMS) / surcharge + 1` // In this case, as long as `surcharge < BASE_PARAMS`, there cannot be any underflow in the operation // above emit InternalDebtUpdated(vaultIDs[i], vault.normalizedDebt, 0); } else { vaultData[vaultIDs[i]].collateralAmount -= collateralReleased; _repayDebt( vaultIDs[i], (amounts[i] * liquidationSurcharge) / BASE_PARAMS, liqData.newInterestAccumulator ); } liqData.collateralAmountToGive += collateralReleased; liqData.stablecoinAmountToReceive += amounts[i]; } // Normalization of good and bad debt is already handled in the `accrueInterestToTreasury` function surplus += (liqData.stablecoinAmountToReceive * (BASE_PARAMS - liquidationSurcharge)) / BASE_PARAMS; badDebt += liqData.badDebtFromLiquidation; _handleRepay(liqData.collateralAmountToGive, liqData.stablecoinAmountToReceive, from, to, who, data); } /// @notice Internal version of the `checkLiquidation` function /// @dev This function takes two additional parameters as when entering this function `oracleValue` /// and `newInterestAccumulator` should have always been computed function _checkLiquidation( Vault memory vault, address liquidator, uint256 oracleValue, uint256 newInterestAccumulator ) internal view returns (LiquidationOpportunity memory liqOpp) { // Checking if the vault can be liquidated (uint256 healthFactor, uint256 currentDebt, uint256 collateralAmountInStable) = _isSolvent( vault, oracleValue, newInterestAccumulator ); // Health factor of a vault that does not exist is `type(uint256).max` if (healthFactor >= BASE_PARAMS) revert HealthyVault(); uint256 liquidationDiscount = (_computeLiquidationBoost(liquidator) * (BASE_PARAMS - healthFactor)) / BASE_PARAMS; // In fact `liquidationDiscount` is stored here as 1 minus discount to save some computation costs // This value is necessarily != 0 as `maxLiquidationDiscount < BASE_PARAMS` liquidationDiscount = liquidationDiscount >= maxLiquidationDiscount ? BASE_PARAMS - maxLiquidationDiscount : BASE_PARAMS - liquidationDiscount; // Same for the surcharge here: it's in fact 1 - the fee taken by the protocol uint256 surcharge = liquidationSurcharge; // Checking if we're in a situation where the health factor is an increasing or a decreasing function of the // amount repaid uint256 maxAmountToRepay; uint256 thresholdRepayAmount; // In the first case, the health factor is an increasing function of the stablecoin amount to repay, // this means that the liquidator can bring the vault to the target health ratio if (healthFactor * liquidationDiscount * surcharge >= collateralFactor * BASE_PARAMS**2) { // This is the max amount to repay that will bring the person to the target health factor // Denom is always positive when a vault gets liquidated in this case and when the health factor // is an increasing function of the amount of stablecoins repaid // And given that most parameters are in base 9, the numerator can very hardly overflow here maxAmountToRepay = ((targetHealthFactor * currentDebt - collateralAmountInStable * collateralFactor) * BASE_PARAMS * liquidationDiscount) / (surcharge * targetHealthFactor * liquidationDiscount - (BASE_PARAMS**2) * collateralFactor); // The quantity below tends to be rounded in the above direction, which means that governance or guardians should // set the `targetHealthFactor` accordingly // Need to check for the dust: liquidating should not leave a dusty amount in the vault if (currentDebt * BASE_PARAMS <= maxAmountToRepay * surcharge + dust * BASE_PARAMS) { // If liquidating to the target threshold would leave a dusty amount: the liquidator can repay all // We're rounding up the max amount to repay to make sure all the debt ends up being paid // and we're computing again the real value of the debt to avoid propagation of rounding errors maxAmountToRepay = (vault.normalizedDebt * newInterestAccumulator * BASE_PARAMS) / (surcharge * BASE_INTEREST) + 1; // In this case the threshold amount is such that it leaves just enough dust: amount is rounded // down such that if a liquidator repays this amount then there would be more than `dust` left in // the liquidated vault if (currentDebt > dust) thresholdRepayAmount = ((currentDebt - dust) * BASE_PARAMS) / surcharge; // If there is from the beginning a dusty debt (because of an implementation upgrade), then // liquidator should repay everything that's left else thresholdRepayAmount = 1; } } else { // In all cases the liquidator can repay stablecoins such that they'll end up getting exactly the collateral // in the liquidated vault // Rounding up to make sure all gets liquidated in this case: the liquidator will never get more than the collateral // amount in the vault however: we're performing the computation of the `collateralAmountInStable` again to avoid // propagation of rounding errors maxAmountToRepay = (vault.collateralAmount * liquidationDiscount * oracleValue) / (BASE_PARAMS * _collatBase) + 1; // It should however make sure not to leave a dusty amount of collateral (in stablecoin value) in the vault if (collateralAmountInStable > _dustCollateral) // There's no issue with this amount being rounded down thresholdRepayAmount = ((collateralAmountInStable - _dustCollateral) * liquidationDiscount) / BASE_PARAMS; // If there is from the beginning a dusty amount of collateral, liquidator should repay everything that's left else thresholdRepayAmount = 1; } liqOpp.maxStablecoinAmountToRepay = maxAmountToRepay; liqOpp.maxCollateralAmountGiven = (maxAmountToRepay * BASE_PARAMS * _collatBase) / (oracleValue * liquidationDiscount); liqOpp.thresholdRepayAmount = thresholdRepayAmount; liqOpp.discount = liquidationDiscount; liqOpp.currentDebt = currentDebt; } // ================================== SETTERS ================================== /// @notice Sets parameters encoded as uint64 /// @param param Value for the parameter /// @param what Parameter to change /// @dev This function performs the required checks when updating a parameter /// @dev When setting parameters governance or the guardian should make sure that when `HF < CF/((1-surcharge)(1-discount))` /// and hence when liquidating a vault is going to decrease its health factor, `discount = max discount`. /// Otherwise, it may be profitable for the liquidator to liquidate in multiple times: as it will decrease /// the HF and therefore increase the discount between each time function setUint64(uint64 param, bytes32 what) external onlyGovernorOrGuardian { if (what == "CF") { if (param > liquidationSurcharge) revert TooHighParameterValue(); collateralFactor = param; } else if (what == "THF") { if (param < BASE_PARAMS) revert TooSmallParameterValue(); targetHealthFactor = param; } else if (what == "BF") { if (param > BASE_PARAMS) revert TooHighParameterValue(); borrowFee = param; } else if (what == "RF") { // As liquidation surcharge is stored as `1-fee` and as we need `repayFee` to be smaller // then the liquidation surcharge, then we need to have: // `liquidationSurcharge <= BASE_PARAMS - repayFee` and as such `liquidationSurcharge + repayFee <= BASE_PARAMS` if (param + liquidationSurcharge > BASE_PARAMS) revert TooHighParameterValue(); repayFee = param; } else if (what == "IR") { _accrue(); interestRate = param; } else if (what == "LS") { if (collateralFactor > param || param + repayFee > BASE_PARAMS) revert InvalidParameterValue(); liquidationSurcharge = param; } else if (what == "MLD") { if (param > BASE_PARAMS) revert TooHighParameterValue(); maxLiquidationDiscount = param; } else { revert InvalidParameterType(); } emit FiledUint64(param, what); } /// @notice Sets `debtCeiling` /// @param _debtCeiling New value for `debtCeiling` /// @dev `debtCeiling` should not be bigger than `type(uint256).max / 10**27` otherwise there could be overflows function setDebtCeiling(uint256 _debtCeiling) external onlyGovernorOrGuardian { debtCeiling = _debtCeiling; emit DebtCeilingUpdated(_debtCeiling); } /// @notice Sets the parameters for the liquidation booster which encodes the slope of the discount function setLiquidationBoostParameters( address _veBoostProxy, uint256[] memory xBoost, uint256[] memory yBoost ) external virtual onlyGovernorOrGuardian { if (yBoost[0] == 0) revert InvalidSetOfParameters(); yLiquidationBoost = yBoost; emit LiquidationBoostParametersUpdated(_veBoostProxy, xBoost, yBoost); } /// @notice Pauses external permissionless functions of the contract function togglePause() external onlyGovernorOrGuardian { paused = !paused; } /// @notice Changes the ERC721 metadata URI function setBaseURI(string memory baseURI_) external onlyGovernorOrGuardian { _baseURI = baseURI_; } /// @notice Changes the whitelisting of an address /// @param target Address to toggle /// @dev If the `target` address is the zero address then this function toggles whitelisting /// for all addresses function toggleWhitelist(address target) external onlyGovernor { if (target != address(0)) { isWhitelisted[target] = 1 - isWhitelisted[target]; } else { whitelistingActivated = !whitelistingActivated; } } /// @notice Changes the reference to the oracle contract used to get the price of the oracle /// @param _oracle Reference to the oracle contract function setOracle(address _oracle) external onlyGovernor { if (IOracle(_oracle).treasury() != treasury) revert InvalidTreasury(); oracle = IOracle(_oracle); } /// @notice Sets the dust variables /// @param _dust New minimum debt allowed /// @param dustCollateral_ New minimum collateral allowed in a vault after a liquidation /// @dev dustCollateral_ is in stable value function setDusts(uint256 _dust, uint256 dustCollateral_) external onlyGovernor { dust = _dust; _dustCollateral = dustCollateral_; } /// @inheritdoc IVaultManagerFunctions function setTreasury(address _treasury) external onlyTreasury { treasury = ITreasury(_treasury); // This function makes sure to propagate the change to the associated contract // even though a single oracle contract could be used in different places oracle.setTreasury(_treasury); } // ============================= VIRTUAL FUNCTIONS ============================= /// @notice Computes the liquidation boost of a given address, that is the slope of the discount function /// @return The slope of the discount function function _computeLiquidationBoost(address) internal view virtual returns (uint256) { return yLiquidationBoost[0]; } /// @notice Hook called before any collateral internal changes /// @param vaultID Vault which sees its collateral amount changed /// @param amount Collateral amount balance of the owner of vaultID increase/decrease /// @param add Whether the balance should be increased/decreased /// @param vaultID Vault which sees its collateral amount changed function _checkpointCollateral( uint256 vaultID, uint256 amount, bool add ) internal virtual {} }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./VaultManagerERC721.sol"; import "../interfaces/external/IERC1271.sol"; /// @title VaultManagerPermit /// @author Angle Labs, Inc. /// @dev Base Implementation of permit functions for the `VaultManager` contract abstract contract VaultManagerPermit is Initializable, VaultManagerERC721 { using Address for address; mapping(address => uint256) private _nonces; /* solhint-disable var-name-mixedcase */ bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private _PERMIT_TYPEHASH; /* solhint-enable var-name-mixedcase */ error ExpiredDeadline(); error InvalidSignature(); //solhint-disable-next-line function __ERC721Permit_init(string memory _name) internal onlyInitializing { _PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,bool approved,uint256 nonce,uint256 deadline)" ); _HASHED_NAME = keccak256(bytes(_name)); _HASHED_VERSION = keccak256(bytes("1")); } /// @notice Allows an address to give or revoke approval for all its vaults to another address /// @param owner Address signing the permit and giving (or revoking) its approval for all the controlled vaults /// @param spender Address to give approval to /// @param approved Whether to give or revoke the approval /// @param deadline Deadline parameter for the signature to be valid /// @dev The `v`, `r`, and `s` parameters are used as signature data function permit( address owner, address spender, bool approved, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { if (block.timestamp > deadline) revert ExpiredDeadline(); // Additional signature checks performed in the `ECDSAUpgradeable.recover` function if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 || (v != 27 && v != 28)) revert InvalidSignature(); bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", _domainSeparatorV4(), keccak256( abi.encode( _PERMIT_TYPEHASH, // 0x3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd8, owner, spender, approved, _useNonce(owner), deadline ) ) ) ); if (owner.isContract()) { if (IERC1271(owner).isValidSignature(digest, abi.encodePacked(r, s, v)) != 0x1626ba7e) revert InvalidSignature(); } else { address signer = ecrecover(digest, v, r, s); if (signer != owner || signer == address(0)) revert InvalidSignature(); } _setApprovalForAll(owner, spender, approved); } /// @notice Returns the current nonce for an `owner` address function nonces(address owner) public view returns (uint256) { return _nonces[owner]; } /// @notice Returns the domain separator for the current chain. // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { return _domainSeparatorV4(); } /// @notice Internal version of the `DOMAIN_SEPARATOR` function function _domainSeparatorV4() internal view returns (bytes32) { return keccak256( abi.encode( // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)') 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f, _HASHED_NAME, _HASHED_VERSION, block.chainid, address(this) ) ); } /// @notice Consumes a nonce for an address: returns the current value and increments it function _useNonce(address owner) internal returns (uint256 current) { current = _nonces[owner]; _nonces[owner] = current + 1; } uint256[49] private __gap; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./VaultManagerStorage.sol"; /// @title VaultManagerERC721 /// @author Angle Labs, Inc. /// @dev Base ERC721 Implementation of VaultManager abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManagerStorage { using SafeERC20 for IERC20; using Address for address; /// @inheritdoc IERC721MetadataUpgradeable string public name; /// @inheritdoc IERC721MetadataUpgradeable string public symbol; // ================================= MODIFIERS ================================= /// @notice Checks if the person interacting with the vault with `vaultID` is approved /// @param caller Address of the person seeking to interact with the vault /// @param vaultID ID of the concerned vault modifier onlyApprovedOrOwner(address caller, uint256 vaultID) { if (!_isApprovedOrOwner(caller, vaultID)) revert NotApproved(); _; } // ================================ ERC721 LOGIC =============================== /// @notice Checks whether a given address is approved for a vault or owns this vault /// @param spender Address for which vault ownership should be checked /// @param vaultID ID of the vault to check /// @return Whether the `spender` address owns or is approved for `vaultID` function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool) { return _isApprovedOrOwner(spender, vaultID); } /// @inheritdoc IERC721MetadataUpgradeable function tokenURI(uint256 vaultID) external view returns (string memory) { if (!_exists(vaultID)) revert NonexistentVault(); // There is no vault with `vaultID` equal to 0, so the following variable is // always greater than zero uint256 temp = vaultID; uint256 digits; while (temp != 0) { ++digits; temp /= 10; } bytes memory buffer = new bytes(digits); while (vaultID != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(vaultID % 10))); vaultID /= 10; } return bytes(_baseURI).length != 0 ? string(abi.encodePacked(_baseURI, string(buffer))) : ""; } /// @inheritdoc IERC721Upgradeable function balanceOf(address owner) external view returns (uint256) { if (owner == address(0)) revert ZeroAddress(); return _balances[owner]; } /// @inheritdoc IERC721Upgradeable function ownerOf(uint256 vaultID) external view returns (address) { return _ownerOf(vaultID); } /// @inheritdoc IERC721Upgradeable function approve(address to, uint256 vaultID) external { address owner = _ownerOf(vaultID); if (to == owner) revert ApprovalToOwner(); if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) revert NotApproved(); _approve(to, vaultID); } /// @inheritdoc IERC721Upgradeable function getApproved(uint256 vaultID) external view returns (address) { if (!_exists(vaultID)) revert NonexistentVault(); return _getApproved(vaultID); } /// @inheritdoc IERC721Upgradeable function setApprovalForAll(address operator, bool approved) external { _setApprovalForAll(msg.sender, operator, approved); } /// @inheritdoc IERC721Upgradeable function isApprovedForAll(address owner, address operator) public view returns (bool) { return _operatorApprovals[owner][operator] == 1; } /// @inheritdoc IERC721Upgradeable function transferFrom( address from, address to, uint256 vaultID ) external onlyApprovedOrOwner(msg.sender, vaultID) { _transfer(from, to, vaultID); } /// @inheritdoc IERC721Upgradeable function safeTransferFrom( address from, address to, uint256 vaultID ) external { safeTransferFrom(from, to, vaultID, ""); } /// @inheritdoc IERC721Upgradeable function safeTransferFrom( address from, address to, uint256 vaultID, bytes memory _data ) public onlyApprovedOrOwner(msg.sender, vaultID) { _safeTransfer(from, to, vaultID, _data); } // ================================ ERC165 LOGIC =============================== /// @inheritdoc IERC165Upgradeable function supportsInterface(bytes4 interfaceId) external pure returns (bool) { return interfaceId == type(IERC721MetadataUpgradeable).interfaceId || interfaceId == type(IERC721Upgradeable).interfaceId || interfaceId == type(IVaultManager).interfaceId || interfaceId == type(IERC165Upgradeable).interfaceId; } // ================== INTERNAL FUNCTIONS FOR THE ERC721 LOGIC ================== /// @notice Internal version of the `ownerOf` function function _ownerOf(uint256 vaultID) internal view returns (address owner) { owner = _owners[vaultID]; if (owner == address(0)) revert NonexistentVault(); } /// @notice Internal version of the `getApproved` function function _getApproved(uint256 vaultID) internal view returns (address) { return _vaultApprovals[vaultID]; } /// @notice Internal version of the `safeTransferFrom` function (with the data parameter) function _safeTransfer( address from, address to, uint256 vaultID, bytes memory _data ) internal { _transfer(from, to, vaultID); if (!_checkOnERC721Received(from, to, vaultID, _data)) revert NonERC721Receiver(); } /// @notice Checks whether a vault exists /// @param vaultID ID of the vault to check /// @return Whether `vaultID` has been created function _exists(uint256 vaultID) internal view returns (bool) { return _owners[vaultID] != address(0); } /// @notice Internal version of the `isApprovedOrOwner` function function _isApprovedOrOwner(address spender, uint256 vaultID) internal view returns (bool) { // The following checks if the vault exists address owner = _ownerOf(vaultID); return (spender == owner || _getApproved(vaultID) == spender || _operatorApprovals[owner][spender] == 1); } /// @notice Internal version of the `createVault` function /// Mints `vaultID` and transfers it to `to` /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract /// @dev Emits a {Transfer} event function _mint(address to) internal returns (uint256 vaultID) { if (whitelistingActivated && (isWhitelisted[to] != 1 || isWhitelisted[msg.sender] != 1)) revert NotWhitelisted(); if (to == address(0)) revert ZeroAddress(); unchecked { vaultIDCount += 1; } vaultID = vaultIDCount; _beforeTokenTransfer(address(0), to, vaultID); unchecked { _balances[to] += 1; } _owners[vaultID] = to; emit Transfer(address(0), to, vaultID); if (!_checkOnERC721Received(address(0), to, vaultID, "")) revert NonERC721Receiver(); } /// @notice Destroys `vaultID` /// @dev `vaultID` must exist /// @dev Emits a {Transfer} event function _burn(uint256 vaultID) internal { address owner = _ownerOf(vaultID); _beforeTokenTransfer(owner, address(0), vaultID); // Clear approvals _approve(address(0), vaultID); // The following line cannot underflow as the owner's balance is necessarily // greater than 1 unchecked { _balances[owner] -= 1; } delete _owners[vaultID]; delete vaultData[vaultID]; emit Transfer(owner, address(0), vaultID); } /// @notice Transfers `vaultID` from `from` to `to` as opposed to {transferFrom}, /// this imposes no restrictions on msg.sender /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from` /// @dev Emits a {Transfer} event /// @dev A whitelist check is performed if necessary on the `to` address function _transfer( address from, address to, uint256 vaultID ) internal { if (_ownerOf(vaultID) != from) revert NotApproved(); if (to == address(0)) revert ZeroAddress(); if (whitelistingActivated && isWhitelisted[to] != 1) revert NotWhitelisted(); _beforeTokenTransfer(from, to, vaultID); // Clear approvals from the previous owner _approve(address(0), vaultID); unchecked { _balances[from] -= 1; _balances[to] += 1; } _owners[vaultID] = to; emit Transfer(from, to, vaultID); } /// @notice Approves `to` to operate on `vaultID` function _approve(address to, uint256 vaultID) internal { _vaultApprovals[vaultID] = to; emit Approval(_ownerOf(vaultID), to, vaultID); } /// @notice Internal version of the `setApprovalForAll` function /// @dev It contains an `approver` field to be used in case someone signs a permit for a particular /// address, and this signature is given to the contract by another address (like a router) function _setApprovalForAll( address approver, address operator, bool approved ) internal { if (operator == approver) revert ApprovalToCaller(); uint256 approval = approved ? 1 : 0; _operatorApprovals[approver][operator] = approval; emit ApprovalForAll(approver, operator, approved); } /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address /// The call is not executed if the target address is not a contract /// @param from Address representing the previous owner of the given token ID /// @param to Target address that will receive the tokens /// @param vaultID ID of the token to be transferred /// @param _data Bytes optional data to send along with the call /// @return Bool whether the call correctly returned the expected value function _checkOnERC721Received( address from, address to, uint256 vaultID, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, vaultID, _data) returns ( bytes4 retval ) { return retval == IERC721ReceiverUpgradeable.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert NonERC721Receiver(); } else { // solhint-disable-next-line no-inline-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /// @notice Hook that is called before any token transfer. This includes minting and burning. /// Calling conditions: /// /// - When `from` and `to` are both non-zero, `from`'s `vaultID` will be /// transferred to `to`. /// - When `from` is zero, `vaultID` will be minted for `to`. /// - When `to` is zero, `from`'s `vaultID` will be burned. /// - `from` and `to` are never both zero. function _beforeTokenTransfer( address from, address to, uint256 vaultID ) internal virtual {} }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.12; /// @title Interface for verifying contract-based account signatures /// @notice Interface that verifies provided signature for the data /// @dev Interface defined by EIP-1271 interface IERC1271 { /// @notice Returns whether the provided signature is valid for the provided data /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes. /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5). /// MUST allow external calls. /// @param hash Hash of the data to be signed /// @param signature Signature byte array associated with _data /// @return magicValue The bytes4 magic value 0x1626ba7e function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/IAgToken.sol"; import "../interfaces/IOracle.sol"; import "../interfaces/ISwapper.sol"; import "../interfaces/ITreasury.sol"; import "../interfaces/IVaultManager.sol"; import "../interfaces/governance/IVeBoostProxy.sol"; /// @title VaultManagerStorage /// @author Angle Labs, Inc. /// @dev Variables, references, parameters and events needed in the `VaultManager` contract // solhint-disable-next-line max-states-count contract VaultManagerStorage is IVaultManagerStorage, Initializable, ReentrancyGuardUpgradeable { /// @notice Base used for parameter computation: almost all the parameters of this contract are set in `BASE_PARAMS` uint256 public constant BASE_PARAMS = 10**9; /// @notice Base used for interest rate computation uint256 public constant BASE_INTEREST = 10**27; /// @notice Used for interest rate computation uint256 public constant HALF_BASE_INTEREST = 10**27 / 2; // ================================= REFERENCES ================================ /// @inheritdoc IVaultManagerStorage ITreasury public treasury; /// @inheritdoc IVaultManagerStorage IERC20 public collateral; /// @inheritdoc IVaultManagerStorage IAgToken public stablecoin; /// @inheritdoc IVaultManagerStorage IOracle public oracle; /// @notice Reference to the contract which computes adjusted veANGLE balances for liquidators boosts IVeBoostProxy public veBoostProxy; /// @notice Base of the collateral uint256 internal _collatBase; // ================================= PARAMETERS ================================ // Unless specified otherwise, parameters of this contract are expressed in `BASE_PARAMS` /// @notice Maximum amount of stablecoins that can be issued with this contract (in `BASE_TOKENS`). This parameter should /// not be bigger than `type(uint256).max / BASE_INTEREST` otherwise there may be some overflows in the `increaseDebt` function uint256 public debtCeiling; /// @notice Threshold veANGLE balance values for the computation of the boost for liquidators: the length of this array /// should normally be 2. The base of the x-values in this array should be `BASE_TOKENS` uint256[] public xLiquidationBoost; /// @notice Values of the liquidation boost at the threshold values of x uint256[] public yLiquidationBoost; /// @inheritdoc IVaultManagerStorage uint64 public collateralFactor; /// @notice Maximum Health factor at which a vault can end up after a liquidation (unless it's fully liquidated) uint64 public targetHealthFactor; /// @notice Upfront fee taken when borrowing stablecoins: this fee is optional and should in practice not be used uint64 public borrowFee; /// @notice Upfront fee taken when repaying stablecoins: this fee is optional as well. It should be smaller /// than the liquidation surcharge (cf below) to avoid exploits where people voluntarily get liquidated at a 0 /// discount to pay smaller repaying fees uint64 public repayFee; /// @notice Per second interest taken to borrowers taking agToken loans. Contrarily to other parameters, it is set in `BASE_INTEREST` /// that is to say in base 10**27 uint64 public interestRate; /// @notice Fee taken by the protocol during a liquidation. Technically, this value is not the fee per se, it's 1 - fee. /// For instance for a 2% fee, `liquidationSurcharge` should be 98% uint64 public liquidationSurcharge; /// @notice Maximum discount given to liquidators uint64 public maxLiquidationDiscount; /// @notice Whether whitelisting is required to own a vault or not bool public whitelistingActivated; /// @notice Whether the contract is paused or not bool public paused; // ================================= VARIABLES ================================= /// @notice Timestamp at which the `interestAccumulator` was updated uint256 public lastInterestAccumulatorUpdated; /// @inheritdoc IVaultManagerStorage uint256 public interestAccumulator; /// @inheritdoc IVaultManagerStorage uint256 public totalNormalizedDebt; /// @notice Surplus accumulated by the contract: surplus is always in stablecoins, and is then reset /// when the value is communicated to the treasury contract uint256 public surplus; /// @notice Bad debt made from liquidated vaults which ended up having no collateral and a positive amount /// of stablecoins uint256 public badDebt; // ================================== MAPPINGS ================================= /// @inheritdoc IVaultManagerStorage mapping(uint256 => Vault) public vaultData; /// @notice Maps an address to 1 if it's whitelisted and can open or own a vault mapping(address => uint256) public isWhitelisted; // ================================ ERC721 DATA ================================ /// @inheritdoc IVaultManagerStorage uint256 public vaultIDCount; /// @notice URI string internal _baseURI; // Mapping from `vaultID` to owner address mapping(uint256 => address) internal _owners; // Mapping from owner address to vault owned count mapping(address => uint256) internal _balances; // Mapping from `vaultID` to approved address mapping(uint256 => address) internal _vaultApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => uint256)) internal _operatorApprovals; uint256[50] private __gap; // =================================== EVENTS ================================== event AccruedToTreasury(uint256 surplusEndValue, uint256 badDebtEndValue); event CollateralAmountUpdated(uint256 vaultID, uint256 collateralAmount, uint8 isIncrease); event InterestAccumulatorUpdated(uint256 value, uint256 timestamp); event InternalDebtUpdated(uint256 vaultID, uint256 internalAmount, uint8 isIncrease); event FiledUint64(uint64 param, bytes32 what); event DebtCeilingUpdated(uint256 debtCeiling); event LiquidationBoostParametersUpdated(address indexed _veBoostProxy, uint256[] xBoost, uint256[] yBoost); event LiquidatedVaults(uint256[] vaultIDs); event DebtTransferred(uint256 srcVaultID, uint256 dstVaultID, address dstVaultManager, uint256 amount); // =================================== ERRORS ================================== error ApprovalToOwner(); error ApprovalToCaller(); error DustyLeftoverAmount(); error DebtCeilingExceeded(); error HealthyVault(); error IncompatibleLengths(); error InsolventVault(); error InvalidParameterValue(); error InvalidParameterType(); error InvalidSetOfParameters(); error InvalidTreasury(); error NonERC721Receiver(); error NonexistentVault(); error NotApproved(); error NotGovernor(); error NotGovernorOrGuardian(); error NotTreasury(); error NotWhitelisted(); error NotVaultManager(); error Paused(); error TooHighParameterValue(); error TooSmallParameterValue(); error ZeroAddress(); /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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 IERC20PermitUpgradeable { /** * @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 // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
// 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 IERC165Upgradeable { /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== * * [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://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @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 v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// 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.6.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.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /// @title IAgToken /// @author Angle Labs, Inc. /// @notice Interface for the stablecoins `AgToken` contracts /// @dev This interface only contains functions of the `AgToken` contract which are called by other contracts /// of this module or of the first module of the Angle Protocol interface IAgToken is IERC20Upgradeable { // ======================= Minter Role Only Functions =========================== /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens /// @param account Address to mint to /// @param amount Amount to mint /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts /// whitelisted by governance function mint(address account, uint256 amount) external; /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender` /// @param amount Amount of tokens to burn /// @param burner Address to burn from /// @param sender Address which requested the burn from `burner` /// @dev This method is to be called by a contract with the minter right after being requested /// to do so by a `sender` address willing to burn tokens from another `burner` address /// @dev The method checks the allowance between the `sender` and the `burner` function burnFrom( uint256 amount, address burner, address sender ) external; /// @notice Burns `amount` tokens from a `burner` address /// @param amount Amount of tokens to burn /// @param burner Address to burn from /// @dev This method is to be called by a contract with a minter right on the AgToken after being /// requested to do so by an address willing to burn tokens from its address function burnSelf(uint256 amount, address burner) external; // ========================= Treasury Only Functions =========================== /// @notice Adds a minter in the contract /// @param minter Minter address to add /// @dev Zero address checks are performed directly in the `Treasury` contract function addMinter(address minter) external; /// @notice Removes a minter from the contract /// @param minter Minter address to remove /// @dev This function can also be called by a minter wishing to revoke itself function removeMinter(address minter) external; /// @notice Sets a new treasury contract /// @param _treasury New treasury address function setTreasury(address _treasury) external; // ========================= External functions ================================ /// @notice Checks whether an address has the right to mint agTokens /// @param minter Address for which the minting right should be checked /// @return Whether the address has the right to mint agTokens or not function isMinter(address minter) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./ITreasury.sol"; /// @title IOracle /// @author Angle Labs, Inc. /// @notice Interface for the `Oracle` contract /// @dev This interface only contains functions of the contract which are called by other contracts /// of this module interface IOracle { /// @notice Reads the rate from the Chainlink circuit and other data provided /// @return quoteAmount The current rate between the in-currency and out-currency in the base /// of the out currency /// @dev For instance if the out currency is EUR (and hence agEUR), then the base of the returned /// value is 10**18 function read() external view returns (uint256); /// @notice Changes the treasury contract /// @param _treasury Address of the new treasury contract /// @dev This function can be called by an approved `VaultManager` contract which can call /// this function after being requested to do so by a `treasury` contract /// @dev In some situations (like reactor contracts), the `VaultManager` may not directly be linked /// to the `oracle` contract and as such we may need governors to be able to call this function as well function setTreasury(address _treasury) external; /// @notice Reference to the `treasury` contract handling this `VaultManager` function treasury() external view returns (ITreasury treasury); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title ISwapper /// @author Angle Labs, Inc. /// @notice Interface for Swapper contracts /// @dev This interface defines the key functions `Swapper` contracts should have when interacting with /// Angle interface ISwapper { /// @notice Notifies a contract that an address should be given `outToken` from `inToken` /// @param inToken Address of the token received /// @param outToken Address of the token to obtain /// @param outTokenRecipient Address to which the outToken should be sent /// @param outTokenOwed Minimum amount of outToken the `outTokenRecipient` address should have at the end of the call /// @param inTokenObtained Amount of collateral obtained by a related address prior /// to the call to this function /// @param data Extra data needed (to encode Uniswap swaps for instance) function swap( IERC20 inToken, IERC20 outToken, address outTokenRecipient, uint256 outTokenOwed, uint256 inTokenObtained, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./IAgToken.sol"; import "./ICoreBorrow.sol"; import "./IFlashAngle.sol"; /// @title ITreasury /// @author Angle Labs, Inc. /// @notice Interface for the `Treasury` contract /// @dev This interface only contains functions of the `Treasury` which are called by other contracts /// of this module interface ITreasury { /// @notice Stablecoin handled by this `treasury` contract function stablecoin() external view returns (IAgToken); /// @notice Checks whether a given address has the governor role /// @param admin Address to check /// @return Whether the address has the governor role /// @dev Access control is only kept in the `CoreBorrow` contract function isGovernor(address admin) external view returns (bool); /// @notice Checks whether a given address has the guardian or the governor role /// @param admin Address to check /// @return Whether the address has the guardian or the governor role /// @dev Access control is only kept in the `CoreBorrow` contract which means that this function /// queries the `CoreBorrow` contract function isGovernorOrGuardian(address admin) external view returns (bool); /// @notice Checks whether a given address has well been initialized in this contract /// as a `VaultManager` /// @param _vaultManager Address to check /// @return Whether the address has been initialized or not function isVaultManager(address _vaultManager) external view returns (bool); /// @notice Sets a new flash loan module for this stablecoin /// @param _flashLoanModule Reference to the new flash loan module /// @dev This function removes the minting right to the old flash loan module and grants /// it to the new module function setFlashLoanModule(address _flashLoanModule) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./ITreasury.sol"; import "./IOracle.sol"; // ========================= Key Structs and Enums ============================= /// @notice Parameters associated to a given `VaultManager` contract: these all correspond /// to parameters which signification is detailed in the `VaultManagerStorage` file struct VaultParameters { uint256 debtCeiling; uint64 collateralFactor; uint64 targetHealthFactor; uint64 interestRate; uint64 liquidationSurcharge; uint64 maxLiquidationDiscount; bool whitelistingActivated; uint256 baseBoost; } /// @notice Data stored to track someone's loan (or equivalently called position) struct Vault { // Amount of collateral deposited in the vault, in collateral decimals. For example, if the collateral // is USDC with 6 decimals, then `collateralAmount` will be in base 10**6 uint256 collateralAmount; // Normalized value of the debt (that is to say of the stablecoins borrowed). It is expressed // in the base of Angle stablecoins (i.e. `BASE_TOKENS = 10**18`) uint256 normalizedDebt; } /// @notice For a given `vaultID`, this encodes a liquidation opportunity that is to say details about the maximum /// amount that could be repaid by liquidating the position /// @dev All the values are null in the case of a vault which cannot be liquidated under these conditions struct LiquidationOpportunity { // Maximum stablecoin amount that can be repaid upon liquidating the vault uint256 maxStablecoinAmountToRepay; // Collateral amount given to the person in the case where the maximum amount to repay is given uint256 maxCollateralAmountGiven; // Threshold value of stablecoin amount to repay: it is ok for a liquidator to repay below threshold, // but if this threshold is non null and the liquidator wants to repay more than threshold, it should repay // the max stablecoin amount given in this vault uint256 thresholdRepayAmount; // Discount proposed to the liquidator on the collateral uint256 discount; // Amount of debt in the vault uint256 currentDebt; } /// @notice Data stored during a liquidation process to keep in memory what's due to a liquidator and some /// essential data for vaults being liquidated struct LiquidatorData { // Current amount of stablecoins the liquidator should give to the contract uint256 stablecoinAmountToReceive; // Current amount of collateral the contract should give to the liquidator uint256 collateralAmountToGive; // Bad debt accrued across the liquidation process uint256 badDebtFromLiquidation; // Oracle value (in stablecoin base) at the time of the liquidation uint256 oracleValue; // Value of the `interestAccumulator` at the time of the call uint256 newInterestAccumulator; } /// @notice Data to track during a series of action the amount to give or receive in stablecoins and collateral /// to the caller or associated addresses struct PaymentData { // Stablecoin amount the contract should give uint256 stablecoinAmountToGive; // Stablecoin amount owed to the contract uint256 stablecoinAmountToReceive; // Collateral amount the contract should give uint256 collateralAmountToGive; // Collateral amount owed to the contract uint256 collateralAmountToReceive; } /// @notice Actions possible when composing calls to the different entry functions proposed enum ActionType { createVault, closeVault, addCollateral, removeCollateral, repayDebt, borrow, getDebtIn, permit } // ========================= Interfaces ============================= /// @title IVaultManagerFunctions /// @author Angle Labs, Inc. /// @notice Interface for the `VaultManager` contract /// @dev This interface only contains functions of the contract which are called by other contracts /// of this module (without getters) interface IVaultManagerFunctions { /// @notice Accrues interest accumulated across all vaults to the surplus and sends the surplus to the treasury /// @return surplusValue Value of the surplus communicated to the `Treasury` /// @return badDebtValue Value of the bad debt communicated to the `Treasury` /// @dev `surplus` and `badDebt` should be reset to 0 once their current value have been given to the `treasury` contract function accrueInterestToTreasury() external returns (uint256 surplusValue, uint256 badDebtValue); /// @notice Removes debt from a vault after being requested to do so by another `VaultManager` contract /// @param vaultID ID of the vault to remove debt from /// @param amountStablecoins Amount of stablecoins to remove from the debt: this amount is to be converted to an /// internal debt amount /// @param senderBorrowFee Borrowing fees from the contract which requested this: this is to make sure that people are not /// arbitraging difference in minting fees /// @param senderRepayFee Repay fees from the contract which requested this: this is to make sure that people are not arbitraging /// differences in repay fees /// @dev This function can only be called from a vaultManager registered in the same Treasury function getDebtOut( uint256 vaultID, uint256 amountStablecoins, uint256 senderBorrowFee, uint256 senderRepayFee ) external; /// @notice Gets the current debt of a vault /// @param vaultID ID of the vault to check /// @return Debt of the vault function getVaultDebt(uint256 vaultID) external view returns (uint256); /// @notice Gets the total debt across all vaults /// @return Total debt across all vaults, taking into account the interest accumulated /// over time function getTotalDebt() external view returns (uint256); /// @notice Sets the treasury contract /// @param _treasury New treasury contract /// @dev All required checks when setting up a treasury contract are performed in the contract /// calling this function function setTreasury(address _treasury) external; /// @notice Creates a vault /// @param toVault Address for which the va /// @return vaultID ID of the vault created /// @dev This function just creates the vault without doing any collateral or function createVault(address toVault) external returns (uint256); /// @notice Allows composability between calls to the different entry points of this module. Any user calling /// this function can perform any of the allowed actions in the order of their choice /// @param actions Set of actions to perform /// @param datas Data to be decoded for each action: it can include like the `vaultID` or the `stablecoinAmount` to borrow /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. This address /// should either be the `msg.sender` or be approved by the latter /// @param to Address to which stablecoins and/or collateral will be sent in case of /// @param who Address of the contract to handle in case of repayment of stablecoins from received collateral /// @param repayData Data to pass to the repayment contract in case of /// @return paymentData Struct containing the accounting changes from the protocol's perspective (like how much of collateral /// or how much has been received). Note that the values in the struct are not aggregated and you could have in the output /// a positive amount of stablecoins to receive as well as a positive amount of stablecoins to give /// @dev This function is optimized to reduce gas cost due to payment from or to the user and that expensive calls /// or computations (like `oracleValue`) are done only once /// @dev When specifying `vaultID` in `data`, it is important to know that if you specify `vaultID = 0`, it will simply /// use the latest `vaultID`. This is the default behavior, and unless you're engaging into some complex protocol actions /// it is encouraged to use `vaultID = 0` only when the first action of the batch is `createVault` function angle( ActionType[] memory actions, bytes[] memory datas, address from, address to, address who, bytes memory repayData ) external returns (PaymentData memory paymentData); /// @notice This function is a wrapper built on top of the function above. It enables users to interact with the contract /// without having to provide `who` and `repayData` parameters function angle( ActionType[] memory actions, bytes[] memory datas, address from, address to ) external returns (PaymentData memory paymentData); /// @notice Initializes the `VaultManager` contract /// @param _treasury Treasury address handling the contract /// @param _collateral Collateral supported by this contract /// @param _oracle Oracle contract used /// @param _symbol Symbol used to define the `VaultManager` name and symbol /// @dev The parameters and the oracle are the only elements which could be modified once the /// contract has been initialized /// @dev For the contract to be fully initialized, governance needs to set the parameters for the liquidation /// boost function initialize( ITreasury _treasury, IERC20 _collateral, IOracle _oracle, VaultParameters calldata params, string memory _symbol ) external; /// @notice Minimum amount of debt a vault can have, expressed in `BASE_TOKENS` that is to say the base of the agTokens function dust() external view returns (uint256); } /// @title IVaultManagerStorage /// @author Angle Labs, Inc. /// @notice Interface for the `VaultManager` contract /// @dev This interface contains getters of the contract's public variables used by other contracts /// of this module interface IVaultManagerStorage { /// @notice Encodes the maximum ratio stablecoin/collateral a vault can have before being liquidated. It's what /// determines the minimum collateral ratio of a position function collateralFactor() external view returns (uint64); /// @notice Stablecoin handled by this contract. Another `VaultManager` contract could have /// the same rights as this `VaultManager` on the stablecoin contract function stablecoin() external view returns (IAgToken); /// @notice Reference to the `treasury` contract handling this `VaultManager` function treasury() external view returns (ITreasury); /// @notice Oracle contract to get access to the price of the collateral with respect to the stablecoin function oracle() external view returns (IOracle); /// @notice The `interestAccumulator` variable keeps track of the interest that should accrue to the protocol. /// The stored value is not necessarily the true value: this one is recomputed every time an action takes place /// within the protocol. It is in base `BASE_INTEREST` function interestAccumulator() external view returns (uint256); /// @notice Reference to the collateral handled by this `VaultManager` function collateral() external view returns (IERC20); /// @notice Total normalized amount of stablecoins borrowed, not taking into account the potential bad debt accumulated /// This value is expressed in the base of Angle stablecoins (`BASE_TOKENS = 10**18`) function totalNormalizedDebt() external view returns (uint256); /// @notice Maximum amount of stablecoins that can be issued with this contract. It is expressed in `BASE_TOKENS` function debtCeiling() external view returns (uint256); /// @notice Maps a `vaultID` to its data (namely collateral amount and normalized debt) function vaultData(uint256 vaultID) external view returns (uint256 collateralAmount, uint256 normalizedDebt); /// @notice ID of the last vault created. The `vaultIDCount` variables serves as a counter to generate a unique /// `vaultID` for each vault: it is like `tokenID` in basic ERC721 contracts function vaultIDCount() external view returns (uint256); } /// @title IVaultManager /// @author Angle Labs, Inc. /// @notice Interface for the `VaultManager` contract interface IVaultManager is IVaultManagerFunctions, IVaultManagerStorage, IERC721Metadata { function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool); } /// @title IVaultManagerListing /// @author Angle Labs, Inc. /// @notice Interface for the `VaultManagerListing` contract interface IVaultManagerListing is IVaultManager { /// @notice Get the collateral owned by `user` in the contract /// @dev This function effectively sums the collateral amounts of all the vaults owned by `user` function getUserCollateral(address user) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /// @title IVeBoostProxy /// @author Angle Labs, Inc. /// @notice Interface for the `VeBoostProxy` contract /// @dev This interface only contains functions of the contract which are called by other contracts /// of this module /// @dev The `veBoostProxy` contract used by Angle is a full fork of Curve Finance implementation interface IVeBoostProxy { /// @notice Reads the adjusted veANGLE balance of an address (adjusted by delegation) //solhint-disable-next-line function adjusted_balance_of(address) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721MetadataUpgradeable is IERC721Upgradeable { /** * @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 (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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 (token/ERC20/extensions/draft-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 // OpenZeppelin Contracts (last updated v4.7.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 * ==== * * [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://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @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.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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: GPL-3.0 pragma solidity ^0.8.12; /// @title ICoreBorrow /// @author Angle Labs, Inc. /// @notice Interface for the `CoreBorrow` contract /// @dev This interface only contains functions of the `CoreBorrow` contract which are called by other contracts /// of this module interface ICoreBorrow { /// @notice Checks if an address corresponds to a treasury of a stablecoin with a flash loan /// module initialized on it /// @param treasury Address to check /// @return Whether the address has the `FLASHLOANER_TREASURY_ROLE` or not function isFlashLoanerTreasury(address treasury) external view returns (bool); /// @notice Checks whether an address is governor of the Angle Protocol or not /// @param admin Address to check /// @return Whether the address has the `GOVERNOR_ROLE` or not function isGovernor(address admin) external view returns (bool); /// @notice Checks whether an address is governor or a guardian of the Angle Protocol or not /// @param admin Address to check /// @return Whether the address has the `GUARDIAN_ROLE` or not /// @dev Governance should make sure when adding a governor to also give this governor the guardian /// role by calling the `addGovernor` function function isGovernorOrGuardian(address admin) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./IAgToken.sol"; import "./ICoreBorrow.sol"; /// @title IFlashAngle /// @author Angle Labs, Inc. /// @notice Interface for the `FlashAngle` contract /// @dev This interface only contains functions of the contract which are called by other contracts /// of this module interface IFlashAngle { /// @notice Reference to the `CoreBorrow` contract managing the FlashLoan module function core() external view returns (ICoreBorrow); /// @notice Sends the fees taken from flash loans to the treasury contract associated to the stablecoin /// @param stablecoin Stablecoin from which profits should be sent /// @return balance Amount of profits sent /// @dev This function can only be called by the treasury contract function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance); /// @notice Adds support for a stablecoin /// @param _treasury Treasury associated to the stablecoin to add support for /// @dev This function can only be called by the `CoreBorrow` contract function addStablecoinSupport(address _treasury) external; /// @notice Removes support for a stablecoin /// @param _treasury Treasury associated to the stablecoin to remove support for /// @dev This function can only be called by the `CoreBorrow` contract function removeStablecoinSupport(address _treasury) external; /// @notice Sets a new core contract /// @param _core Core contract address to set /// @dev This function can only be called by the `CoreBorrow` contract function setCore(address _core) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721Metadata.sol";
// 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 (last updated v4.7.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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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); }
{ "optimizer": { "enabled": true, "runs": 1 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"ApprovalToCaller","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"DebtCeilingExceeded","type":"error"},{"inputs":[],"name":"DustyLeftoverAmount","type":"error"},{"inputs":[],"name":"ExpiredDeadline","type":"error"},{"inputs":[],"name":"HealthyVault","type":"error"},{"inputs":[],"name":"IncompatibleLengths","type":"error"},{"inputs":[],"name":"InsolventVault","type":"error"},{"inputs":[],"name":"InvalidParameterType","type":"error"},{"inputs":[],"name":"InvalidParameterValue","type":"error"},{"inputs":[],"name":"InvalidSetOfParameters","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTreasury","type":"error"},{"inputs":[],"name":"NonERC721Receiver","type":"error"},{"inputs":[],"name":"NonexistentVault","type":"error"},{"inputs":[],"name":"NotApproved","type":"error"},{"inputs":[],"name":"NotGovernor","type":"error"},{"inputs":[],"name":"NotGovernorOrGuardian","type":"error"},{"inputs":[],"name":"NotTreasury","type":"error"},{"inputs":[],"name":"NotVaultManager","type":"error"},{"inputs":[],"name":"NotWhitelisted","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"TooHighParameterValue","type":"error"},{"inputs":[],"name":"TooSmallParameterValue","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"surplusEndValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"badDebtEndValue","type":"uint256"}],"name":"AccruedToTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"isIncrease","type":"uint8"}],"name":"CollateralAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtCeiling","type":"uint256"}],"name":"DebtCeilingUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"srcVaultID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dstVaultID","type":"uint256"},{"indexed":false,"internalType":"address","name":"dstVaultManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DebtTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"param","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"what","type":"bytes32"}],"name":"FiledUint64","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"InterestAccumulatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"internalAmount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"isIncrease","type":"uint8"}],"name":"InternalDebtUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"vaultIDs","type":"uint256[]"}],"name":"LiquidatedVaults","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_veBoostProxy","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"xBoost","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"yBoost","type":"uint256[]"}],"name":"LiquidationBoostParametersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BASE_INTEREST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_PARAMS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HALF_BASE_INTEREST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterestToTreasury","outputs":[{"internalType":"uint256","name":"surplusValue","type":"uint256"},{"internalType":"uint256","name":"badDebtValue","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ActionType[]","name":"actions","type":"uint8[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"angle","outputs":[{"components":[{"internalType":"uint256","name":"stablecoinAmountToGive","type":"uint256"},{"internalType":"uint256","name":"stablecoinAmountToReceive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToGive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToReceive","type":"uint256"}],"internalType":"struct PaymentData","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ActionType[]","name":"actions","type":"uint8[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes","name":"repayData","type":"bytes"}],"name":"angle","outputs":[{"components":[{"internalType":"uint256","name":"stablecoinAmountToGive","type":"uint256"},{"internalType":"uint256","name":"stablecoinAmountToReceive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToGive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToReceive","type":"uint256"}],"internalType":"struct PaymentData","name":"paymentData","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"badDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"},{"internalType":"address","name":"liquidator","type":"address"}],"name":"checkLiquidation","outputs":[{"components":[{"internalType":"uint256","name":"maxStablecoinAmountToRepay","type":"uint256"},{"internalType":"uint256","name":"maxCollateralAmountGiven","type":"uint256"},{"internalType":"uint256","name":"thresholdRepayAmount","type":"uint256"},{"internalType":"uint256","name":"discount","type":"uint256"},{"internalType":"uint256","name":"currentDebt","type":"uint256"}],"internalType":"struct LiquidationOpportunity","name":"liqOpp","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralFactor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"toVault","type":"address"}],"name":"createVault","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtCeiling","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dust","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"},{"internalType":"uint256","name":"stablecoinAmount","type":"uint256"},{"internalType":"uint256","name":"senderBorrowFee","type":"uint256"},{"internalType":"uint256","name":"senderRepayFee","type":"uint256"}],"name":"getDebtOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getTotalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"getVaultDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITreasury","name":"_treasury","type":"address"},{"internalType":"contract IERC20","name":"_collateral","type":"address"},{"internalType":"contract IOracle","name":"_oracle","type":"address"},{"components":[{"internalType":"uint256","name":"debtCeiling","type":"uint256"},{"internalType":"uint64","name":"collateralFactor","type":"uint64"},{"internalType":"uint64","name":"targetHealthFactor","type":"uint64"},{"internalType":"uint64","name":"interestRate","type":"uint64"},{"internalType":"uint64","name":"liquidationSurcharge","type":"uint64"},{"internalType":"uint64","name":"maxLiquidationDiscount","type":"uint64"},{"internalType":"bool","name":"whitelistingActivated","type":"bool"},{"internalType":"uint256","name":"baseBoost","type":"uint256"}],"internalType":"struct VaultParameters","name":"params","type":"tuple"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestAccumulator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRate","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastInterestAccumulatorUpdated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"vaultIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"liquidate","outputs":[{"components":[{"internalType":"uint256","name":"stablecoinAmountToReceive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToGive","type":"uint256"},{"internalType":"uint256","name":"badDebtFromLiquidation","type":"uint256"},{"internalType":"uint256","name":"oracleValue","type":"uint256"},{"internalType":"uint256","name":"newInterestAccumulator","type":"uint256"}],"internalType":"struct LiquidatorData","name":"liqData","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"vaultIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"liquidate","outputs":[{"components":[{"internalType":"uint256","name":"stablecoinAmountToReceive","type":"uint256"},{"internalType":"uint256","name":"collateralAmountToGive","type":"uint256"},{"internalType":"uint256","name":"badDebtFromLiquidation","type":"uint256"},{"internalType":"uint256","name":"oracleValue","type":"uint256"},{"internalType":"uint256","name":"newInterestAccumulator","type":"uint256"}],"internalType":"struct LiquidatorData","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationSurcharge","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidationDiscount","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"vaultID","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtCeiling","type":"uint256"}],"name":"setDebtCeiling","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dust","type":"uint256"},{"internalType":"uint256","name":"dustCollateral_","type":"uint256"}],"name":"setDusts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_veBoostProxy","type":"address"},{"internalType":"uint256[]","name":"xBoost","type":"uint256[]"},{"internalType":"uint256[]","name":"yBoost","type":"uint256[]"}],"name":"setLiquidationBoostParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"param","type":"uint64"},{"internalType":"bytes32","name":"what","type":"bytes32"}],"name":"setUint64","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stablecoin","outputs":[{"internalType":"contract IAgToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"surplus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"targetHealthFactor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"togglePause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"toggleWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalNormalizedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"vaultID","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ITreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vaultData","outputs":[{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"normalizedDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultIDCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veBoostProxy","outputs":[{"internalType":"contract IVeBoostProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistingActivated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xLiquidationBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yLiquidationBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50600054610100900460ff1615808015620000335750600054600160ff909116105b8062000063575062000050306200013d60201b620033591760201c565b15801562000063575060005460ff166001145b620000cb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b6000805460ff191660011790558015620000ef576000805461ff0019166101001790555b801562000136576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b506200014c565b6001600160a01b03163b151590565b615f2c806200015c6000396000f3fe608060405234801561001057600080fd5b50600436106102f65760003560e01c8063010db195146102fb57806301ffc9a71461032457806306fdde0314610347578063081812fc1461035c578063087a60071461036f578063095ea7b3146103865780630e198f221461039b57806313888565146103a457806323b872dd146103ad578063254cf439146103c0578063307439af146103f257806334ce998a1461041257806335836f151461041a5780633644e5151461042d57806339393ac91461043557806339eb4dc6146104485780633ae2325f1461045c5780633af32abf1461046f5780633c2e941b1461048f57806342842e0e14610498578063430c2081146104ab5780634f7e43df146104be57806355f804b3146104d85780635b84d88a146104eb5780635c975abb146104fe57806361d027b3146105125780636352211e1461052557806370a0823114610538578063741075431461054b5780637aacfffa1461055e5780637adbf9731461059a5780637c0f59f4146105ad5780637c3a00fd146105c75780637dc0d1d0146105da5780637e53bd97146105ed5780637e56d47c146106005780637ecebe0014610613578063835986b41461063c57806389050f1d1461064f57806395d89b41146106615780639a3b6f2f146106695780639f48118f146106af578063a22cb465146106ba578063af2c8c2e146106cd578063b1511cc9146106d6578063b4bd6f46146106e9578063b88d4fde146106fc578063bbcac5571461070f578063c4ae316814610718578063c66d8b0114610720578063c87b56dd1461073a578063d8dfeb451461074d578063d9b1cb5b14610760578063de1f776514610773578063de8fc69814610785578063df011c4114610798578063e182b883146107ab578063e1c84ea4146107be578063e626648a146107c7578063e985e9c5146107e1578063e9cbd822146107f4578063f0f4426014610807578063f51cc7dd1461081a578063fad9aba31461082d578063fc29b02114610836578063fd527cf814610849575b600080fd5b60375461030e906001600160a01b031681565b60405161031b9190614ee0565b60405180910390f35b610337610332366004614f0a565b610851565b604051901515815260200161031b565b61034f6108be565b60405161031b9190614f7f565b61030e61036a366004614f92565b61094c565b610378603f5481565b60405190815260200161031b565b610399610394366004614fc0565b61097d565b005b610378603e5481565b61037860415481565b6103996103bb366004614fec565b610a0a565b603c546103da90600160401b90046001600160401b031681565b6040516001600160401b03909116815260200161031b565b61040561040036600461502d565b610a45565b60405161031b919061505d565b610378610af7565b610378610428366004614f92565b610b29565b610378610b65565b610399610443366004615096565b610b6f565b603d5461033790600160c01b900460ff1681565b61037861046a366004614f92565b610c6f565b61037861047d366004615096565b60446020526000908152604090205481565b61037860455481565b6103996104a6366004614fec565b610c90565b6103376104b9366004614fc0565b610cab565b603d546103da90600160801b90046001600160401b031681565b6103996104e6366004615168565b610cb7565b6103996104f936600461519c565b610d5c565b603d5461033790600160c81b900460ff1681565b60335461030e906001600160a01b031681565b61030e610533366004614f92565b610df5565b610378610546366004615096565b610e00565b6103996105593660046151d5565b610e45565b61058561056c366004614f92565b6043602052600090815260409020805460019091015482565b6040805192835260208301919091520161031b565b6103996105a8366004615096565b611211565b603c546103da90600160c01b90046001600160401b031681565b603d546103da906001600160401b031681565b60365461030e906001600160a01b031681565b6103996105fb36600461527f565b611358565b61040561060e3660046152f4565b611549565b610378610621366004615096565b6001600160a01b03166000908152607f602052604090205490565b61039961064a3660046153b8565b611af6565b610378676765c793fa10079d601a1b81565b61034f611cae565b61067c6106773660046154d2565b611cbb565b60405161031b91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b610378633b9aca0081565b6103996106c8366004615568565b611cf0565b61037860405481565b6103996106e4366004614f92565b611cfb565b6103786106f7366004615096565b611dc4565b61039961070a366004615596565b611e00565b61037860425481565b610399611e3d565b603d546103da90600160401b90046001600160401b031681565b61034f610748366004614f92565b611eec565b60345461030e906001600160a01b031681565b61039961076e366004615601565b612041565b610378676765c793fa10079d601b1b81565b61067c610793366004615695565b6125ec565b603c546103da906001600160401b031681565b6103786107b9366004614f92565b612e73565b61037860395481565b603c546103da90600160801b90046001600160401b031681565b6103376107ef3660046156f3565b612e83565b60355461030e906001600160a01b031681565b610399610815366004615096565b612eb1565b610399610828366004615730565b612f51565b61037860b45481565b6104056108443660046157aa565b613210565b61058561323a565b60006001600160e01b03198216635b5e139f60e01b148061088257506001600160e01b031982166380ac58cd60e01b145b8061089d57506001600160e01b0319821663430c208160e01b145b806108b857506001600160e01b031982166301ffc9a760e01b145b92915050565b607d80546108cb90615806565b80601f01602080910402602001604051908101604052809291908181526020018280546108f790615806565b80156109445780601f1061091957610100808354040283529160200191610944565b820191906000526020600020905b81548152906001019060200180831161092757829003601f168201915b505050505081565b600061095782613368565b6109745760405163062a39dd60e11b815260040160405180910390fd5b6108b882613385565b6000610988826133a0565b9050806001600160a01b0316836001600160a01b031614156109bd576040516349fa8bc360e11b815260040160405180910390fd5b336001600160a01b038216148015906109dd57506109db8133612e83565b155b156109fb5760405163c19f17a960e01b815260040160405180910390fd5b610a0583836133d6565b505050565b3381610a168282613444565b610a335760405163c19f17a960e01b815260040160405180910390fd5b610a3e8585856134c2565b5050505050565b610a4d614db6565b60008381526043602090815260409182902082518084018452815481526001909101548183015260365483516315f789a960e21b81529351610af094929387936001600160a01b03909316926357de26a492600480830193928290030181865afa158015610abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae3919061583b565b610aeb6135e9565b61377e565b9392505050565b6000676765c793fa10079d601b1b610b0d6135e9565b604054610b1a919061586a565b610b24919061589f565b905090565b6000676765c793fa10079d601b1b610b3f6135e9565b600084815260436020526040902060010154610b5b919061586a565b6108b8919061589f565b6000610b24613ad0565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610b9f903390600401614ee0565b602060405180830381865afa158015610bbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be091906158b3565b610bfd57604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b03811615610c4c576001600160a01b038116600090815260446020526040902054610c309060016158d0565b6001600160a01b03821660009081526044602052604090205550565b603d805460ff60c01b198116600160c01b9182900460ff16159091021790555b50565b603b8181548110610c7f57600080fd5b600091825260209091200154905081565b610a0583838360405180602001604052806000815250611e00565b6000610af08383613444565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610ce7903390600401614ee0565b602060405180830381865afa158015610d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2891906158b3565b610d4557604051632678482f60e21b815260040160405180910390fd5b8051610d58906046906020840190614de5565b5050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610d8c903390600401614ee0565b602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906158b3565b610dea57604051633b8d9d7560e21b815260040160405180910390fd5b60b49190915560b555565b60006108b8826133a0565b60006001600160a01b038216610e295760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b031660009081526048602052604090205490565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610e75903390600401614ee0565b602060405180830381865afa158015610e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb691906158b3565b610ed357604051632678482f60e21b815260040160405180910390fd5b806121a360f11b1415610f3757603d546001600160401b03600160401b90910481169083161115610f1757604051637650e96360e11b815260040160405180910390fd5b603c80546001600160401b0319166001600160401b0384161790556111ca565b80622a242360e91b1415610f9c57633b9aca00826001600160401b03161015610f735760405163da6a17b960e01b815260040160405180910390fd5b603c8054600160401b600160801b031916600160401b6001600160401b038516021790556111ca565b8061212360f11b141561100057633b9aca00826001600160401b03161115610fd757604051637650e96360e11b815260040160405180910390fd5b603c8054600160801b600160c01b031916600160801b6001600160401b038516021790556111ca565b8061292360f11b141561107d57603d54633b9aca009061103090600160401b90046001600160401b0316846158e7565b6001600160401b0316111561105857604051637650e96360e11b815260040160405180910390fd5b603c80546001600160c01b0316600160c01b6001600160401b038516021790556111ca565b806124a960f11b14156110b357611092613b3c565b50603d80546001600160401b0319166001600160401b0384161790556111ca565b80614c5360f01b141561114c57603c546001600160401b03808416911611806111055750603c54633b9aca00906110fa90600160c01b90046001600160401b0316846158e7565b6001600160401b0316115b156111235760405163180d062b60e31b815260040160405180910390fd5b603d8054600160401b600160801b031916600160401b6001600160401b038516021790556111ca565b806213531160ea1b14156111b157633b9aca00826001600160401b0316111561118857604051637650e96360e11b815260040160405180910390fd5b603d8054600160801b600160c01b031916600160801b6001600160401b038516021790556111ca565b60405163e1daa9cf60e01b815260040160405180910390fd5b604080516001600160401b0384168152602081018390527f13b367dac93b85d1ed9b3d8961d8b48e1a677c9800bb1613b4b0416b2d5b61d091015b60405180910390a15050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890611241903390600401614ee0565b602060405180830381865afa15801561125e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128291906158b3565b61129f57604051633b8d9d7560e21b815260040160405180910390fd5b603354604080516361d027b360e01b815290516001600160a01b03928316928416916361d027b39160048083019260209291908290030181865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f9190615912565b6001600160a01b031614611336576040516302979eb960e31b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611388903390600401614ee0565b602060405180830381865afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c991906158b3565b6113e657604051632678482f60e21b815260040160405180910390fd5b805182511415806114115750806000815181106114055761140561592f565b60200260200101516000145b806114a057506001600160a01b038316158015906114a057508160008151811061143d5761143d61592f565b6020026020010151826001815181106114585761145861592f565b60200260200101511115806114a057508060008151811061147b5761147b61592f565b6020026020010151816001815181106114965761149661592f565b6020026020010151105b156114be57604051631746545d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b03851617905581516114ec90603a906020850190614e69565b50805161150090603b906020840190614e69565b50826001600160a01b03167feb74d4d9fea592587c926aeb35eb6a7893fb28db0c1c8eb2eb3c586e7164b76c838360405161153c929190615980565b60405180910390a2505050565b611551614db6565b603d54600160c81b900460ff161561157c576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156115a85760405162461bcd60e51b815260040161159f906159a5565b60405180910390fd5b600260015586518651811415806115bd575080155b156115db576040516346282e8d60e01b815260040160405180910390fd5b603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611652919061583b565b606083015261165f613b3c565b60808301526040517f965a177723c641ee49150b583a0b9ad4730bb20d3474e00ae5a65e777c00d67b90611694908a906159dc565b60405180910390a160005b81811015611a66576000604360008b84815181106116bf576116bf61592f565b60200260200101518152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600061170c82338760600151886080015161377e565b90508060400151600014158015611740575080604001518a84815181106117355761173561592f565b602002602001015110155b80611767575080600001518a848151811061175d5761175d61592f565b6020026020010151115b156117905780600001518a84815181106117835761178361592f565b6020026020010181815250505b6000856060015182606001516117a6919061586a565b603854633b9aca008d87815181106117c0576117c061592f565b60200260200101516117d2919061586a565b6117dc919061586a565b6117e6919061589f565b90506118148c85815181106117fd576117fd61592f565b60200260200101518285600001511115610c6c5750565b8251811061194a575081516020830151604080546000906118369084906158d0565b92505081905550604360008d86815181106118535761185361592f565b60209081029190910181015182528101919091526040016000908120818155600101819055603d548c51633b9aca0091600160401b90046001600160401b0316908e90889081106118a6576118a661592f565b60200260200101516118b8919061586a565b6118c2919061589f565b9050826080015181106118d65760006118e6565b8083608001516118e691906158d0565b876040018181516118f791906159ef565b905250508b51600080516020615e97833981519152908d908690811061191f5761191f61592f565b60200260200101518460200151600060405161193d93929190615a07565b60405180910390a1611a0b565b80604360008e87815181106119615761196161592f565b60200260200101518152602001908152602001600020600001600082825461198991906158d0565b92505081905550611a098c85815181106119a5576119a561592f565b6020026020010151633b9aca00603d60089054906101000a90046001600160401b03166001600160401b03168e88815181106119e3576119e361592f565b60200260200101516119f5919061586a565b6119ff919061589f565b8860800151613bdd565b505b8086602001818151611a1d91906159ef565b9052508a518b9085908110611a3457611a3461592f565b602002602001015186600001818151611a4d91906159ef565b905250611a5f9250839150615a209050565b905061169f565b50603d54633b9aca0090611a8a90600160401b90046001600160401b0316826158d0565b8351611a96919061586a565b611aa0919061589f565b60416000828254611ab191906159ef565b9091555050604082015160428054600090611acd9084906159ef565b909155505060208201518251611ae7919088888888613d0c565b50600180559695505050505050565b603d54600160c81b900460ff1615611b21576040516313d0ff5960e31b815260040160405180910390fd5b6033546040516333b52a9f60e11b81526001600160a01b039091169063676a553e90611b51903390600401614ee0565b602060405180830381865afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9291906158b3565b611baf5760405163027f480760e01b815260040160405180910390fd5b603c54600090600160c01b90046001600160401b0316821015611bed57603c54611bea908390600160c01b90046001600160401b03166158d0565b90505b603c54600090600160801b90046001600160401b0316841115611c2a57603c54611c2790600160801b90046001600160401b0316856158d0565b90505b6000611c3b6002633b9aca00615b1f565b611c4983633b9aca006158d0565b611c5785633b9aca006158d0565b611c61908961586a565b611c6b919061586a565b611c75919061589f565b9050611c8181876158d0565b60416000828254611c9291906159ef565b90915550611ca4905087826000613bdd565b5050505050505050565b607e80546108cb90615806565b611cc3614ea3565b60408051600080825260208201909252611ce5918791879187918791906125ec565b90505b949350505050565b610d58338383613e16565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611d2b903390600401614ee0565b602060405180830381865afa158015611d48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6c91906158b3565b611d8957604051632678482f60e21b815260040160405180910390fd5b60398190556040518181527fdd63b3dcdbebad734892f7c7a26d0f647fbc7eec973e0775f5229018ac4ab47a9060200160405180910390a150565b603d54600090600160c81b900460ff1615611df2576040516313d0ff5960e31b815260040160405180910390fd5b6108b882613ecc565b919050565b3382611e0c8282613444565b611e295760405163c19f17a960e01b815260040160405180910390fd5b611e3586868686613ffa565b505050505050565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611e6d903390600401614ee0565b602060405180830381865afa158015611e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eae91906158b3565b611ecb57604051632678482f60e21b815260040160405180910390fd5b603d805460ff60c81b198116600160c81b9182900460ff1615909102179055565b6060611ef782613368565b611f145760405163062a39dd60e11b815260040160405180910390fd5b8160005b8115611f3b57611f2781615a20565b9050611f34600a8361589f565b9150611f18565b6000816001600160401b03811115611f5557611f556150b3565b6040519080825280601f01601f191660200182016040528015611f7f576020820181803683370190505b5090505b8415611fea57611f946001836158d0565b9150611fa1600a86615b2e565b611fac9060306159ef565b60f81b818381518110611fc157611fc161592f565b60200101906001600160f81b031916908160001a905350611fe3600a8661589f565b9450611f83565b60468054611ff790615806565b151590506120145760405180602001604052806000815250612038565b604681604051602001612028929190615b5e565b6040516020818303038152906040525b95945050505050565b600054610100900460ff16158080156120615750600054600160ff909116105b80612082575061207030613359565b158015612082575060005460ff166001145b6120e55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161159f565b6000805460ff191660011790558015612108576000805461ff0019166101001790555b856001600160a01b0316846001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612150573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121749190615912565b6001600160a01b03161461219b576040516302979eb960e31b815260040160405180910390fd5b603380546001600160a01b038089166001600160a01b0319928316179092556034805492881692909116821790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015612204573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122289190615bfc565b61223390600a615b1f565b603881905550856001600160a01b031663e9cbd8226040518163ffffffff1660e01b8152600401602060405180830381865afa158015612277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229b9190615912565b603580546001600160a01b03199081166001600160a01b0393841617909155603680549091169186169190911790556040516000906122de908490602001615c19565b60408051601f19818403018152919052805190915061230490607d906020840190614de5565b5061230e81614034565b8260405160200161231f9190615c60565b604051602081830303815290604052607e9080519060200190612343929190614de5565b50676765c793fa10079d601b1b603f5542603e5561236760a0850160808601615c8a565b6001600160401b03166123806040860160208701615c8a565b6001600160401b031611806123b05750633b9aca006123a560a0860160808701615c8a565b6001600160401b0316115b806123d657506123c66060850160408601615c8a565b6001600160401b0316633b9aca00115b806123fd5750633b9aca006123f160c0860160a08701615c8a565b6001600160401b031610155b8061240a575060e0840135155b1561242857604051631746545d60e11b815260040160405180910390fd5b833560395561243d6040850160208601615c8a565b603c80546001600160401b0319166001600160401b039290921691909117905561246d6060850160408601615c8a565b603c80546001600160401b0392909216600160401b02600160401b600160801b03199092169190911790556124a86080850160608601615c8a565b603d80546001600160401b0319166001600160401b03929092169190911790556124d860a0850160808601615c8a565b603d80546001600160401b0392909216600160401b02600160401b600160801b031990921691909117905561251360c0850160a08601615c8a565b603d80546001600160401b0392909216600160801b02600160801b600160c01b031990921691909117905561254e60e0850160c08601615ca5565b603d8054911515600160c01b0260ff60c01b19909216919091179055604080516020810190915260e0850135815261258a90603b906001614e69565b5050603d805460ff60c81b1916600160c81b1790558015611e35576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6125f4614ea3565b603d54600160c81b900460ff161561261f576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156126425760405162461bcd60e51b815260040161159f906159a5565b60026001558551875114158061265757508651155b15612675576040516346282e8d60e01b815260040160405180910390fd5b6000806000806000805b8c51811015612bdc5760008d828151811061269c5761269c61592f565b60200260200101519050600060078111156126b9576126b9615cc2565b8160078111156126cb576126cb615cc2565b141561270c576127068d83815181106126e6576126e661592f565b60200260200101518060200190518101906127019190615912565b613ecc565b50612bcb565b600281600781111561272057612720615cc2565b1415612786578c82815181106127385761273861592f565b60200260200101518060200190518101906127539190615cd8565b95509250826127625760455492505b61276c838661410a565b848860600181815161277e91906159ef565b905250612bcb565b600781600781111561279a5761279a615cc2565b14156128735760008060008f85815181106127b7576127b761592f565b60200260200101518060200190518101906127d29190615cfc565b60345460405163d505accf60e01b81526001600160a01b038089166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c48201849052969f50939d50939b509497509550929350169063d505accf9060e401600060405180830381600087803b15801561285357600080fd5b505af1158015612867573d6000803e3d6000fd5b50505050505050612bcb565b8661288357612880613b3c565b96505b600481600781111561289757612897615cc2565b1415612963578c82815181106128af576128af61592f565b60200260200101518060200190518101906128ca9190615cd8565b94509250826128d95760455492505b6128e4838589613bdd565b603c5490945060009061290b90600160c01b90046001600160401b0316633b9aca006158d0565b612919633b9aca008761586a565b612923919061589f565b905061292f85826158d0565b6041600082825461294091906159ef565b92505081905550808960200181815161295991906159ef565b905250612bcb9050565b856129e257603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129df919061583b565b95505b60018160078111156129f6576129f6615cc2565b1415612a72578c8281518110612a0e57612a0e61592f565b6020026020010151806020019051810190612a29919061583b565b925082612a365760455492505b612a41838789614176565b80965081955050508488604001818151612a5b91906159ef565b90525060208801805185919061277e9083906159ef565b6003816007811115612a8657612a86615cc2565b1415612ae6578c8281518110612a9e57612a9e61592f565b6020026020010151806020019051810190612ab99190615cd8565b9550925082612ac85760455492505b612ad48386888a614296565b848860400181815161277e91906159ef565b6005816007811115612afa57612afa615cc2565b1415612b5c578c8281518110612b1257612b1261592f565b6020026020010151806020019051810190612b2d9190615cd8565b9450925082612b3c5760455492505b612b488385888a614370565b9350838860000181815161277e91906159ef565b6006816007811115612b7057612b70615cc2565b1415612bcb576000808e8481518110612b8b57612b8b61592f565b6020026020010151806020019051810190612ba69190615d4f565b98509196509250905084612bba5760455494505b612bc8858383898c8e61440b565b50505b50612bd581615a20565b905061267f565b508551602087015110612cd35785516020870151600091612bfc916158d0565b90508660600151876040015110612c3357612c2e87606001518860400151612c2491906158d0565b828d8d8d8d613d0c565b612ccd565b8015612ca057603554604051630d43af8160e21b81526001600160a01b039091169063350ebe0490612c6d9084908f903390600401615d8d565b600060405180830381600087803b158015612c8757600080fd5b505af1158015612c9b573d6000803e3d6000fd5b505050505b612ccd333089604001518a60600151612cb991906158d0565b6034546001600160a01b0316929190614547565b50612e5f565b60208601518651600091612ce6916158d0565b6035546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990612d19908d908590600401615dac565b600060405180830381600087803b158015612d3357600080fd5b505af1158015612d47573d6000803e3d6000fd5b50505050866060015187604001511115612d8b57612d868a88606001518960400151612d7391906158d0565b6034546001600160a01b031691906145b2565b612e5d565b600087604001518860600151612da191906158d0565b90508015612e5b57885115612e4357896001600160a01b031663a5d4096b603560009054906101000a90046001600160a01b0316603460009054906101000a90046001600160a01b03163385878f6040518763ffffffff1660e01b8152600401612e1096959493929190615dc5565b600060405180830381600087803b158015612e2a57600080fd5b505af1158015612e3e573d6000803e3d6000fd5b505050505b603454612e5b906001600160a01b0316333084614547565b505b505b505060018055509198975050505050505050565b603a8181548110610c7f57600080fd5b6001600160a01b039182166000908152604a6020908152604080832093909416825291909152205460011490565b6033546001600160a01b03163314612edc5760405163b90cdbb160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0383811691909117909155603654604051630787a21360e51b815291169063f0f4426090612f23908490600401614ee0565b600060405180830381600087803b158015612f3d57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b83421115612f725760405163f87d927160e01b815260040160405180910390fd5b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03811180612fa957508260ff16601b14158015612fa957508260ff16601c14155b15612fc757604051638baa579f60e01b815260040160405180910390fd5b6000612fd1613ad0565b608254898989612fe08d6145d1565b6040805160208101969096526001600160a01b03948516908601529290911660608401521515608083015260a082015260c0810187905260e0016040516020818303038152906040528051906020012060405160200161305792919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050613081886001600160a01b0316613359565b1561315d57604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b038a1691631626ba7e916130e7918591606501615e07565b602060405180830381865afa158015613104573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131289190615e20565b6001600160e01b031916631626ba7e60e01b1461315857604051638baa579f60e01b815260040160405180910390fd5b613205565b6040805160008082526020820180845284905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156131b1573d6000803e3d6000fd5b505050602060405103519050886001600160a01b0316816001600160a01b03161415806131e557506001600160a01b038116155b1561320357604051638baa579f60e01b815260040160405180910390fd5b505b611ca4888888613e16565b613218614db6565b60408051600080825260208201909252611ce591879187918791879190611549565b60335460009081906001600160a01b0316331461326a5760405163b90cdbb160e01b815260040160405180910390fd5b613272613b3c565b50506041805460428054600093849055929055915080821061330b5761329881836158d0565b6035546033546040516340c10f1960e01b8152929450600093506001600160a01b03918216926340c10f19926132d49216908690600401615dac565b600060405180830381600087803b1580156132ee57600080fd5b505af1158015613302573d6000803e3d6000fd5b5050505061331c565b61331582826158d0565b9050600091505b60408051838152602081018390527ffeb12225c131aab793a00c5239afb778932d170fa28ce6e9d23703e4bd892121910160405180910390a19091565b6001600160a01b03163b151590565b6000908152604760205260409020546001600160a01b0316151590565b6000908152604960205260409020546001600160a01b031690565b6000818152604760205260409020546001600160a01b031680611dfb5760405163062a39dd60e11b815260040160405180910390fd5b600081815260496020526040902080546001600160a01b0319166001600160a01b038416908117909155819061340b826133a0565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080613450836133a0565b9050806001600160a01b0316846001600160a01b0316148061348b5750836001600160a01b031661348084613385565b6001600160a01b0316145b80611ce857506001600160a01b038082166000908152604a6020908152604080832093881683529290522054600114949350505050565b826001600160a01b03166134d5826133a0565b6001600160a01b0316146134fc5760405163c19f17a960e01b815260040160405180910390fd5b6001600160a01b0382166135235760405163d92e233d60e01b815260040160405180910390fd5b603d54600160c01b900460ff16801561355557506001600160a01b038216600090815260446020526040902054600114155b1561357357604051630b094f2760e31b815260040160405180910390fd5b61357e6000826133d6565b6001600160a01b038084166000818152604860209081526040808320805460001901905593861680835284832080546001019055858352604790915283822080546001600160a01b03191682179055925184939291600080516020615ed783398151915291a4505050565b600080603e54426135fa91906158d0565b603d549091506001600160401b0316811580613614575080155b1561362357603f549250505090565b60006136306001846158d0565b905060006002841161364357600061364e565b61364e6002856158d0565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b613674868061586a565b61367e91906159ef565b613688919061589f565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b6136ae878561586a565b6136b891906159ef565b6136c2919061589f565b905060006002836136d3878a61586a565b6136dd919061586a565b6136e7919061589f565b90506000600683866136f9898c61586a565b613703919061586a565b61370d919061586a565b613717919061589f565b9050676765c793fa10079d601b1b81836137318b8b61586a565b61374690676765c793fa10079d601b1b6159ef565b61375091906159ef565b61375a91906159ef565b603f54613767919061586a565b613771919061589f565b9850505050505050505090565b613786614db6565b6000806000613796888787614615565b925092509250633b9aca0083106137c0576040516315fe9b6160e21b815260040160405180910390fd5b6000633b9aca006137d185826158d0565b6137da8a61469e565b6137e4919061586a565b6137ee919061589f565b603d54909150600160801b90046001600160401b031681101561381e5761381981633b9aca006158d0565b61383f565b603d5461383f90600160801b90046001600160401b0316633b9aca006158d0565b603d54909150600160401b90046001600160401b03166000806138676002633b9aca00615b1f565b603c5461387d91906001600160401b031661586a565b83613888868a61586a565b613892919061586a565b10613a1b57603c546001600160401b03166138b26002633b9aca00615b1f565b6138bc919061586a565b603c5485906138db90600160401b90046001600160401b03168661586a565b6138e5919061586a565b6138ef91906158d0565b603c548590633b9aca009061390d906001600160401b03168961586a565b603c5461392b908b90600160401b90046001600160401b031661586a565b61393591906158d0565b61393f919061586a565b613949919061586a565b613953919061589f565b9150633b9aca0060b454613967919061586a565b613971848461586a565b61397b91906159ef565b613989633b9aca008861586a565b11613a16576139a3676765c793fa10079d601b1b8461586a565b633b9aca008a8e602001516139b8919061586a565b6139c2919061586a565b6139cc919061589f565b6139d79060016159ef565b915060b454861115613a125782633b9aca0060b454886139f791906158d0565b613a01919061586a565b613a0b919061589f565b9050613a7e565b5060015b613a7e565b603854613a2c90633b9aca0061586a565b8c518b90613a3b90879061586a565b613a45919061586a565b613a4f919061589f565b613a5a9060016159ef565b915060b554851115613a7a57633b9aca008460b554876139f791906158d0565b5060015b818852613a8b848b61586a565b603854613a9c633b9aca008561586a565b613aa6919061586a565b613ab0919061589f565b602089015260408801525050606085015250608083015250949350505050565b60808054608154604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082015290810192909252606082015246918101919091523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6000613b466135e9565b90506000676765c793fa10079d601b1b603f5483613b6491906158d0565b604054613b71919061586a565b613b7b919061589f565b90508060416000828254613b8f91906159ef565b9091555050603f82905542603e8190556040805184815260208101929092527fd1fa8ba00a3bf20274346919dce0de62d2a140af2c71fe7e29fa6472eea3bb9d910160405180910390a15090565b600081613bef57613bec613b3c565b91505b60008481526043602052604081206001015490676765c793fa10079d601b1b613c18858461586a565b613c22919061589f565b9050808510613c3357935080613c56565b83613c49676765c793fa10079d601b1b8761586a565b613c53919061589f565b90505b613c6081836158d0565b91508060406000828254613c7491906158d0565b90915550508115801590613ca95750676765c793fa10079d601b1b60b454613c9c919061586a565b613ca6858461586a565b11155b15613cc75760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604080822060010184905551600080516020615e9783398151915291613cfa9189918591615a07565b60405180910390a15092949350505050565b8515613d2957603454613d29906001600160a01b031684886145b2565b8415611e3557805115613da85760345460355460405163a5d4096b60e01b81526001600160a01b038086169363a5d4096b93613d759391831692169089908b908d908990600401615dc5565b600060405180830381600087803b158015613d8f57600080fd5b505af1158015613da3573d6000803e3d6000fd5b505050505b603554604051630d43af8160e21b81526001600160a01b039091169063350ebe0490613ddc90889088903390600401615d8d565b600060405180830381600087803b158015613df657600080fd5b505af1158015613e0a573d6000803e3d6000fd5b50505050505050505050565b826001600160a01b0316826001600160a01b03161415613e49576040516320c5195360e21b815260040160405180910390fd5b600081613e57576000613e5a565b60015b6001600160a01b038581166000818152604a602090815260408083209489168084529482529182902060ff959095169485905590518615158152939450919290917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b603d54600090600160c01b900460ff168015613f1b57506001600160a01b0382166000908152604460205260409020546001141580613f1b575033600090815260446020526040902054600114155b15613f3957604051630b094f2760e31b815260040160405180910390fd5b6001600160a01b038216613f605760405163d92e233d60e01b815260040160405180910390fd5b5060458054600101908190556001600160a01b038216600081815260486020908152604080832080546001019055848352604790915280822080546001600160a01b031916841790555183929190600080516020615ed7833981519152908290a4613fdd60008383604051806020016040528060008152506148cd565b611dfb576040516320149b4360e21b815260040160405180910390fd5b6140058484846134c2565b614011848484846148cd565b61402e576040516320149b4360e21b815260040160405180910390fd5b50505050565b600054610100900460ff1661409f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161159f565b7f3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd860825580516020918201206080556040805180820190915260018152603160f81b9101527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6608155565b61411382613368565b6141305760405163062a39dd60e11b815260040160405180910390fd5b6000828152604360205260408120805483929061414e9084906159ef565b9091555050604051600080516020615eb7833981519152906112059084908490600190615a07565b60008033856141858282613444565b6141a25760405163c19f17a960e01b815260040160405180910390fd5b6000878152604360209081526040808320815180830190925280548252600101549181019190915290806141d7838a8a614615565b5091509150633b9aca00821161420057604051631527804d60e31b815260040160405180910390fd5b82602001516040600082825461421691906158d0565b9091555061422590508a6149d0565b603c5460009061424990600160c01b90046001600160401b0316633b9aca006158d0565b614257633b9aca008461586a565b614261919061589f565b905061426d82826158d0565b6041600082825461427e91906159ef565b90915550509251929a92995091975050505050505050565b33846142a28282613444565b6142bf5760405163c19f17a960e01b815260040160405180910390fd5b600086815260436020526040812080548792906142dd9084906158d0565b909155505060008681526043602090815260408083208151808301909252805482526001015491810191909152614315908686614615565b50509050633b9aca00811161433d57604051631527804d60e31b815260040160405180910390fd5b600080516020615eb78339815191528787600060405161435f93929190615a07565b60405180910390a150505050505050565b6000338561437e8282613444565b61439b5760405163c19f17a960e01b815260040160405180910390fd5b6143a787878787614a4f565b603c54909650600090633b9aca00906143d1908990600160801b90046001600160401b031661586a565b6143db919061589f565b905080604160008282546143ef91906159ef565b909155506143ff905081886158d0565b98975050505050505050565b33866144178282613444565b6144345760405163c19f17a960e01b815260040160405180910390fd5b60408051898152602081018890526001600160a01b038916818301526060810187905290517fddd3b70af631334f7552aadb582ed091018e62e103fa8b150ca66cc700d4dac69181900360800190a161448f88868686614a4f565b94506001600160a01b0387163014156144b3576144ad868685613bdd565b50611ca4565b603c546040516320d661ad60e21b815260048101889052602481018790526001600160401b03600160801b830481166044830152600160c01b90920490911660648201526001600160a01b0388169063835986b490608401600060405180830381600087803b15801561452557600080fd5b505af1158015614539573d6000803e3d6000fd5b505050505050505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261402e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614be2565b610a058363a9059cbb60e01b848460405160240161457b929190615dac565b6001600160a01b0381166000908152607f60205260409020546145f58160016159ef565b6001600160a01b039092166000908152607f602052604090209190915590565b6000806000676765c793fa10079d601b1b848760200151614636919061586a565b614640919061589f565b9150603854858760000151614655919061586a565b61465f919061589f565b905081614670576000199250614695565b603c548290614688906001600160401b03168361586a565b614692919061589f565b92505b93509350939050565b6037546000906001600160a01b03166146d757603b6000815481106146c5576146c561592f565b90600052602060002001549050919050565b603754604051635dfba04560e11b81526000916001600160a01b03169063bbf7408a90614708908690600401614ee0565b602060405180830381865afa158015614725573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614749919061583b565b9050603a60018154811061475f5761475f61592f565b9060005260206000200154811061479757603b6001815481106147845761478461592f565b9060005260206000200154915050919050565b603a6000815481106147ab576147ab61592f565b906000526020600020015481116147d057603b6000815481106147845761478461592f565b603a6000815481106147e4576147e461592f565b9060005260206000200154603a6001815481106148035761480361592f565b906000526020600020015461481891906158d0565b603a60008154811061482c5761482c61592f565b90600052602060002001548261484291906158d0565b603b6000815481106148565761485661592f565b9060005260206000200154603b6001815481106148755761487561592f565b906000526020600020015461488a91906158d0565b614894919061586a565b61489e919061589f565b603b6000815481106148b2576148b261592f565b9060005260206000200154610af091906159ef565b50919050565b60006148e1846001600160a01b0316613359565b156149c857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614918903390899088908890600401615e3d565b6020604051808303816000875af1925050508015614953575060408051601f3d908101601f1916820190925261495091810190615e20565b60015b6149ae573d808015614981576040519150601f19603f3d011682016040523d82523d6000602084013e614986565b606091505b5080516149a6576040516320149b4360e21b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611ce8565b506001611ce8565b60006149db826133a0565b90506149e86000836133d6565b6001600160a01b038116600081815260486020908152604080832080546000190190558583526047825280832080546001600160a01b0319169055604390915280822082815560010182905551849290600080516020615ed7833981519152908390a45050565b60008082614a68676765c793fa10079d601b1b8761586a565b614a72919061589f565b600087815260436020526040902060010154909150614aad5760b4548511614aad5760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604081206001018054839290614ace9084906159ef565b925050819055508060406000828254614ae791906159ef565b9091555050603954614b0590676765c793fa10079d601b1b9061586a565b83604054614b13919061586a565b1115614b32576040516371239a6160e11b815260040160405180910390fd5b60008681526043602090815260408083208151808301909252805482526001015491810191909152614b65908686614615565b50509050633b9aca008111614b8d57604051631527804d60e31b815260040160405180910390fd5b600080516020615e9783398151915287836001604051614baf93929190615a07565b60405180910390a1676765c793fa10079d601b1b614bcd858461586a565b614bd7919061589f565b979650505050505050565b6000614c37826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cb49092919063ffffffff16565b805190915015610a055780806020019051810190614c5591906158b3565b610a055760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161159f565b6060611ce8848460008585614cc885613359565b614d145760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161159f565b600080866001600160a01b03168587604051614d309190615e7a565b60006040518083038185875af1925050503d8060008114614d6d576040519150601f19603f3d011682016040523d82523d6000602084013e614d72565b606091505b5091509150614bd782828660608315614d8c575081610af0565b825115614d9c5782518084602001fd5b8160405162461bcd60e51b815260040161159f9190614f7f565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054614df190615806565b90600052602060002090601f016020900481019282614e135760008555614e59565b82601f10614e2c57805160ff1916838001178555614e59565b82800160010185558215614e59579182015b82811115614e59578251825591602001919060010190614e3e565b50614e65929150614ecb565b5090565b828054828255906000526020600020908101928215614e595791602002820182811115614e59578251825591602001919060010190614e3e565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b5b80821115614e655760008155600101614ecc565b6001600160a01b0391909116815260200190565b6001600160e01b031981168114610c6c57600080fd5b600060208284031215614f1c57600080fd5b8135610af081614ef4565b60005b83811015614f42578181015183820152602001614f2a565b8381111561402e5750506000910152565b60008151808452614f6b816020860160208601614f27565b601f01601f19169290920160200192915050565b602081526000610af06020830184614f53565b600060208284031215614fa457600080fd5b5035919050565b6001600160a01b0381168114610c6c57600080fd5b60008060408385031215614fd357600080fd5b8235614fde81614fab565b946020939093013593505050565b60008060006060848603121561500157600080fd5b833561500c81614fab565b9250602084013561501c81614fab565b929592945050506040919091013590565b6000806040838503121561504057600080fd5b82359150602083013561505281614fab565b809150509250929050565b60a081016108b8828480518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b6000602082840312156150a857600080fd5b8135610af081614fab565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150f1576150f16150b3565b604052919050565b600082601f83011261510a57600080fd5b81356001600160401b03811115615123576151236150b3565b615136601f8201601f19166020016150c9565b81815284602083860101111561514b57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561517a57600080fd5b81356001600160401b0381111561519057600080fd5b611ce8848285016150f9565b600080604083850312156151af57600080fd5b50508035926020909101359150565b80356001600160401b0381168114611dfb57600080fd5b600080604083850312156151e857600080fd5b614fde836151be565b60006001600160401b0382111561520a5761520a6150b3565b5060051b60200190565b600082601f83011261522557600080fd5b8135602061523a615235836151f1565b6150c9565b82815260059290921b8401810191818101908684111561525957600080fd5b8286015b84811015615274578035835291830191830161525d565b509695505050505050565b60008060006060848603121561529457600080fd5b833561529f81614fab565b925060208401356001600160401b03808211156152bb57600080fd5b6152c787838801615214565b935060408601359150808211156152dd57600080fd5b506152ea86828701615214565b9150509250925092565b60008060008060008060c0878903121561530d57600080fd5b86356001600160401b038082111561532457600080fd5b6153308a838b01615214565b9750602089013591508082111561534657600080fd5b6153528a838b01615214565b96506040890135915061536482614fab565b90945060608801359061537682614fab565b90935060808801359061538882614fab565b90925060a0880135908082111561539e57600080fd5b506153ab89828a016150f9565b9150509295509295509295565b600080600080608085870312156153ce57600080fd5b5050823594602084013594506040840135936060013592509050565b600082601f8301126153fb57600080fd5b8135602061540b615235836151f1565b82815260059290921b8401810191818101908684111561542a57600080fd5b8286015b84811015615274578035600881106154465760008081fd5b835291830191830161542e565b600082601f83011261546457600080fd5b81356020615474615235836151f1565b82815260059290921b8401810191818101908684111561549357600080fd5b8286015b848110156152745780356001600160401b038111156154b65760008081fd5b6154c48986838b01016150f9565b845250918301918301615497565b600080600080608085870312156154e857600080fd5b84356001600160401b03808211156154ff57600080fd5b61550b888389016153ea565b9550602087013591508082111561552157600080fd5b5061552e87828801615453565b935050604085013561553f81614fab565b9150606085013561554f81614fab565b939692955090935050565b8015158114610c6c57600080fd5b6000806040838503121561557b57600080fd5b823561558681614fab565b915060208301356150528161555a565b600080600080608085870312156155ac57600080fd5b84356155b781614fab565b935060208501356155c781614fab565b92506040850135915060608501356001600160401b038111156155e957600080fd5b6155f5878288016150f9565b91505092959194509250565b600080600080600085870361018081121561561b57600080fd5b863561562681614fab565b9550602087013561563681614fab565b9450604087013561564681614fab565b9350610100605f198201121561565b57600080fd5b506060860191506101608601356001600160401b0381111561567c57600080fd5b615688888289016150f9565b9150509295509295909350565b60008060008060008060c087890312156156ae57600080fd5b86356001600160401b03808211156156c557600080fd5b6156d18a838b016153ea565b975060208901359150808211156156e757600080fd5b6153528a838b01615453565b6000806040838503121561570657600080fd5b823561571181614fab565b9150602083013561505281614fab565b60ff81168114610c6c57600080fd5b600080600080600080600060e0888a03121561574b57600080fd5b873561575681614fab565b9650602088013561576681614fab565b955060408801356157768161555a565b945060608801359350608088013561578d81615721565b9699959850939692959460a0840135945060c09093013592915050565b600080600080608085870312156157c057600080fd5b84356001600160401b03808211156157d757600080fd5b6157e388838901615214565b955060208701359150808211156157f957600080fd5b5061552e87828801615214565b600181811c9082168061581a57607f821691505b602082108114156148c757634e487b7160e01b600052602260045260246000fd5b60006020828403121561584d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561588457615884615854565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826158ae576158ae615889565b500490565b6000602082840312156158c557600080fd5b8151610af08161555a565b6000828210156158e2576158e2615854565b500390565b60006001600160401b0382811684821680830382111561590957615909615854565b01949350505050565b60006020828403121561592457600080fd5b8151610af081614fab565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b8381101561597557815187529582019590820190600101615959565b509495945050505050565b6040815260006159936040830185615945565b82810360208401526120388185615945565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b602081526000610af06020830184615945565b60008219821115615a0257615a02615854565b500190565b928352602083019190915260ff16604082015260600190565b6000600019821415615a3457615a34615854565b5060010190565b600181815b80851115615a76578160001904821115615a5c57615a5c615854565b80851615615a6957918102915b93841c9390800290615a40565b509250929050565b600082615a8d575060016108b8565b81615a9a575060006108b8565b8160018114615ab05760028114615aba57615ad6565b60019150506108b8565b60ff841115615acb57615acb615854565b50506001821b6108b8565b5060208310610133831016604e8410600b8410161715615af9575081810a6108b8565b615b038383615a3b565b8060001904821115615b1757615b17615854565b029392505050565b6000610af060ff841683615a7e565b600082615b3d57615b3d615889565b500690565b60008151615b54818560208601614f27565b9290920192915050565b600080845481600182811c915080831680615b7a57607f831692505b6020808410821415615b9a57634e487b7160e01b86526022600452602486fd5b818015615bae5760018114615bbf57615bec565b60ff19861689528489019650615bec565b60008b81526020902060005b86811015615be45781548b820152908501908301615bcb565b505084890196505b5050505050506120388185615b42565b600060208284031215615c0e57600080fd5b8151610af081615721565b6e020b733b63290283937ba37b1b7b61608d1b815260008251615c4381600f850160208701614f27565b650815985d5b1d60d21b600f939091019283015250601501919050565b60008251615c72818460208701614f27565b650b5d985d5b1d60d21b920191825250600601919050565b600060208284031215615c9c57600080fd5b610af0826151be565b600060208284031215615cb757600080fd5b8135610af08161555a565b634e487b7160e01b600052602160045260246000fd5b60008060408385031215615ceb57600080fd5b505080516020909101519092909150565b60008060008060008060c08789031215615d1557600080fd5b8651615d2081614fab565b6020880151604089015160608a015160808b015160a0909b0151939c929b509099909850965090945092505050565b60008060008060808587031215615d6557600080fd5b845193506020850151615d7781614fab565b6040860151606090960151949790965092505050565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a082018190526000906143ff90830184614f53565b828152604060208201526000611ce86040830184614f53565b600060208284031215615e3257600080fd5b8151610af081614ef4565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e7090830184614f53565b9695505050505050565b60008251615e8c818460208701614f27565b919091019291505056fe70cf49afe7355562d5b022e594790f22b71ad8cc7eec902fa5feac7c67f71091722cb71fa87c947148cefc06dd890af5802a6a00207c5ddecf1191bf71ce3cd4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122004adf5a8fe3c52a612a81111fd6100f9eeb84fbeb3cfcc411a5bf2e9a14a72cb64736f6c634300080c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102f65760003560e01c8063010db195146102fb57806301ffc9a71461032457806306fdde0314610347578063081812fc1461035c578063087a60071461036f578063095ea7b3146103865780630e198f221461039b57806313888565146103a457806323b872dd146103ad578063254cf439146103c0578063307439af146103f257806334ce998a1461041257806335836f151461041a5780633644e5151461042d57806339393ac91461043557806339eb4dc6146104485780633ae2325f1461045c5780633af32abf1461046f5780633c2e941b1461048f57806342842e0e14610498578063430c2081146104ab5780634f7e43df146104be57806355f804b3146104d85780635b84d88a146104eb5780635c975abb146104fe57806361d027b3146105125780636352211e1461052557806370a0823114610538578063741075431461054b5780637aacfffa1461055e5780637adbf9731461059a5780637c0f59f4146105ad5780637c3a00fd146105c75780637dc0d1d0146105da5780637e53bd97146105ed5780637e56d47c146106005780637ecebe0014610613578063835986b41461063c57806389050f1d1461064f57806395d89b41146106615780639a3b6f2f146106695780639f48118f146106af578063a22cb465146106ba578063af2c8c2e146106cd578063b1511cc9146106d6578063b4bd6f46146106e9578063b88d4fde146106fc578063bbcac5571461070f578063c4ae316814610718578063c66d8b0114610720578063c87b56dd1461073a578063d8dfeb451461074d578063d9b1cb5b14610760578063de1f776514610773578063de8fc69814610785578063df011c4114610798578063e182b883146107ab578063e1c84ea4146107be578063e626648a146107c7578063e985e9c5146107e1578063e9cbd822146107f4578063f0f4426014610807578063f51cc7dd1461081a578063fad9aba31461082d578063fc29b02114610836578063fd527cf814610849575b600080fd5b60375461030e906001600160a01b031681565b60405161031b9190614ee0565b60405180910390f35b610337610332366004614f0a565b610851565b604051901515815260200161031b565b61034f6108be565b60405161031b9190614f7f565b61030e61036a366004614f92565b61094c565b610378603f5481565b60405190815260200161031b565b610399610394366004614fc0565b61097d565b005b610378603e5481565b61037860415481565b6103996103bb366004614fec565b610a0a565b603c546103da90600160401b90046001600160401b031681565b6040516001600160401b03909116815260200161031b565b61040561040036600461502d565b610a45565b60405161031b919061505d565b610378610af7565b610378610428366004614f92565b610b29565b610378610b65565b610399610443366004615096565b610b6f565b603d5461033790600160c01b900460ff1681565b61037861046a366004614f92565b610c6f565b61037861047d366004615096565b60446020526000908152604090205481565b61037860455481565b6103996104a6366004614fec565b610c90565b6103376104b9366004614fc0565b610cab565b603d546103da90600160801b90046001600160401b031681565b6103996104e6366004615168565b610cb7565b6103996104f936600461519c565b610d5c565b603d5461033790600160c81b900460ff1681565b60335461030e906001600160a01b031681565b61030e610533366004614f92565b610df5565b610378610546366004615096565b610e00565b6103996105593660046151d5565b610e45565b61058561056c366004614f92565b6043602052600090815260409020805460019091015482565b6040805192835260208301919091520161031b565b6103996105a8366004615096565b611211565b603c546103da90600160c01b90046001600160401b031681565b603d546103da906001600160401b031681565b60365461030e906001600160a01b031681565b6103996105fb36600461527f565b611358565b61040561060e3660046152f4565b611549565b610378610621366004615096565b6001600160a01b03166000908152607f602052604090205490565b61039961064a3660046153b8565b611af6565b610378676765c793fa10079d601a1b81565b61034f611cae565b61067c6106773660046154d2565b611cbb565b60405161031b91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b610378633b9aca0081565b6103996106c8366004615568565b611cf0565b61037860405481565b6103996106e4366004614f92565b611cfb565b6103786106f7366004615096565b611dc4565b61039961070a366004615596565b611e00565b61037860425481565b610399611e3d565b603d546103da90600160401b90046001600160401b031681565b61034f610748366004614f92565b611eec565b60345461030e906001600160a01b031681565b61039961076e366004615601565b612041565b610378676765c793fa10079d601b1b81565b61067c610793366004615695565b6125ec565b603c546103da906001600160401b031681565b6103786107b9366004614f92565b612e73565b61037860395481565b603c546103da90600160801b90046001600160401b031681565b6103376107ef3660046156f3565b612e83565b60355461030e906001600160a01b031681565b610399610815366004615096565b612eb1565b610399610828366004615730565b612f51565b61037860b45481565b6104056108443660046157aa565b613210565b61058561323a565b60006001600160e01b03198216635b5e139f60e01b148061088257506001600160e01b031982166380ac58cd60e01b145b8061089d57506001600160e01b0319821663430c208160e01b145b806108b857506001600160e01b031982166301ffc9a760e01b145b92915050565b607d80546108cb90615806565b80601f01602080910402602001604051908101604052809291908181526020018280546108f790615806565b80156109445780601f1061091957610100808354040283529160200191610944565b820191906000526020600020905b81548152906001019060200180831161092757829003601f168201915b505050505081565b600061095782613368565b6109745760405163062a39dd60e11b815260040160405180910390fd5b6108b882613385565b6000610988826133a0565b9050806001600160a01b0316836001600160a01b031614156109bd576040516349fa8bc360e11b815260040160405180910390fd5b336001600160a01b038216148015906109dd57506109db8133612e83565b155b156109fb5760405163c19f17a960e01b815260040160405180910390fd5b610a0583836133d6565b505050565b3381610a168282613444565b610a335760405163c19f17a960e01b815260040160405180910390fd5b610a3e8585856134c2565b5050505050565b610a4d614db6565b60008381526043602090815260409182902082518084018452815481526001909101548183015260365483516315f789a960e21b81529351610af094929387936001600160a01b03909316926357de26a492600480830193928290030181865afa158015610abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae3919061583b565b610aeb6135e9565b61377e565b9392505050565b6000676765c793fa10079d601b1b610b0d6135e9565b604054610b1a919061586a565b610b24919061589f565b905090565b6000676765c793fa10079d601b1b610b3f6135e9565b600084815260436020526040902060010154610b5b919061586a565b6108b8919061589f565b6000610b24613ad0565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610b9f903390600401614ee0565b602060405180830381865afa158015610bbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be091906158b3565b610bfd57604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b03811615610c4c576001600160a01b038116600090815260446020526040902054610c309060016158d0565b6001600160a01b03821660009081526044602052604090205550565b603d805460ff60c01b198116600160c01b9182900460ff16159091021790555b50565b603b8181548110610c7f57600080fd5b600091825260209091200154905081565b610a0583838360405180602001604052806000815250611e00565b6000610af08383613444565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610ce7903390600401614ee0565b602060405180830381865afa158015610d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2891906158b3565b610d4557604051632678482f60e21b815260040160405180910390fd5b8051610d58906046906020840190614de5565b5050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610d8c903390600401614ee0565b602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906158b3565b610dea57604051633b8d9d7560e21b815260040160405180910390fd5b60b49190915560b555565b60006108b8826133a0565b60006001600160a01b038216610e295760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b031660009081526048602052604090205490565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610e75903390600401614ee0565b602060405180830381865afa158015610e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb691906158b3565b610ed357604051632678482f60e21b815260040160405180910390fd5b806121a360f11b1415610f3757603d546001600160401b03600160401b90910481169083161115610f1757604051637650e96360e11b815260040160405180910390fd5b603c80546001600160401b0319166001600160401b0384161790556111ca565b80622a242360e91b1415610f9c57633b9aca00826001600160401b03161015610f735760405163da6a17b960e01b815260040160405180910390fd5b603c8054600160401b600160801b031916600160401b6001600160401b038516021790556111ca565b8061212360f11b141561100057633b9aca00826001600160401b03161115610fd757604051637650e96360e11b815260040160405180910390fd5b603c8054600160801b600160c01b031916600160801b6001600160401b038516021790556111ca565b8061292360f11b141561107d57603d54633b9aca009061103090600160401b90046001600160401b0316846158e7565b6001600160401b0316111561105857604051637650e96360e11b815260040160405180910390fd5b603c80546001600160c01b0316600160c01b6001600160401b038516021790556111ca565b806124a960f11b14156110b357611092613b3c565b50603d80546001600160401b0319166001600160401b0384161790556111ca565b80614c5360f01b141561114c57603c546001600160401b03808416911611806111055750603c54633b9aca00906110fa90600160c01b90046001600160401b0316846158e7565b6001600160401b0316115b156111235760405163180d062b60e31b815260040160405180910390fd5b603d8054600160401b600160801b031916600160401b6001600160401b038516021790556111ca565b806213531160ea1b14156111b157633b9aca00826001600160401b0316111561118857604051637650e96360e11b815260040160405180910390fd5b603d8054600160801b600160c01b031916600160801b6001600160401b038516021790556111ca565b60405163e1daa9cf60e01b815260040160405180910390fd5b604080516001600160401b0384168152602081018390527f13b367dac93b85d1ed9b3d8961d8b48e1a677c9800bb1613b4b0416b2d5b61d091015b60405180910390a15050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890611241903390600401614ee0565b602060405180830381865afa15801561125e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128291906158b3565b61129f57604051633b8d9d7560e21b815260040160405180910390fd5b603354604080516361d027b360e01b815290516001600160a01b03928316928416916361d027b39160048083019260209291908290030181865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f9190615912565b6001600160a01b031614611336576040516302979eb960e31b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611388903390600401614ee0565b602060405180830381865afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c991906158b3565b6113e657604051632678482f60e21b815260040160405180910390fd5b805182511415806114115750806000815181106114055761140561592f565b60200260200101516000145b806114a057506001600160a01b038316158015906114a057508160008151811061143d5761143d61592f565b6020026020010151826001815181106114585761145861592f565b60200260200101511115806114a057508060008151811061147b5761147b61592f565b6020026020010151816001815181106114965761149661592f565b6020026020010151105b156114be57604051631746545d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b03851617905581516114ec90603a906020850190614e69565b50805161150090603b906020840190614e69565b50826001600160a01b03167feb74d4d9fea592587c926aeb35eb6a7893fb28db0c1c8eb2eb3c586e7164b76c838360405161153c929190615980565b60405180910390a2505050565b611551614db6565b603d54600160c81b900460ff161561157c576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156115a85760405162461bcd60e51b815260040161159f906159a5565b60405180910390fd5b600260015586518651811415806115bd575080155b156115db576040516346282e8d60e01b815260040160405180910390fd5b603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611652919061583b565b606083015261165f613b3c565b60808301526040517f965a177723c641ee49150b583a0b9ad4730bb20d3474e00ae5a65e777c00d67b90611694908a906159dc565b60405180910390a160005b81811015611a66576000604360008b84815181106116bf576116bf61592f565b60200260200101518152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600061170c82338760600151886080015161377e565b90508060400151600014158015611740575080604001518a84815181106117355761173561592f565b602002602001015110155b80611767575080600001518a848151811061175d5761175d61592f565b6020026020010151115b156117905780600001518a84815181106117835761178361592f565b6020026020010181815250505b6000856060015182606001516117a6919061586a565b603854633b9aca008d87815181106117c0576117c061592f565b60200260200101516117d2919061586a565b6117dc919061586a565b6117e6919061589f565b90506118148c85815181106117fd576117fd61592f565b60200260200101518285600001511115610c6c5750565b8251811061194a575081516020830151604080546000906118369084906158d0565b92505081905550604360008d86815181106118535761185361592f565b60209081029190910181015182528101919091526040016000908120818155600101819055603d548c51633b9aca0091600160401b90046001600160401b0316908e90889081106118a6576118a661592f565b60200260200101516118b8919061586a565b6118c2919061589f565b9050826080015181106118d65760006118e6565b8083608001516118e691906158d0565b876040018181516118f791906159ef565b905250508b51600080516020615e97833981519152908d908690811061191f5761191f61592f565b60200260200101518460200151600060405161193d93929190615a07565b60405180910390a1611a0b565b80604360008e87815181106119615761196161592f565b60200260200101518152602001908152602001600020600001600082825461198991906158d0565b92505081905550611a098c85815181106119a5576119a561592f565b6020026020010151633b9aca00603d60089054906101000a90046001600160401b03166001600160401b03168e88815181106119e3576119e361592f565b60200260200101516119f5919061586a565b6119ff919061589f565b8860800151613bdd565b505b8086602001818151611a1d91906159ef565b9052508a518b9085908110611a3457611a3461592f565b602002602001015186600001818151611a4d91906159ef565b905250611a5f9250839150615a209050565b905061169f565b50603d54633b9aca0090611a8a90600160401b90046001600160401b0316826158d0565b8351611a96919061586a565b611aa0919061589f565b60416000828254611ab191906159ef565b9091555050604082015160428054600090611acd9084906159ef565b909155505060208201518251611ae7919088888888613d0c565b50600180559695505050505050565b603d54600160c81b900460ff1615611b21576040516313d0ff5960e31b815260040160405180910390fd5b6033546040516333b52a9f60e11b81526001600160a01b039091169063676a553e90611b51903390600401614ee0565b602060405180830381865afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9291906158b3565b611baf5760405163027f480760e01b815260040160405180910390fd5b603c54600090600160c01b90046001600160401b0316821015611bed57603c54611bea908390600160c01b90046001600160401b03166158d0565b90505b603c54600090600160801b90046001600160401b0316841115611c2a57603c54611c2790600160801b90046001600160401b0316856158d0565b90505b6000611c3b6002633b9aca00615b1f565b611c4983633b9aca006158d0565b611c5785633b9aca006158d0565b611c61908961586a565b611c6b919061586a565b611c75919061589f565b9050611c8181876158d0565b60416000828254611c9291906159ef565b90915550611ca4905087826000613bdd565b5050505050505050565b607e80546108cb90615806565b611cc3614ea3565b60408051600080825260208201909252611ce5918791879187918791906125ec565b90505b949350505050565b610d58338383613e16565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611d2b903390600401614ee0565b602060405180830381865afa158015611d48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6c91906158b3565b611d8957604051632678482f60e21b815260040160405180910390fd5b60398190556040518181527fdd63b3dcdbebad734892f7c7a26d0f647fbc7eec973e0775f5229018ac4ab47a9060200160405180910390a150565b603d54600090600160c81b900460ff1615611df2576040516313d0ff5960e31b815260040160405180910390fd5b6108b882613ecc565b919050565b3382611e0c8282613444565b611e295760405163c19f17a960e01b815260040160405180910390fd5b611e3586868686613ffa565b505050505050565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611e6d903390600401614ee0565b602060405180830381865afa158015611e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eae91906158b3565b611ecb57604051632678482f60e21b815260040160405180910390fd5b603d805460ff60c81b198116600160c81b9182900460ff1615909102179055565b6060611ef782613368565b611f145760405163062a39dd60e11b815260040160405180910390fd5b8160005b8115611f3b57611f2781615a20565b9050611f34600a8361589f565b9150611f18565b6000816001600160401b03811115611f5557611f556150b3565b6040519080825280601f01601f191660200182016040528015611f7f576020820181803683370190505b5090505b8415611fea57611f946001836158d0565b9150611fa1600a86615b2e565b611fac9060306159ef565b60f81b818381518110611fc157611fc161592f565b60200101906001600160f81b031916908160001a905350611fe3600a8661589f565b9450611f83565b60468054611ff790615806565b151590506120145760405180602001604052806000815250612038565b604681604051602001612028929190615b5e565b6040516020818303038152906040525b95945050505050565b600054610100900460ff16158080156120615750600054600160ff909116105b80612082575061207030613359565b158015612082575060005460ff166001145b6120e55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161159f565b6000805460ff191660011790558015612108576000805461ff0019166101001790555b856001600160a01b0316846001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612150573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121749190615912565b6001600160a01b03161461219b576040516302979eb960e31b815260040160405180910390fd5b603380546001600160a01b038089166001600160a01b0319928316179092556034805492881692909116821790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015612204573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122289190615bfc565b61223390600a615b1f565b603881905550856001600160a01b031663e9cbd8226040518163ffffffff1660e01b8152600401602060405180830381865afa158015612277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229b9190615912565b603580546001600160a01b03199081166001600160a01b0393841617909155603680549091169186169190911790556040516000906122de908490602001615c19565b60408051601f19818403018152919052805190915061230490607d906020840190614de5565b5061230e81614034565b8260405160200161231f9190615c60565b604051602081830303815290604052607e9080519060200190612343929190614de5565b50676765c793fa10079d601b1b603f5542603e5561236760a0850160808601615c8a565b6001600160401b03166123806040860160208701615c8a565b6001600160401b031611806123b05750633b9aca006123a560a0860160808701615c8a565b6001600160401b0316115b806123d657506123c66060850160408601615c8a565b6001600160401b0316633b9aca00115b806123fd5750633b9aca006123f160c0860160a08701615c8a565b6001600160401b031610155b8061240a575060e0840135155b1561242857604051631746545d60e11b815260040160405180910390fd5b833560395561243d6040850160208601615c8a565b603c80546001600160401b0319166001600160401b039290921691909117905561246d6060850160408601615c8a565b603c80546001600160401b0392909216600160401b02600160401b600160801b03199092169190911790556124a86080850160608601615c8a565b603d80546001600160401b0319166001600160401b03929092169190911790556124d860a0850160808601615c8a565b603d80546001600160401b0392909216600160401b02600160401b600160801b031990921691909117905561251360c0850160a08601615c8a565b603d80546001600160401b0392909216600160801b02600160801b600160c01b031990921691909117905561254e60e0850160c08601615ca5565b603d8054911515600160c01b0260ff60c01b19909216919091179055604080516020810190915260e0850135815261258a90603b906001614e69565b5050603d805460ff60c81b1916600160c81b1790558015611e35576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6125f4614ea3565b603d54600160c81b900460ff161561261f576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156126425760405162461bcd60e51b815260040161159f906159a5565b60026001558551875114158061265757508651155b15612675576040516346282e8d60e01b815260040160405180910390fd5b6000806000806000805b8c51811015612bdc5760008d828151811061269c5761269c61592f565b60200260200101519050600060078111156126b9576126b9615cc2565b8160078111156126cb576126cb615cc2565b141561270c576127068d83815181106126e6576126e661592f565b60200260200101518060200190518101906127019190615912565b613ecc565b50612bcb565b600281600781111561272057612720615cc2565b1415612786578c82815181106127385761273861592f565b60200260200101518060200190518101906127539190615cd8565b95509250826127625760455492505b61276c838661410a565b848860600181815161277e91906159ef565b905250612bcb565b600781600781111561279a5761279a615cc2565b14156128735760008060008f85815181106127b7576127b761592f565b60200260200101518060200190518101906127d29190615cfc565b60345460405163d505accf60e01b81526001600160a01b038089166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c48201849052969f50939d50939b509497509550929350169063d505accf9060e401600060405180830381600087803b15801561285357600080fd5b505af1158015612867573d6000803e3d6000fd5b50505050505050612bcb565b8661288357612880613b3c565b96505b600481600781111561289757612897615cc2565b1415612963578c82815181106128af576128af61592f565b60200260200101518060200190518101906128ca9190615cd8565b94509250826128d95760455492505b6128e4838589613bdd565b603c5490945060009061290b90600160c01b90046001600160401b0316633b9aca006158d0565b612919633b9aca008761586a565b612923919061589f565b905061292f85826158d0565b6041600082825461294091906159ef565b92505081905550808960200181815161295991906159ef565b905250612bcb9050565b856129e257603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129df919061583b565b95505b60018160078111156129f6576129f6615cc2565b1415612a72578c8281518110612a0e57612a0e61592f565b6020026020010151806020019051810190612a29919061583b565b925082612a365760455492505b612a41838789614176565b80965081955050508488604001818151612a5b91906159ef565b90525060208801805185919061277e9083906159ef565b6003816007811115612a8657612a86615cc2565b1415612ae6578c8281518110612a9e57612a9e61592f565b6020026020010151806020019051810190612ab99190615cd8565b9550925082612ac85760455492505b612ad48386888a614296565b848860400181815161277e91906159ef565b6005816007811115612afa57612afa615cc2565b1415612b5c578c8281518110612b1257612b1261592f565b6020026020010151806020019051810190612b2d9190615cd8565b9450925082612b3c5760455492505b612b488385888a614370565b9350838860000181815161277e91906159ef565b6006816007811115612b7057612b70615cc2565b1415612bcb576000808e8481518110612b8b57612b8b61592f565b6020026020010151806020019051810190612ba69190615d4f565b98509196509250905084612bba5760455494505b612bc8858383898c8e61440b565b50505b50612bd581615a20565b905061267f565b508551602087015110612cd35785516020870151600091612bfc916158d0565b90508660600151876040015110612c3357612c2e87606001518860400151612c2491906158d0565b828d8d8d8d613d0c565b612ccd565b8015612ca057603554604051630d43af8160e21b81526001600160a01b039091169063350ebe0490612c6d9084908f903390600401615d8d565b600060405180830381600087803b158015612c8757600080fd5b505af1158015612c9b573d6000803e3d6000fd5b505050505b612ccd333089604001518a60600151612cb991906158d0565b6034546001600160a01b0316929190614547565b50612e5f565b60208601518651600091612ce6916158d0565b6035546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990612d19908d908590600401615dac565b600060405180830381600087803b158015612d3357600080fd5b505af1158015612d47573d6000803e3d6000fd5b50505050866060015187604001511115612d8b57612d868a88606001518960400151612d7391906158d0565b6034546001600160a01b031691906145b2565b612e5d565b600087604001518860600151612da191906158d0565b90508015612e5b57885115612e4357896001600160a01b031663a5d4096b603560009054906101000a90046001600160a01b0316603460009054906101000a90046001600160a01b03163385878f6040518763ffffffff1660e01b8152600401612e1096959493929190615dc5565b600060405180830381600087803b158015612e2a57600080fd5b505af1158015612e3e573d6000803e3d6000fd5b505050505b603454612e5b906001600160a01b0316333084614547565b505b505b505060018055509198975050505050505050565b603a8181548110610c7f57600080fd5b6001600160a01b039182166000908152604a6020908152604080832093909416825291909152205460011490565b6033546001600160a01b03163314612edc5760405163b90cdbb160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0383811691909117909155603654604051630787a21360e51b815291169063f0f4426090612f23908490600401614ee0565b600060405180830381600087803b158015612f3d57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b83421115612f725760405163f87d927160e01b815260040160405180910390fd5b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03811180612fa957508260ff16601b14158015612fa957508260ff16601c14155b15612fc757604051638baa579f60e01b815260040160405180910390fd5b6000612fd1613ad0565b608254898989612fe08d6145d1565b6040805160208101969096526001600160a01b03948516908601529290911660608401521515608083015260a082015260c0810187905260e0016040516020818303038152906040528051906020012060405160200161305792919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050613081886001600160a01b0316613359565b1561315d57604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b038a1691631626ba7e916130e7918591606501615e07565b602060405180830381865afa158015613104573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131289190615e20565b6001600160e01b031916631626ba7e60e01b1461315857604051638baa579f60e01b815260040160405180910390fd5b613205565b6040805160008082526020820180845284905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156131b1573d6000803e3d6000fd5b505050602060405103519050886001600160a01b0316816001600160a01b03161415806131e557506001600160a01b038116155b1561320357604051638baa579f60e01b815260040160405180910390fd5b505b611ca4888888613e16565b613218614db6565b60408051600080825260208201909252611ce591879187918791879190611549565b60335460009081906001600160a01b0316331461326a5760405163b90cdbb160e01b815260040160405180910390fd5b613272613b3c565b50506041805460428054600093849055929055915080821061330b5761329881836158d0565b6035546033546040516340c10f1960e01b8152929450600093506001600160a01b03918216926340c10f19926132d49216908690600401615dac565b600060405180830381600087803b1580156132ee57600080fd5b505af1158015613302573d6000803e3d6000fd5b5050505061331c565b61331582826158d0565b9050600091505b60408051838152602081018390527ffeb12225c131aab793a00c5239afb778932d170fa28ce6e9d23703e4bd892121910160405180910390a19091565b6001600160a01b03163b151590565b6000908152604760205260409020546001600160a01b0316151590565b6000908152604960205260409020546001600160a01b031690565b6000818152604760205260409020546001600160a01b031680611dfb5760405163062a39dd60e11b815260040160405180910390fd5b600081815260496020526040902080546001600160a01b0319166001600160a01b038416908117909155819061340b826133a0565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080613450836133a0565b9050806001600160a01b0316846001600160a01b0316148061348b5750836001600160a01b031661348084613385565b6001600160a01b0316145b80611ce857506001600160a01b038082166000908152604a6020908152604080832093881683529290522054600114949350505050565b826001600160a01b03166134d5826133a0565b6001600160a01b0316146134fc5760405163c19f17a960e01b815260040160405180910390fd5b6001600160a01b0382166135235760405163d92e233d60e01b815260040160405180910390fd5b603d54600160c01b900460ff16801561355557506001600160a01b038216600090815260446020526040902054600114155b1561357357604051630b094f2760e31b815260040160405180910390fd5b61357e6000826133d6565b6001600160a01b038084166000818152604860209081526040808320805460001901905593861680835284832080546001019055858352604790915283822080546001600160a01b03191682179055925184939291600080516020615ed783398151915291a4505050565b600080603e54426135fa91906158d0565b603d549091506001600160401b0316811580613614575080155b1561362357603f549250505090565b60006136306001846158d0565b905060006002841161364357600061364e565b61364e6002856158d0565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b613674868061586a565b61367e91906159ef565b613688919061589f565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b6136ae878561586a565b6136b891906159ef565b6136c2919061589f565b905060006002836136d3878a61586a565b6136dd919061586a565b6136e7919061589f565b90506000600683866136f9898c61586a565b613703919061586a565b61370d919061586a565b613717919061589f565b9050676765c793fa10079d601b1b81836137318b8b61586a565b61374690676765c793fa10079d601b1b6159ef565b61375091906159ef565b61375a91906159ef565b603f54613767919061586a565b613771919061589f565b9850505050505050505090565b613786614db6565b6000806000613796888787614615565b925092509250633b9aca0083106137c0576040516315fe9b6160e21b815260040160405180910390fd5b6000633b9aca006137d185826158d0565b6137da8a61469e565b6137e4919061586a565b6137ee919061589f565b603d54909150600160801b90046001600160401b031681101561381e5761381981633b9aca006158d0565b61383f565b603d5461383f90600160801b90046001600160401b0316633b9aca006158d0565b603d54909150600160401b90046001600160401b03166000806138676002633b9aca00615b1f565b603c5461387d91906001600160401b031661586a565b83613888868a61586a565b613892919061586a565b10613a1b57603c546001600160401b03166138b26002633b9aca00615b1f565b6138bc919061586a565b603c5485906138db90600160401b90046001600160401b03168661586a565b6138e5919061586a565b6138ef91906158d0565b603c548590633b9aca009061390d906001600160401b03168961586a565b603c5461392b908b90600160401b90046001600160401b031661586a565b61393591906158d0565b61393f919061586a565b613949919061586a565b613953919061589f565b9150633b9aca0060b454613967919061586a565b613971848461586a565b61397b91906159ef565b613989633b9aca008861586a565b11613a16576139a3676765c793fa10079d601b1b8461586a565b633b9aca008a8e602001516139b8919061586a565b6139c2919061586a565b6139cc919061589f565b6139d79060016159ef565b915060b454861115613a125782633b9aca0060b454886139f791906158d0565b613a01919061586a565b613a0b919061589f565b9050613a7e565b5060015b613a7e565b603854613a2c90633b9aca0061586a565b8c518b90613a3b90879061586a565b613a45919061586a565b613a4f919061589f565b613a5a9060016159ef565b915060b554851115613a7a57633b9aca008460b554876139f791906158d0565b5060015b818852613a8b848b61586a565b603854613a9c633b9aca008561586a565b613aa6919061586a565b613ab0919061589f565b602089015260408801525050606085015250608083015250949350505050565b60808054608154604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082015290810192909252606082015246918101919091523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6000613b466135e9565b90506000676765c793fa10079d601b1b603f5483613b6491906158d0565b604054613b71919061586a565b613b7b919061589f565b90508060416000828254613b8f91906159ef565b9091555050603f82905542603e8190556040805184815260208101929092527fd1fa8ba00a3bf20274346919dce0de62d2a140af2c71fe7e29fa6472eea3bb9d910160405180910390a15090565b600081613bef57613bec613b3c565b91505b60008481526043602052604081206001015490676765c793fa10079d601b1b613c18858461586a565b613c22919061589f565b9050808510613c3357935080613c56565b83613c49676765c793fa10079d601b1b8761586a565b613c53919061589f565b90505b613c6081836158d0565b91508060406000828254613c7491906158d0565b90915550508115801590613ca95750676765c793fa10079d601b1b60b454613c9c919061586a565b613ca6858461586a565b11155b15613cc75760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604080822060010184905551600080516020615e9783398151915291613cfa9189918591615a07565b60405180910390a15092949350505050565b8515613d2957603454613d29906001600160a01b031684886145b2565b8415611e3557805115613da85760345460355460405163a5d4096b60e01b81526001600160a01b038086169363a5d4096b93613d759391831692169089908b908d908990600401615dc5565b600060405180830381600087803b158015613d8f57600080fd5b505af1158015613da3573d6000803e3d6000fd5b505050505b603554604051630d43af8160e21b81526001600160a01b039091169063350ebe0490613ddc90889088903390600401615d8d565b600060405180830381600087803b158015613df657600080fd5b505af1158015613e0a573d6000803e3d6000fd5b50505050505050505050565b826001600160a01b0316826001600160a01b03161415613e49576040516320c5195360e21b815260040160405180910390fd5b600081613e57576000613e5a565b60015b6001600160a01b038581166000818152604a602090815260408083209489168084529482529182902060ff959095169485905590518615158152939450919290917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b603d54600090600160c01b900460ff168015613f1b57506001600160a01b0382166000908152604460205260409020546001141580613f1b575033600090815260446020526040902054600114155b15613f3957604051630b094f2760e31b815260040160405180910390fd5b6001600160a01b038216613f605760405163d92e233d60e01b815260040160405180910390fd5b5060458054600101908190556001600160a01b038216600081815260486020908152604080832080546001019055848352604790915280822080546001600160a01b031916841790555183929190600080516020615ed7833981519152908290a4613fdd60008383604051806020016040528060008152506148cd565b611dfb576040516320149b4360e21b815260040160405180910390fd5b6140058484846134c2565b614011848484846148cd565b61402e576040516320149b4360e21b815260040160405180910390fd5b50505050565b600054610100900460ff1661409f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161159f565b7f3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd860825580516020918201206080556040805180820190915260018152603160f81b9101527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6608155565b61411382613368565b6141305760405163062a39dd60e11b815260040160405180910390fd5b6000828152604360205260408120805483929061414e9084906159ef565b9091555050604051600080516020615eb7833981519152906112059084908490600190615a07565b60008033856141858282613444565b6141a25760405163c19f17a960e01b815260040160405180910390fd5b6000878152604360209081526040808320815180830190925280548252600101549181019190915290806141d7838a8a614615565b5091509150633b9aca00821161420057604051631527804d60e31b815260040160405180910390fd5b82602001516040600082825461421691906158d0565b9091555061422590508a6149d0565b603c5460009061424990600160c01b90046001600160401b0316633b9aca006158d0565b614257633b9aca008461586a565b614261919061589f565b905061426d82826158d0565b6041600082825461427e91906159ef565b90915550509251929a92995091975050505050505050565b33846142a28282613444565b6142bf5760405163c19f17a960e01b815260040160405180910390fd5b600086815260436020526040812080548792906142dd9084906158d0565b909155505060008681526043602090815260408083208151808301909252805482526001015491810191909152614315908686614615565b50509050633b9aca00811161433d57604051631527804d60e31b815260040160405180910390fd5b600080516020615eb78339815191528787600060405161435f93929190615a07565b60405180910390a150505050505050565b6000338561437e8282613444565b61439b5760405163c19f17a960e01b815260040160405180910390fd5b6143a787878787614a4f565b603c54909650600090633b9aca00906143d1908990600160801b90046001600160401b031661586a565b6143db919061589f565b905080604160008282546143ef91906159ef565b909155506143ff905081886158d0565b98975050505050505050565b33866144178282613444565b6144345760405163c19f17a960e01b815260040160405180910390fd5b60408051898152602081018890526001600160a01b038916818301526060810187905290517fddd3b70af631334f7552aadb582ed091018e62e103fa8b150ca66cc700d4dac69181900360800190a161448f88868686614a4f565b94506001600160a01b0387163014156144b3576144ad868685613bdd565b50611ca4565b603c546040516320d661ad60e21b815260048101889052602481018790526001600160401b03600160801b830481166044830152600160c01b90920490911660648201526001600160a01b0388169063835986b490608401600060405180830381600087803b15801561452557600080fd5b505af1158015614539573d6000803e3d6000fd5b505050505050505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261402e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614be2565b610a058363a9059cbb60e01b848460405160240161457b929190615dac565b6001600160a01b0381166000908152607f60205260409020546145f58160016159ef565b6001600160a01b039092166000908152607f602052604090209190915590565b6000806000676765c793fa10079d601b1b848760200151614636919061586a565b614640919061589f565b9150603854858760000151614655919061586a565b61465f919061589f565b905081614670576000199250614695565b603c548290614688906001600160401b03168361586a565b614692919061589f565b92505b93509350939050565b6037546000906001600160a01b03166146d757603b6000815481106146c5576146c561592f565b90600052602060002001549050919050565b603754604051635dfba04560e11b81526000916001600160a01b03169063bbf7408a90614708908690600401614ee0565b602060405180830381865afa158015614725573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614749919061583b565b9050603a60018154811061475f5761475f61592f565b9060005260206000200154811061479757603b6001815481106147845761478461592f565b9060005260206000200154915050919050565b603a6000815481106147ab576147ab61592f565b906000526020600020015481116147d057603b6000815481106147845761478461592f565b603a6000815481106147e4576147e461592f565b9060005260206000200154603a6001815481106148035761480361592f565b906000526020600020015461481891906158d0565b603a60008154811061482c5761482c61592f565b90600052602060002001548261484291906158d0565b603b6000815481106148565761485661592f565b9060005260206000200154603b6001815481106148755761487561592f565b906000526020600020015461488a91906158d0565b614894919061586a565b61489e919061589f565b603b6000815481106148b2576148b261592f565b9060005260206000200154610af091906159ef565b50919050565b60006148e1846001600160a01b0316613359565b156149c857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614918903390899088908890600401615e3d565b6020604051808303816000875af1925050508015614953575060408051601f3d908101601f1916820190925261495091810190615e20565b60015b6149ae573d808015614981576040519150601f19603f3d011682016040523d82523d6000602084013e614986565b606091505b5080516149a6576040516320149b4360e21b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611ce8565b506001611ce8565b60006149db826133a0565b90506149e86000836133d6565b6001600160a01b038116600081815260486020908152604080832080546000190190558583526047825280832080546001600160a01b0319169055604390915280822082815560010182905551849290600080516020615ed7833981519152908390a45050565b60008082614a68676765c793fa10079d601b1b8761586a565b614a72919061589f565b600087815260436020526040902060010154909150614aad5760b4548511614aad5760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604081206001018054839290614ace9084906159ef565b925050819055508060406000828254614ae791906159ef565b9091555050603954614b0590676765c793fa10079d601b1b9061586a565b83604054614b13919061586a565b1115614b32576040516371239a6160e11b815260040160405180910390fd5b60008681526043602090815260408083208151808301909252805482526001015491810191909152614b65908686614615565b50509050633b9aca008111614b8d57604051631527804d60e31b815260040160405180910390fd5b600080516020615e9783398151915287836001604051614baf93929190615a07565b60405180910390a1676765c793fa10079d601b1b614bcd858461586a565b614bd7919061589f565b979650505050505050565b6000614c37826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cb49092919063ffffffff16565b805190915015610a055780806020019051810190614c5591906158b3565b610a055760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161159f565b6060611ce8848460008585614cc885613359565b614d145760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161159f565b600080866001600160a01b03168587604051614d309190615e7a565b60006040518083038185875af1925050503d8060008114614d6d576040519150601f19603f3d011682016040523d82523d6000602084013e614d72565b606091505b5091509150614bd782828660608315614d8c575081610af0565b825115614d9c5782518084602001fd5b8160405162461bcd60e51b815260040161159f9190614f7f565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054614df190615806565b90600052602060002090601f016020900481019282614e135760008555614e59565b82601f10614e2c57805160ff1916838001178555614e59565b82800160010185558215614e59579182015b82811115614e59578251825591602001919060010190614e3e565b50614e65929150614ecb565b5090565b828054828255906000526020600020908101928215614e595791602002820182811115614e59578251825591602001919060010190614e3e565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b5b80821115614e655760008155600101614ecc565b6001600160a01b0391909116815260200190565b6001600160e01b031981168114610c6c57600080fd5b600060208284031215614f1c57600080fd5b8135610af081614ef4565b60005b83811015614f42578181015183820152602001614f2a565b8381111561402e5750506000910152565b60008151808452614f6b816020860160208601614f27565b601f01601f19169290920160200192915050565b602081526000610af06020830184614f53565b600060208284031215614fa457600080fd5b5035919050565b6001600160a01b0381168114610c6c57600080fd5b60008060408385031215614fd357600080fd5b8235614fde81614fab565b946020939093013593505050565b60008060006060848603121561500157600080fd5b833561500c81614fab565b9250602084013561501c81614fab565b929592945050506040919091013590565b6000806040838503121561504057600080fd5b82359150602083013561505281614fab565b809150509250929050565b60a081016108b8828480518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b6000602082840312156150a857600080fd5b8135610af081614fab565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150f1576150f16150b3565b604052919050565b600082601f83011261510a57600080fd5b81356001600160401b03811115615123576151236150b3565b615136601f8201601f19166020016150c9565b81815284602083860101111561514b57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561517a57600080fd5b81356001600160401b0381111561519057600080fd5b611ce8848285016150f9565b600080604083850312156151af57600080fd5b50508035926020909101359150565b80356001600160401b0381168114611dfb57600080fd5b600080604083850312156151e857600080fd5b614fde836151be565b60006001600160401b0382111561520a5761520a6150b3565b5060051b60200190565b600082601f83011261522557600080fd5b8135602061523a615235836151f1565b6150c9565b82815260059290921b8401810191818101908684111561525957600080fd5b8286015b84811015615274578035835291830191830161525d565b509695505050505050565b60008060006060848603121561529457600080fd5b833561529f81614fab565b925060208401356001600160401b03808211156152bb57600080fd5b6152c787838801615214565b935060408601359150808211156152dd57600080fd5b506152ea86828701615214565b9150509250925092565b60008060008060008060c0878903121561530d57600080fd5b86356001600160401b038082111561532457600080fd5b6153308a838b01615214565b9750602089013591508082111561534657600080fd5b6153528a838b01615214565b96506040890135915061536482614fab565b90945060608801359061537682614fab565b90935060808801359061538882614fab565b90925060a0880135908082111561539e57600080fd5b506153ab89828a016150f9565b9150509295509295509295565b600080600080608085870312156153ce57600080fd5b5050823594602084013594506040840135936060013592509050565b600082601f8301126153fb57600080fd5b8135602061540b615235836151f1565b82815260059290921b8401810191818101908684111561542a57600080fd5b8286015b84811015615274578035600881106154465760008081fd5b835291830191830161542e565b600082601f83011261546457600080fd5b81356020615474615235836151f1565b82815260059290921b8401810191818101908684111561549357600080fd5b8286015b848110156152745780356001600160401b038111156154b65760008081fd5b6154c48986838b01016150f9565b845250918301918301615497565b600080600080608085870312156154e857600080fd5b84356001600160401b03808211156154ff57600080fd5b61550b888389016153ea565b9550602087013591508082111561552157600080fd5b5061552e87828801615453565b935050604085013561553f81614fab565b9150606085013561554f81614fab565b939692955090935050565b8015158114610c6c57600080fd5b6000806040838503121561557b57600080fd5b823561558681614fab565b915060208301356150528161555a565b600080600080608085870312156155ac57600080fd5b84356155b781614fab565b935060208501356155c781614fab565b92506040850135915060608501356001600160401b038111156155e957600080fd5b6155f5878288016150f9565b91505092959194509250565b600080600080600085870361018081121561561b57600080fd5b863561562681614fab565b9550602087013561563681614fab565b9450604087013561564681614fab565b9350610100605f198201121561565b57600080fd5b506060860191506101608601356001600160401b0381111561567c57600080fd5b615688888289016150f9565b9150509295509295909350565b60008060008060008060c087890312156156ae57600080fd5b86356001600160401b03808211156156c557600080fd5b6156d18a838b016153ea565b975060208901359150808211156156e757600080fd5b6153528a838b01615453565b6000806040838503121561570657600080fd5b823561571181614fab565b9150602083013561505281614fab565b60ff81168114610c6c57600080fd5b600080600080600080600060e0888a03121561574b57600080fd5b873561575681614fab565b9650602088013561576681614fab565b955060408801356157768161555a565b945060608801359350608088013561578d81615721565b9699959850939692959460a0840135945060c09093013592915050565b600080600080608085870312156157c057600080fd5b84356001600160401b03808211156157d757600080fd5b6157e388838901615214565b955060208701359150808211156157f957600080fd5b5061552e87828801615214565b600181811c9082168061581a57607f821691505b602082108114156148c757634e487b7160e01b600052602260045260246000fd5b60006020828403121561584d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561588457615884615854565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826158ae576158ae615889565b500490565b6000602082840312156158c557600080fd5b8151610af08161555a565b6000828210156158e2576158e2615854565b500390565b60006001600160401b0382811684821680830382111561590957615909615854565b01949350505050565b60006020828403121561592457600080fd5b8151610af081614fab565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b8381101561597557815187529582019590820190600101615959565b509495945050505050565b6040815260006159936040830185615945565b82810360208401526120388185615945565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b602081526000610af06020830184615945565b60008219821115615a0257615a02615854565b500190565b928352602083019190915260ff16604082015260600190565b6000600019821415615a3457615a34615854565b5060010190565b600181815b80851115615a76578160001904821115615a5c57615a5c615854565b80851615615a6957918102915b93841c9390800290615a40565b509250929050565b600082615a8d575060016108b8565b81615a9a575060006108b8565b8160018114615ab05760028114615aba57615ad6565b60019150506108b8565b60ff841115615acb57615acb615854565b50506001821b6108b8565b5060208310610133831016604e8410600b8410161715615af9575081810a6108b8565b615b038383615a3b565b8060001904821115615b1757615b17615854565b029392505050565b6000610af060ff841683615a7e565b600082615b3d57615b3d615889565b500690565b60008151615b54818560208601614f27565b9290920192915050565b600080845481600182811c915080831680615b7a57607f831692505b6020808410821415615b9a57634e487b7160e01b86526022600452602486fd5b818015615bae5760018114615bbf57615bec565b60ff19861689528489019650615bec565b60008b81526020902060005b86811015615be45781548b820152908501908301615bcb565b505084890196505b5050505050506120388185615b42565b600060208284031215615c0e57600080fd5b8151610af081615721565b6e020b733b63290283937ba37b1b7b61608d1b815260008251615c4381600f850160208701614f27565b650815985d5b1d60d21b600f939091019283015250601501919050565b60008251615c72818460208701614f27565b650b5d985d5b1d60d21b920191825250600601919050565b600060208284031215615c9c57600080fd5b610af0826151be565b600060208284031215615cb757600080fd5b8135610af08161555a565b634e487b7160e01b600052602160045260246000fd5b60008060408385031215615ceb57600080fd5b505080516020909101519092909150565b60008060008060008060c08789031215615d1557600080fd5b8651615d2081614fab565b6020880151604089015160608a015160808b015160a0909b0151939c929b509099909850965090945092505050565b60008060008060808587031215615d6557600080fd5b845193506020850151615d7781614fab565b6040860151606090960151949790965092505050565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a082018190526000906143ff90830184614f53565b828152604060208201526000611ce86040830184614f53565b600060208284031215615e3257600080fd5b8151610af081614ef4565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e7090830184614f53565b9695505050505050565b60008251615e8c818460208701614f27565b919091019291505056fe70cf49afe7355562d5b022e594790f22b71ad8cc7eec902fa5feac7c67f71091722cb71fa87c947148cefc06dd890af5802a6a00207c5ddecf1191bf71ce3cd4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122004adf5a8fe3c52a612a81111fd6100f9eeb84fbeb3cfcc411a5bf2e9a14a72cb64736f6c634300080c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.