Note: Our ether balance display is temporarily unavailable. Please check back later.
Source Code
Overview
ETH Balance
Ether balance is temporarily unavailable. Please check back later.
More Info
ContractCreator
Multichain Info
N/A
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 7270642 | 615 days ago | IN | Create: PositionsManager | 0 ETH | 0.01482725 |
Loading...
Loading
Contract Name:
PositionsManager
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity 0.8.13; import "./interfaces/IPositionsManager.sol"; import "./interfaces/IWETH.sol"; import "./MatchingEngine.sol"; /// @title PositionsManager. /// @author Morpho Labs. /// @custom:contact [email protected] /// @notice Main Logic of Morpho Protocol, implementation of the 5 main functionalities: supply, borrow, withdraw, repay and liquidate. contract PositionsManager is IPositionsManager, MatchingEngine { using DoubleLinkedList for DoubleLinkedList.List; using SafeTransferLib for ERC20; using CompoundMath for uint256; /// EVENTS /// /// @notice Emitted when a supply happens. /// @param _supplier The address of the account sending funds. /// @param _onBehalf The address of the account whose positions will be updated. /// @param _poolTokenAddress The address of the market where assets are supplied into. /// @param _amount The amount of assets supplied (in underlying). /// @param _balanceOnPool The supply balance on pool after update. /// @param _balanceInP2P The supply balance in peer-to-peer after update. event Supplied( address indexed _supplier, address indexed _onBehalf, address indexed _poolTokenAddress, uint256 _amount, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// @notice Emitted when a borrow happens. /// @param _borrower The address of the borrower. /// @param _poolTokenAddress The address of the market where assets are borrowed. /// @param _amount The amount of assets borrowed (in underlying). /// @param _balanceOnPool The borrow balance on pool after update. /// @param _balanceInP2P The borrow balance in peer-to-peer after update event Borrowed( address indexed _borrower, address indexed _poolTokenAddress, uint256 _amount, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// @notice Emitted when a withdrawal happens. /// @param _supplier The address of the supplier whose supply is withdrawn. /// @param _receiver The address receiving the tokens. /// @param _poolTokenAddress The address of the market from where assets are withdrawn. /// @param _amount The amount of assets withdrawn (in underlying). /// @param _balanceOnPool The supply balance on pool after update. /// @param _balanceInP2P The supply balance in peer-to-peer after update. event Withdrawn( address indexed _supplier, address indexed _receiver, address indexed _poolTokenAddress, uint256 _amount, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// @notice Emitted when a repayment happens. /// @param _repayer The address of the account repaying the debt. /// @param _onBehalf The address of the account whose debt is repaid. /// @param _poolTokenAddress The address of the market where assets are repaid. /// @param _amount The amount of assets repaid (in underlying). /// @param _balanceOnPool The borrow balance on pool after update. /// @param _balanceInP2P The borrow balance in peer-to-peer after update. event Repaid( address indexed _repayer, address indexed _onBehalf, address indexed _poolTokenAddress, uint256 _amount, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// @notice Emitted when a liquidation happens. /// @param _liquidator The address of the liquidator. /// @param _liquidated The address of the liquidated. /// @param _poolTokenBorrowedAddress The address of the borrowed asset. /// @param _amountRepaid The amount of borrowed asset repaid (in underlying). /// @param _poolTokenCollateralAddress The address of the collateral asset seized. /// @param _amountSeized The amount of collateral asset seized (in underlying). event Liquidated( address _liquidator, address indexed _liquidated, address indexed _poolTokenBorrowedAddress, uint256 _amountRepaid, address indexed _poolTokenCollateralAddress, uint256 _amountSeized ); /// @notice Emitted when the borrow peer-to-peer delta is updated. /// @param _poolTokenAddress The address of the market. /// @param _p2pBorrowDelta The borrow peer-to-peer delta after update. event P2PBorrowDeltaUpdated(address indexed _poolTokenAddress, uint256 _p2pBorrowDelta); /// @notice Emitted when the supply peer-to-peer delta is updated. /// @param _poolTokenAddress The address of the market. /// @param _p2pSupplyDelta The supply peer-to-peer delta after update. event P2PSupplyDeltaUpdated(address indexed _poolTokenAddress, uint256 _p2pSupplyDelta); /// @notice Emitted when the supply and borrow peer-to-peer amounts are updated. /// @param _poolTokenAddress The address of the market. /// @param _p2pSupplyAmount The supply peer-to-peer amount after update. /// @param _p2pBorrowAmount The borrow peer-to-peer amount after update. event P2PAmountsUpdated( address indexed _poolTokenAddress, uint256 _p2pSupplyAmount, uint256 _p2pBorrowAmount ); /// ERRORS /// /// @notice Thrown when the amount repaid during the liquidation is above what is allowed to be repaid. error AmountAboveWhatAllowedToRepay(); /// @notice Thrown when the borrow on Compound failed. error BorrowOnCompoundFailed(); /// @notice Thrown when the redeem on Compound failed . error RedeemOnCompoundFailed(); /// @notice Thrown when the repay on Compound failed. error RepayOnCompoundFailed(); /// @notice Thrown when the mint on Compound failed. error MintOnCompoundFailed(); /// @notice Thrown when user is not a member of the market. error UserNotMemberOfMarket(); /// @notice Thrown when the user does not have enough remaining collateral to withdraw. error UnauthorisedWithdraw(); /// @notice Thrown when the positions of the user is not liquidatable. error UnauthorisedLiquidate(); /// @notice Thrown when the user does not have enough collateral for the borrow. error UnauthorisedBorrow(); /// @notice Thrown when the amount desired for a withdrawal is too small. error WithdrawTooSmall(); /// @notice Thrown when the address is zero. error AddressIsZero(); /// @notice Thrown when the amount is equal to 0. error AmountIsZero(); /// @notice Thrown when a user tries to repay its debt after borrowing in the same block. error SameBlockBorrowRepay(); /// STRUCTS /// // Struct to avoid stack too deep. struct SupplyVars { uint256 remainingToSupply; uint256 poolBorrowIndex; uint256 toRepay; } // Struct to avoid stack too deep. struct WithdrawVars { uint256 remainingGasForMatching; uint256 remainingToWithdraw; uint256 poolSupplyIndex; uint256 p2pSupplyIndex; uint256 withdrawable; uint256 toWithdraw; ERC20 underlyingToken; } // Struct to avoid stack too deep. struct RepayVars { uint256 remainingGasForMatching; uint256 remainingToRepay; uint256 maxToRepayOnPool; uint256 poolBorrowIndex; uint256 p2pSupplyIndex; uint256 p2pBorrowIndex; uint256 borrowedOnPool; uint256 feeToRepay; uint256 toRepay; } // Struct to avoid stack too deep. struct LiquidateVars { uint256 collateralPrice; uint256 borrowBalance; uint256 supplyBalance; uint256 borrowedPrice; uint256 amountToSeize; } /// LOGIC /// /// @dev Implements supply logic. /// @param _poolTokenAddress The address of the pool token the user wants to interact with. /// @param _supplier The address of the account sending funds. /// @param _onBehalf The address of the account whose positions will be updated. /// @param _amount The amount of token (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function supplyLogic( address _poolTokenAddress, address _supplier, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching ) external { if (_onBehalf == address(0)) revert AddressIsZero(); if (_amount == 0) revert AmountIsZero(); _updateP2PIndexes(_poolTokenAddress); _enterMarketIfNeeded(_poolTokenAddress, _onBehalf); ERC20 underlyingToken = _getUnderlying(_poolTokenAddress); underlyingToken.safeTransferFrom(_supplier, address(this), _amount); Types.Delta storage delta = deltas[_poolTokenAddress]; SupplyVars memory vars; vars.poolBorrowIndex = ICToken(_poolTokenAddress).borrowIndex(); vars.remainingToSupply = _amount; /// Supply in peer-to-peer /// // Match borrow peer-to-peer delta first if any. if (delta.p2pBorrowDelta > 0) { uint256 deltaInUnderlying = delta.p2pBorrowDelta.mul(vars.poolBorrowIndex); if (deltaInUnderlying > vars.remainingToSupply) { vars.toRepay += vars.remainingToSupply; delta.p2pBorrowDelta -= vars.remainingToSupply.div(vars.poolBorrowIndex); vars.remainingToSupply = 0; } else { vars.toRepay += deltaInUnderlying; delta.p2pBorrowDelta = 0; vars.remainingToSupply -= deltaInUnderlying; } emit P2PBorrowDeltaUpdated(_poolTokenAddress, delta.p2pBorrowDelta); } // Match pool borrowers if any. if ( vars.remainingToSupply > 0 && !p2pDisabled[_poolTokenAddress] && borrowersOnPool[_poolTokenAddress].getHead() != address(0) ) { (uint256 matched, ) = _matchBorrowers( _poolTokenAddress, vars.remainingToSupply, _maxGasForMatching ); // In underlying. if (matched > 0) { vars.toRepay += matched; vars.remainingToSupply -= matched; delta.p2pBorrowAmount += matched.div(p2pBorrowIndex[_poolTokenAddress]); } } if (vars.toRepay > 0) { uint256 toAddInP2P = vars.toRepay.div(p2pSupplyIndex[_poolTokenAddress]); delta.p2pSupplyAmount += toAddInP2P; supplyBalanceInOf[_poolTokenAddress][_onBehalf].inP2P += toAddInP2P; _repayToPool(_poolTokenAddress, underlyingToken, vars.toRepay); // Reverts on error. emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); } /// Supply on pool /// if (vars.remainingToSupply > 0) { supplyBalanceInOf[_poolTokenAddress][_onBehalf].onPool += vars.remainingToSupply.div( ICToken(_poolTokenAddress).exchangeRateStored() // Exchange rate has already been updated. ); // In scaled balance. _supplyToPool(_poolTokenAddress, underlyingToken, vars.remainingToSupply); // Reverts on error. } _updateSupplierInDS(_poolTokenAddress, _onBehalf); emit Supplied( _supplier, _onBehalf, _poolTokenAddress, _amount, supplyBalanceInOf[_poolTokenAddress][_onBehalf].onPool, supplyBalanceInOf[_poolTokenAddress][_onBehalf].inP2P ); } /// @dev Implements borrow logic. /// @param _poolTokenAddress The address of the market the user wants to interact with. /// @param _amount The amount of token (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function borrowLogic( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) external { if (_amount == 0) revert AmountIsZero(); _updateP2PIndexes(_poolTokenAddress); _enterMarketIfNeeded(_poolTokenAddress, msg.sender); lastBorrowBlock[msg.sender] = block.number; if (_isLiquidatable(msg.sender, _poolTokenAddress, 0, _amount)) revert UnauthorisedBorrow(); ERC20 underlyingToken = _getUnderlying(_poolTokenAddress); uint256 remainingToBorrow = _amount; uint256 toWithdraw; Types.Delta storage delta = deltas[_poolTokenAddress]; uint256 poolSupplyIndex = ICToken(_poolTokenAddress).exchangeRateStored(); // Exchange rate has already been updated. uint256 withdrawable = ICToken(_poolTokenAddress).balanceOfUnderlying(address(this)); // The balance on pool. /// Borrow in peer-to-peer /// // Match supply peer-to-peer delta first if any. if (delta.p2pSupplyDelta > 0) { uint256 deltaInUnderlying = delta.p2pSupplyDelta.mul(poolSupplyIndex); if (deltaInUnderlying > remainingToBorrow || deltaInUnderlying > withdrawable) { uint256 matchedDelta = CompoundMath.min(remainingToBorrow, withdrawable); toWithdraw += matchedDelta; delta.p2pSupplyDelta -= matchedDelta.div(poolSupplyIndex); remainingToBorrow -= matchedDelta; } else { toWithdraw += deltaInUnderlying; delta.p2pSupplyDelta = 0; remainingToBorrow -= deltaInUnderlying; } emit P2PSupplyDeltaUpdated(_poolTokenAddress, delta.p2pSupplyDelta); } // Match pool suppliers if any. if ( remainingToBorrow > 0 && !p2pDisabled[_poolTokenAddress] && suppliersOnPool[_poolTokenAddress].getHead() != address(0) ) { (uint256 matched, ) = _matchSuppliers( _poolTokenAddress, CompoundMath.min(remainingToBorrow, withdrawable - toWithdraw), _maxGasForMatching ); // In underlying. if (matched > 0) { toWithdraw += matched; remainingToBorrow -= matched; deltas[_poolTokenAddress].p2pSupplyAmount += matched.div( p2pSupplyIndex[_poolTokenAddress] ); } } if (toWithdraw > 0) { uint256 toAddInP2P = toWithdraw.div(p2pBorrowIndex[_poolTokenAddress]); // In peer-to-peer unit. deltas[_poolTokenAddress].p2pBorrowAmount += toAddInP2P; borrowBalanceInOf[_poolTokenAddress][msg.sender].inP2P += toAddInP2P; emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); // If this value is equal to 0 the withdraw will revert on Compound. if (toWithdraw.div(poolSupplyIndex) > 0) _withdrawFromPool(_poolTokenAddress, toWithdraw); // Reverts on error. } /// Borrow on pool /// if (remainingToBorrow > 0) { borrowBalanceInOf[_poolTokenAddress][msg.sender].onPool += remainingToBorrow.div( ICToken(_poolTokenAddress).borrowIndex() ); // In cdUnit. _borrowFromPool(_poolTokenAddress, remainingToBorrow); } _updateBorrowerInDS(_poolTokenAddress, msg.sender); underlyingToken.safeTransfer(msg.sender, _amount); emit Borrowed( msg.sender, _poolTokenAddress, _amount, borrowBalanceInOf[_poolTokenAddress][msg.sender].onPool, borrowBalanceInOf[_poolTokenAddress][msg.sender].inP2P ); } /// @dev Implements withdraw logic with security checks. /// @param _poolTokenAddress The address of the market the user wants to interact with. /// @param _amount The amount of token (in underlying). /// @param _supplier The address of the supplier. /// @param _receiver The address of the user who will receive the tokens. /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function withdrawLogic( address _poolTokenAddress, uint256 _amount, address _supplier, address _receiver, uint256 _maxGasForMatching ) external { if (_amount == 0) revert AmountIsZero(); if (!userMembership[_poolTokenAddress][_supplier]) revert UserNotMemberOfMarket(); _updateP2PIndexes(_poolTokenAddress); uint256 toWithdraw = Math.min( _getUserSupplyBalanceInOf(_poolTokenAddress, _supplier), _amount ); if (_isLiquidatable(_supplier, _poolTokenAddress, toWithdraw, 0)) revert UnauthorisedWithdraw(); _safeWithdrawLogic(_poolTokenAddress, toWithdraw, _supplier, _receiver, _maxGasForMatching); } /// @dev Implements repay logic with security checks. /// @param _poolTokenAddress The address of the market the user wants to interact with. /// @param _repayer The address of the account repaying the debt. /// @param _onBehalf The address of the account whose debt is repaid. /// @param _amount The amount of token (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function repayLogic( address _poolTokenAddress, address _repayer, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching ) external { if (_amount == 0) revert AmountIsZero(); if (!userMembership[_poolTokenAddress][_onBehalf]) revert UserNotMemberOfMarket(); _updateP2PIndexes(_poolTokenAddress); uint256 toRepay = Math.min( _getUserBorrowBalanceInOf(_poolTokenAddress, _onBehalf), _amount ); _safeRepayLogic(_poolTokenAddress, _repayer, _onBehalf, toRepay, _maxGasForMatching); } /// @notice Liquidates a position. /// @param _poolTokenBorrowedAddress The address of the pool token the liquidator wants to repay. /// @param _poolTokenCollateralAddress The address of the collateral pool token the liquidator wants to seize. /// @param _borrower The address of the borrower to liquidate. /// @param _amount The amount of token (in underlying) to repay. function liquidateLogic( address _poolTokenBorrowedAddress, address _poolTokenCollateralAddress, address _borrower, uint256 _amount ) external { if ( !userMembership[_poolTokenBorrowedAddress][_borrower] || !userMembership[_poolTokenCollateralAddress][_borrower] ) revert UserNotMemberOfMarket(); _updateP2PIndexes(_poolTokenBorrowedAddress); _updateP2PIndexes(_poolTokenCollateralAddress); if (!_isLiquidatable(_borrower, address(0), 0, 0)) revert UnauthorisedLiquidate(); LiquidateVars memory vars; vars.borrowBalance = _getUserBorrowBalanceInOf(_poolTokenBorrowedAddress, _borrower); if (_amount > vars.borrowBalance.mul(comptroller.closeFactorMantissa())) revert AmountAboveWhatAllowedToRepay(); // Same mechanism as Compound. Liquidator cannot repay more than part of the debt (cf close factor on Compound). _safeRepayLogic(_poolTokenBorrowedAddress, msg.sender, _borrower, _amount, 0); ICompoundOracle compoundOracle = ICompoundOracle(comptroller.oracle()); vars.collateralPrice = compoundOracle.getUnderlyingPrice(_poolTokenCollateralAddress); vars.borrowedPrice = compoundOracle.getUnderlyingPrice(_poolTokenBorrowedAddress); if (vars.collateralPrice == 0 || vars.borrowedPrice == 0) revert CompoundOracleFailed(); // Compute the amount of collateral tokens to seize. This is the minimum between the repaid value plus the liquidation incentive and the available supply. vars.amountToSeize = Math.min( _amount.mul(comptroller.liquidationIncentiveMantissa()).mul(vars.borrowedPrice).div( vars.collateralPrice ), _getUserSupplyBalanceInOf(_poolTokenCollateralAddress, _borrower) ); _safeWithdrawLogic( _poolTokenCollateralAddress, vars.amountToSeize, _borrower, msg.sender, 0 ); emit Liquidated( msg.sender, _borrower, _poolTokenBorrowedAddress, _amount, _poolTokenCollateralAddress, vars.amountToSeize ); } /// INTERNAL /// /// @dev Implements withdraw logic without security checks. /// @param _poolTokenAddress The address of the market the user wants to interact with. /// @param _amount The amount of token (in underlying). /// @param _supplier The address of the supplier. /// @param _receiver The address of the user who will receive the tokens. /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function _safeWithdrawLogic( address _poolTokenAddress, uint256 _amount, address _supplier, address _receiver, uint256 _maxGasForMatching ) internal { if (_amount == 0) revert AmountIsZero(); WithdrawVars memory vars; vars.underlyingToken = _getUnderlying(_poolTokenAddress); vars.remainingToWithdraw = _amount; vars.remainingGasForMatching = _maxGasForMatching; vars.withdrawable = ICToken(_poolTokenAddress).balanceOfUnderlying(address(this)); vars.poolSupplyIndex = ICToken(_poolTokenAddress).exchangeRateStored(); // Exchange rate has already been updated. if (_amount.div(vars.poolSupplyIndex) == 0) revert WithdrawTooSmall(); /// Soft withdraw /// uint256 onPoolSupply = supplyBalanceInOf[_poolTokenAddress][_supplier].onPool; if (onPoolSupply > 0) { uint256 maxToWithdrawOnPool = onPoolSupply.mul(vars.poolSupplyIndex); if ( maxToWithdrawOnPool > vars.remainingToWithdraw || maxToWithdrawOnPool > vars.withdrawable ) { vars.toWithdraw = CompoundMath.min(vars.remainingToWithdraw, vars.withdrawable); vars.remainingToWithdraw -= vars.toWithdraw; supplyBalanceInOf[_poolTokenAddress][_supplier].onPool -= vars.toWithdraw.div( vars.poolSupplyIndex ); } else { vars.toWithdraw = maxToWithdrawOnPool; vars.remainingToWithdraw -= maxToWithdrawOnPool; supplyBalanceInOf[_poolTokenAddress][_supplier].onPool = 0; } if (vars.remainingToWithdraw == 0) { _updateSupplierInDS(_poolTokenAddress, _supplier); _leaveMarketIfNeeded(_poolTokenAddress, _supplier); // If this value is equal to 0 the withdraw will revert on Compound. if (vars.toWithdraw.div(vars.poolSupplyIndex) > 0) _withdrawFromPool(_poolTokenAddress, vars.toWithdraw); // Reverts on error. vars.underlyingToken.safeTransfer(_receiver, _amount); emit Withdrawn( _supplier, _receiver, _poolTokenAddress, _amount, supplyBalanceInOf[_poolTokenAddress][_supplier].onPool, supplyBalanceInOf[_poolTokenAddress][_supplier].inP2P ); return; } } Types.Delta storage delta = deltas[_poolTokenAddress]; vars.p2pSupplyIndex = p2pSupplyIndex[_poolTokenAddress]; supplyBalanceInOf[_poolTokenAddress][_supplier].inP2P -= CompoundMath.min( supplyBalanceInOf[_poolTokenAddress][_supplier].inP2P, vars.remainingToWithdraw.div(vars.p2pSupplyIndex) ); // In peer-to-peer unit _updateSupplierInDS(_poolTokenAddress, _supplier); /// Transfer withdraw /// // Reduce peer-to-peer supply delta first if any. if (vars.remainingToWithdraw > 0 && delta.p2pSupplyDelta > 0) { uint256 deltaInUnderlying = delta.p2pSupplyDelta.mul(vars.poolSupplyIndex); if ( deltaInUnderlying > vars.remainingToWithdraw || deltaInUnderlying > vars.withdrawable - vars.toWithdraw ) { uint256 matchedDelta = CompoundMath.min( vars.remainingToWithdraw, vars.withdrawable - vars.toWithdraw ); delta.p2pSupplyDelta -= matchedDelta.div(vars.poolSupplyIndex); delta.p2pSupplyAmount -= matchedDelta.div(vars.p2pSupplyIndex); vars.toWithdraw += matchedDelta; vars.remainingToWithdraw -= matchedDelta; } else { vars.toWithdraw += deltaInUnderlying; vars.remainingToWithdraw -= deltaInUnderlying; delta.p2pSupplyDelta = 0; delta.p2pSupplyAmount -= deltaInUnderlying.div(vars.p2pSupplyIndex); } emit P2PSupplyDeltaUpdated(_poolTokenAddress, delta.p2pSupplyDelta); emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); } // Match pool suppliers if any. if ( vars.remainingToWithdraw > 0 && !p2pDisabled[_poolTokenAddress] && suppliersOnPool[_poolTokenAddress].getHead() != address(0) ) { (uint256 matched, uint256 gasConsumedInMatching) = _matchSuppliers( _poolTokenAddress, CompoundMath.min(vars.remainingToWithdraw, vars.withdrawable - vars.toWithdraw), vars.remainingGasForMatching ); if (vars.remainingGasForMatching <= gasConsumedInMatching) vars.remainingGasForMatching = 0; else vars.remainingGasForMatching -= gasConsumedInMatching; if (matched > 0) { vars.remainingToWithdraw -= matched; vars.toWithdraw += matched; } } // If this value is equal to 0 the withdraw will revert on Compound. if (vars.toWithdraw.div(vars.poolSupplyIndex) > 0) _withdrawFromPool(_poolTokenAddress, vars.toWithdraw); // Reverts on error. /// Hard withdraw /// // Unmatch peer-to-peer borrowers. if (vars.remainingToWithdraw > 0) { uint256 unmatched = _unmatchBorrowers( _poolTokenAddress, vars.remainingToWithdraw, vars.remainingGasForMatching ); // If unmatched does not cover remainingToWithdraw, the difference is added to the borrow peer-to-peer delta. if (unmatched < vars.remainingToWithdraw) { delta.p2pBorrowDelta += (vars.remainingToWithdraw - unmatched).div( ICToken(_poolTokenAddress).borrowIndex() ); emit P2PBorrowDeltaUpdated(_poolTokenAddress, delta.p2pBorrowDelta); } delta.p2pSupplyAmount -= vars.remainingToWithdraw.div(vars.p2pSupplyIndex); delta.p2pBorrowAmount -= unmatched.div(p2pBorrowIndex[_poolTokenAddress]); emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); _borrowFromPool(_poolTokenAddress, vars.remainingToWithdraw); // Reverts on error. } _leaveMarketIfNeeded(_poolTokenAddress, _supplier); vars.underlyingToken.safeTransfer(_receiver, _amount); emit Withdrawn( _supplier, _receiver, _poolTokenAddress, _amount, supplyBalanceInOf[_poolTokenAddress][_supplier].onPool, supplyBalanceInOf[_poolTokenAddress][_supplier].inP2P ); } /// @dev Implements repay logic without security checks. /// @param _poolTokenAddress The address of the market the user wants to interact with. /// @param _repayer The address of the account repaying the debt. /// @param _onBehalf The address of the account whose debt is repaid. /// @param _amount The amount of token (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. function _safeRepayLogic( address _poolTokenAddress, address _repayer, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching ) internal { if (lastBorrowBlock[_onBehalf] == block.number) revert SameBlockBorrowRepay(); ERC20 underlyingToken = _getUnderlying(_poolTokenAddress); underlyingToken.safeTransferFrom(_repayer, address(this), _amount); RepayVars memory vars; vars.remainingToRepay = _amount; vars.remainingGasForMatching = _maxGasForMatching; vars.poolBorrowIndex = ICToken(_poolTokenAddress).borrowIndex(); /// Soft repay /// vars.borrowedOnPool = borrowBalanceInOf[_poolTokenAddress][_onBehalf].onPool; if (vars.borrowedOnPool > 0) { vars.maxToRepayOnPool = vars.borrowedOnPool.mul(vars.poolBorrowIndex); if (vars.maxToRepayOnPool > vars.remainingToRepay) { vars.toRepay = vars.remainingToRepay; borrowBalanceInOf[_poolTokenAddress][_onBehalf].onPool -= CompoundMath.min( vars.borrowedOnPool, vars.toRepay.div(vars.poolBorrowIndex) ); // In cdUnit. _updateBorrowerInDS(_poolTokenAddress, _onBehalf); _repayToPool(_poolTokenAddress, underlyingToken, vars.toRepay); // Reverts on error. _leaveMarketIfNeeded(_poolTokenAddress, _onBehalf); emit Repaid( _repayer, _onBehalf, _poolTokenAddress, _amount, borrowBalanceInOf[_poolTokenAddress][_onBehalf].onPool, borrowBalanceInOf[_poolTokenAddress][_onBehalf].inP2P ); return; } else { vars.toRepay = vars.maxToRepayOnPool; vars.remainingToRepay -= vars.toRepay; borrowBalanceInOf[_poolTokenAddress][_onBehalf].onPool = 0; } } Types.Delta storage delta = deltas[_poolTokenAddress]; vars.p2pSupplyIndex = p2pSupplyIndex[_poolTokenAddress]; vars.p2pBorrowIndex = p2pBorrowIndex[_poolTokenAddress]; borrowBalanceInOf[_poolTokenAddress][_onBehalf].inP2P -= CompoundMath.min( borrowBalanceInOf[_poolTokenAddress][_onBehalf].inP2P, vars.remainingToRepay.div(vars.p2pBorrowIndex) ); // In peer-to-peer unit. _updateBorrowerInDS(_poolTokenAddress, _onBehalf); // Reduce peer-to-peer borrow delta first if any. if (vars.remainingToRepay > 0 && delta.p2pBorrowDelta > 0) { uint256 deltaInUnderlying = delta.p2pBorrowDelta.mul(vars.poolBorrowIndex); if (deltaInUnderlying > vars.remainingToRepay) { delta.p2pBorrowDelta -= vars.remainingToRepay.div(vars.poolBorrowIndex); delta.p2pBorrowAmount -= vars.remainingToRepay.div(vars.p2pBorrowIndex); vars.toRepay += vars.remainingToRepay; vars.remainingToRepay = 0; } else { delta.p2pBorrowDelta = 0; delta.p2pBorrowAmount -= deltaInUnderlying.div(vars.p2pBorrowIndex); vars.toRepay += deltaInUnderlying; vars.remainingToRepay -= deltaInUnderlying; } emit P2PBorrowDeltaUpdated(_poolTokenAddress, delta.p2pBorrowDelta); emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); } // Repay the fee. if (vars.remainingToRepay > 0) { // Fee = (p2pBorrowAmount - p2pBorrowDelta) - (p2pSupplyAmount - p2pSupplyDelta). // No need to subtract p2pBorrowDelta as it is zero. vars.feeToRepay = CompoundMath.safeSub( delta.p2pBorrowAmount.mul(vars.p2pBorrowIndex), (delta.p2pSupplyAmount.mul(vars.p2pSupplyIndex) - delta.p2pSupplyDelta.mul(ICToken(_poolTokenAddress).exchangeRateStored())) ); if (vars.feeToRepay > 0) { uint256 feeRepaid = CompoundMath.min(vars.feeToRepay, vars.remainingToRepay); vars.remainingToRepay -= feeRepaid; delta.p2pBorrowAmount -= feeRepaid.div(vars.p2pBorrowIndex); emit P2PAmountsUpdated( _poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount ); } } /// Transfer repay /// // Match pool borrowers if any. if ( vars.remainingToRepay > 0 && !p2pDisabled[_poolTokenAddress] && borrowersOnPool[_poolTokenAddress].getHead() != address(0) ) { (uint256 matched, uint256 gasConsumedInMatching) = _matchBorrowers( _poolTokenAddress, vars.remainingToRepay, vars.remainingGasForMatching ); if (vars.remainingGasForMatching <= gasConsumedInMatching) vars.remainingGasForMatching = 0; else vars.remainingGasForMatching -= gasConsumedInMatching; if (matched > 0) { vars.remainingToRepay -= matched; vars.toRepay += matched; } } _repayToPool(_poolTokenAddress, underlyingToken, vars.toRepay); // Reverts on error. /// Hard repay /// // Unmatch peer-to-peer suppliers. if (vars.remainingToRepay > 0) { uint256 unmatched = _unmatchSuppliers( _poolTokenAddress, vars.remainingToRepay, vars.remainingGasForMatching ); // If unmatched does not cover remainingToRepay, the difference is added to the supply peer-to-peer delta. if (unmatched < vars.remainingToRepay) { delta.p2pSupplyDelta += (vars.remainingToRepay - unmatched).div( ICToken(_poolTokenAddress).exchangeRateStored() // Exchange rate has already been updated. ); emit P2PSupplyDeltaUpdated(_poolTokenAddress, delta.p2pSupplyDelta); } delta.p2pSupplyAmount -= unmatched.div(vars.p2pSupplyIndex); delta.p2pBorrowAmount -= vars.remainingToRepay.div(vars.p2pBorrowIndex); emit P2PAmountsUpdated(_poolTokenAddress, delta.p2pSupplyAmount, delta.p2pBorrowAmount); _supplyToPool(_poolTokenAddress, underlyingToken, vars.remainingToRepay); // Reverts on error. } _leaveMarketIfNeeded(_poolTokenAddress, _onBehalf); emit Repaid( _repayer, _onBehalf, _poolTokenAddress, _amount, borrowBalanceInOf[_poolTokenAddress][_onBehalf].onPool, borrowBalanceInOf[_poolTokenAddress][_onBehalf].inP2P ); } /// @dev Supplies underlying tokens to Compound. /// @param _poolTokenAddress The address of the pool token. /// @param _underlyingToken The underlying token of the market to supply to. /// @param _amount The amount of token (in underlying). function _supplyToPool( address _poolTokenAddress, ERC20 _underlyingToken, uint256 _amount ) internal { if (_poolTokenAddress == cEth) { IWETH(wEth).withdraw(_amount); // Turn wETH into ETH. ICEther(_poolTokenAddress).mint{value: _amount}(); } else { _underlyingToken.safeApprove(_poolTokenAddress, _amount); if (ICToken(_poolTokenAddress).mint(_amount) != 0) revert MintOnCompoundFailed(); } } /// @dev Withdraws underlying tokens from Compound. /// @param _poolTokenAddress The address of the pool token. /// @param _amount The amount of token (in underlying). function _withdrawFromPool(address _poolTokenAddress, uint256 _amount) internal { if (ICToken(_poolTokenAddress).redeemUnderlying(_amount) != 0) revert RedeemOnCompoundFailed(); if (_poolTokenAddress == cEth) IWETH(address(wEth)).deposit{value: _amount}(); // Turn the ETH received in wETH. } /// @dev Borrows underlying tokens from Compound. /// @param _poolTokenAddress The address of the pool token. /// @param _amount The amount of token (in underlying). function _borrowFromPool(address _poolTokenAddress, uint256 _amount) internal { if ((ICToken(_poolTokenAddress).borrow(_amount) != 0)) revert BorrowOnCompoundFailed(); if (_poolTokenAddress == cEth) IWETH(address(wEth)).deposit{value: _amount}(); // Turn the ETH received in wETH. } /// @dev Repays underlying tokens to Compound. /// @param _poolTokenAddress The address of the pool token. /// @param _underlyingToken The underlying token of the market to repay to. /// @param _amount The amount of token (in underlying). function _repayToPool( address _poolTokenAddress, ERC20 _underlyingToken, uint256 _amount ) internal { // Repay only what is necessary. The remaining tokens stays on the contracts and are claimable by the DAO. _amount = Math.min( _amount, ICToken(_poolTokenAddress).borrowBalanceCurrent(address(this)) // The debt of the contract. ); if (_amount > 0) { if (_poolTokenAddress == cEth) { IWETH(wEth).withdraw(_amount); // Turn wETH into ETH. ICEther(_poolTokenAddress).repayBorrow{value: _amount}(); } else { _underlyingToken.safeApprove(_poolTokenAddress, _amount); if (ICToken(_poolTokenAddress).repayBorrow(_amount) != 0) revert RepayOnCompoundFailed(); } } } /// @dev Enters the user into the market if not already there. /// @param _user The address of the user to update. /// @param _poolTokenAddress The address of the market to check. function _enterMarketIfNeeded(address _poolTokenAddress, address _user) internal { if (!userMembership[_poolTokenAddress][_user]) { userMembership[_poolTokenAddress][_user] = true; enteredMarkets[_user].push(_poolTokenAddress); } } /// @dev Removes the user from the market if its balances are null. /// @param _user The address of the user to update. /// @param _poolTokenAddress The address of the market to check. function _leaveMarketIfNeeded(address _poolTokenAddress, address _user) internal { if ( userMembership[_poolTokenAddress][_user] && supplyBalanceInOf[_poolTokenAddress][_user].inP2P == 0 && supplyBalanceInOf[_poolTokenAddress][_user].onPool == 0 && borrowBalanceInOf[_poolTokenAddress][_user].inP2P == 0 && borrowBalanceInOf[_poolTokenAddress][_user].onPool == 0 ) { uint256 index; while (enteredMarkets[_user][index] != _poolTokenAddress) { unchecked { ++index; } } userMembership[_poolTokenAddress][_user] = false; uint256 length = enteredMarkets[_user].length; if (index != length - 1) enteredMarkets[_user][index] = enteredMarkets[_user][length - 1]; enteredMarkets[_user].pop(); } } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; interface IPositionsManager { function supplyLogic( address _poolTokenAddress, address _supplier, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching ) external; function borrowLogic( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) external; function withdrawLogic( address _poolTokenAddress, uint256 _amount, address _supplier, address _receiver, uint256 _maxGasForMatching ) external; function repayLogic( address _poolTokenAddress, address _repayer, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching ) external; function liquidateLogic( address _poolTokenBorrowedAddress, address _poolTokenCollateralAddress, address _borrower, uint256 _amount ) external; }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; function withdraw(uint256) external; }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity 0.8.13; import "./MorphoUtils.sol"; /// @title MatchingEngine. /// @author Morpho Labs. /// @custom:contact [email protected] /// @notice Smart contract managing the matching engine. abstract contract MatchingEngine is MorphoUtils { using DoubleLinkedList for DoubleLinkedList.List; using CompoundMath for uint256; /// STRUCTS /// // Struct to avoid stack too deep. struct UnmatchVars { uint256 p2pIndex; uint256 toUnmatch; uint256 poolIndex; uint256 inUnderlying; uint256 gasLeftAtTheBeginning; } // Struct to avoid stack too deep. struct MatchVars { uint256 p2pIndex; uint256 toMatch; uint256 poolIndex; uint256 inUnderlying; uint256 gasLeftAtTheBeginning; } /// @notice Emitted when the position of a supplier is updated. /// @param _user The address of the supplier. /// @param _poolTokenAddress The address of the market. /// @param _balanceOnPool The supply balance on pool after update. /// @param _balanceInP2P The supply balance in peer-to-peer after update. event SupplierPositionUpdated( address indexed _user, address indexed _poolTokenAddress, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// @notice Emitted when the position of a borrower is updated. /// @param _user The address of the borrower. /// @param _poolTokenAddress The address of the market. /// @param _balanceOnPool The borrow balance on pool after update. /// @param _balanceInP2P The borrow balance in peer-to-peer after update. event BorrowerPositionUpdated( address indexed _user, address indexed _poolTokenAddress, uint256 _balanceOnPool, uint256 _balanceInP2P ); /// INTERNAL /// /// @notice Matches suppliers' liquidity waiting on Compound up to the given `_amount` and moves it to peer-to-peer. /// @dev Note: This function expects Compound's exchange rate and peer-to-peer indexes to have been updated. /// @param _poolTokenAddress The address of the market from which to match suppliers. /// @param _amount The token amount to search for (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. /// @return matched The amount of liquidity matched (in underlying). /// @return gasConsumedInMatching The amount of gas consumed within the matching loop. function _matchSuppliers( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) internal returns (uint256 matched, uint256 gasConsumedInMatching) { if (_maxGasForMatching == 0) return (0, 0); MatchVars memory vars; vars.poolIndex = ICToken(_poolTokenAddress).exchangeRateStored(); // Exchange rate has already been updated. vars.p2pIndex = p2pSupplyIndex[_poolTokenAddress]; address firstPoolSupplier; Types.SupplyBalance storage firstPoolSupplierBalance; vars.gasLeftAtTheBeginning = gasleft(); while ( matched < _amount && (firstPoolSupplier = suppliersOnPool[_poolTokenAddress].getHead()) != address(0) && vars.gasLeftAtTheBeginning - gasleft() < _maxGasForMatching ) { firstPoolSupplierBalance = supplyBalanceInOf[_poolTokenAddress][firstPoolSupplier]; vars.inUnderlying = firstPoolSupplierBalance.onPool.mul(vars.poolIndex); uint256 newPoolSupplyBalance; uint256 newP2PSupplyBalance; uint256 maxToMatch = _amount - matched; if (vars.inUnderlying <= maxToMatch) { // newPoolSupplyBalance is 0. newP2PSupplyBalance = firstPoolSupplierBalance.inP2P + vars.inUnderlying.div(vars.p2pIndex); matched += vars.inUnderlying; } else { newPoolSupplyBalance = firstPoolSupplierBalance.onPool - maxToMatch.div(vars.poolIndex); newP2PSupplyBalance = firstPoolSupplierBalance.inP2P + maxToMatch.div(vars.p2pIndex); matched = _amount; } firstPoolSupplierBalance.onPool = newPoolSupplyBalance; firstPoolSupplierBalance.inP2P = newP2PSupplyBalance; _updateSupplierInDS(_poolTokenAddress, firstPoolSupplier); emit SupplierPositionUpdated( firstPoolSupplier, _poolTokenAddress, newPoolSupplyBalance, newP2PSupplyBalance ); } gasConsumedInMatching = vars.gasLeftAtTheBeginning - gasleft(); } /// @notice Unmatches suppliers' liquidity in peer-to-peer up to the given `_amount` and moves it to Compound. /// @dev Note: This function expects Compound's exchange rate and peer-to-peer indexes to have been updated. /// @param _poolTokenAddress The address of the market from which to unmatch suppliers. /// @param _amount The amount to search for (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. /// @return The amount unmatched (in underlying). function _unmatchSuppliers( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) internal returns (uint256) { if (_maxGasForMatching == 0) return 0; UnmatchVars memory vars; vars.poolIndex = ICToken(_poolTokenAddress).exchangeRateStored(); // Exchange rate has already been updated. vars.p2pIndex = p2pSupplyIndex[_poolTokenAddress]; address firstP2PSupplier; Types.SupplyBalance storage firstP2PSupplierBalance; uint256 remainingToUnmatch = _amount; vars.gasLeftAtTheBeginning = gasleft(); while ( remainingToUnmatch > 0 && (firstP2PSupplier = suppliersInP2P[_poolTokenAddress].getHead()) != address(0) && vars.gasLeftAtTheBeginning - gasleft() < _maxGasForMatching ) { firstP2PSupplierBalance = supplyBalanceInOf[_poolTokenAddress][firstP2PSupplier]; vars.inUnderlying = firstP2PSupplierBalance.inP2P.mul(vars.p2pIndex); uint256 newPoolSupplyBalance; uint256 newP2PSupplyBalance; if (vars.inUnderlying <= remainingToUnmatch) { // newP2PSupplyBalance is 0. newPoolSupplyBalance = firstP2PSupplierBalance.onPool + vars.inUnderlying.div(vars.poolIndex); remainingToUnmatch -= vars.inUnderlying; } else { newPoolSupplyBalance = firstP2PSupplierBalance.onPool + remainingToUnmatch.div(vars.poolIndex); newP2PSupplyBalance = firstP2PSupplierBalance.inP2P - remainingToUnmatch.div(vars.p2pIndex); remainingToUnmatch = 0; } firstP2PSupplierBalance.onPool = newPoolSupplyBalance; firstP2PSupplierBalance.inP2P = newP2PSupplyBalance; _updateSupplierInDS(_poolTokenAddress, firstP2PSupplier); emit SupplierPositionUpdated( firstP2PSupplier, _poolTokenAddress, newPoolSupplyBalance, newP2PSupplyBalance ); } return _amount - remainingToUnmatch; } /// @notice Matches borrowers' liquidity waiting on Compound up to the given `_amount` and moves it to peer-to-peer. /// @dev Note: This function expects peer-to-peer indexes to have been updated.. /// @param _poolTokenAddress The address of the market from which to match borrowers. /// @param _amount The amount to search for (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. /// @return matched The amount of liquidity matched (in underlying). /// @return gasConsumedInMatching The amount of gas consumed within the matching loop. function _matchBorrowers( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) internal returns (uint256 matched, uint256 gasConsumedInMatching) { if (_maxGasForMatching == 0) return (0, 0); MatchVars memory vars; vars.poolIndex = ICToken(_poolTokenAddress).borrowIndex(); vars.p2pIndex = p2pBorrowIndex[_poolTokenAddress]; address firstPoolBorrower; Types.BorrowBalance storage firstPoolBorrowerBalance; vars.gasLeftAtTheBeginning = gasleft(); while ( matched < _amount && (firstPoolBorrower = borrowersOnPool[_poolTokenAddress].getHead()) != address(0) && vars.gasLeftAtTheBeginning - gasleft() < _maxGasForMatching ) { firstPoolBorrowerBalance = borrowBalanceInOf[_poolTokenAddress][firstPoolBorrower]; vars.inUnderlying = firstPoolBorrowerBalance.onPool.mul(vars.poolIndex); uint256 newPoolBorrowBalance; uint256 newP2PBorrowBalance; uint256 maxToMatch = _amount - matched; if (vars.inUnderlying <= maxToMatch) { // newPoolBorrowBalance is 0. newP2PBorrowBalance = firstPoolBorrowerBalance.inP2P + vars.inUnderlying.div(vars.p2pIndex); matched += vars.inUnderlying; } else { newPoolBorrowBalance = firstPoolBorrowerBalance.onPool - maxToMatch.div(vars.poolIndex); newP2PBorrowBalance = firstPoolBorrowerBalance.inP2P + maxToMatch.div(vars.p2pIndex); matched = _amount; } firstPoolBorrowerBalance.onPool = newPoolBorrowBalance; firstPoolBorrowerBalance.inP2P = newP2PBorrowBalance; _updateBorrowerInDS(_poolTokenAddress, firstPoolBorrower); emit BorrowerPositionUpdated( firstPoolBorrower, _poolTokenAddress, newPoolBorrowBalance, newP2PBorrowBalance ); } gasConsumedInMatching = vars.gasLeftAtTheBeginning - gasleft(); } /// @notice Unmatches borrowers' liquidity in peer-to-peer for the given `_amount` and moves it to Compound. /// @dev Note: This function expects and peer-to-peer indexes to have been updated. /// @param _poolTokenAddress The address of the market from which to unmatch borrowers. /// @param _amount The amount to unmatch (in underlying). /// @param _maxGasForMatching The maximum amount of gas to consume within a matching engine loop. /// @return The amount unmatched (in underlying). function _unmatchBorrowers( address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching ) internal returns (uint256) { if (_maxGasForMatching == 0) return 0; UnmatchVars memory vars; vars.poolIndex = ICToken(_poolTokenAddress).borrowIndex(); vars.p2pIndex = p2pBorrowIndex[_poolTokenAddress]; address firstP2PBorrower; Types.BorrowBalance storage firstP2PBorrowerBalance; uint256 remainingToUnmatch = _amount; vars.gasLeftAtTheBeginning = gasleft(); while ( remainingToUnmatch > 0 && (firstP2PBorrower = borrowersInP2P[_poolTokenAddress].getHead()) != address(0) && vars.gasLeftAtTheBeginning - gasleft() < _maxGasForMatching ) { firstP2PBorrowerBalance = borrowBalanceInOf[_poolTokenAddress][firstP2PBorrower]; vars.inUnderlying = firstP2PBorrowerBalance.inP2P.mul(vars.p2pIndex); uint256 newPoolBorrowBalance; uint256 newP2PBorrowBalance; if (vars.inUnderlying <= remainingToUnmatch) { // newP2PBorrowBalance is 0. newPoolBorrowBalance = firstP2PBorrowerBalance.onPool + vars.inUnderlying.div(vars.poolIndex); remainingToUnmatch -= vars.inUnderlying; } else { newPoolBorrowBalance = firstP2PBorrowerBalance.onPool + remainingToUnmatch.div(vars.poolIndex); newP2PBorrowBalance = firstP2PBorrowerBalance.inP2P - remainingToUnmatch.div(vars.p2pIndex); remainingToUnmatch = 0; } firstP2PBorrowerBalance.onPool = newPoolBorrowBalance; firstP2PBorrowerBalance.inP2P = newP2PBorrowBalance; _updateBorrowerInDS(_poolTokenAddress, firstP2PBorrower); emit BorrowerPositionUpdated( firstP2PBorrower, _poolTokenAddress, newPoolBorrowBalance, newP2PBorrowBalance ); } return _amount - remainingToUnmatch; } /// @notice Updates `_user` in the supplier data structures. /// @param _poolTokenAddress The address of the market on which to update the suppliers data structure. /// @param _user The address of the user. function _updateSupplierInDS(address _poolTokenAddress, address _user) internal { uint256 onPool = supplyBalanceInOf[_poolTokenAddress][_user].onPool; uint256 inP2P = supplyBalanceInOf[_poolTokenAddress][_user].inP2P; uint256 formerValueOnPool = suppliersOnPool[_poolTokenAddress].getValueOf(_user); uint256 formerValueInP2P = suppliersInP2P[_poolTokenAddress].getValueOf(_user); // Round pool balance to 0 if below threshold. if (onPool <= dustThreshold) { supplyBalanceInOf[_poolTokenAddress][_user].onPool = 0; onPool = 0; } if (formerValueOnPool != onPool) { if (formerValueOnPool > 0) suppliersOnPool[_poolTokenAddress].remove(_user); if (onPool > 0) suppliersOnPool[_poolTokenAddress].insertSorted(_user, onPool, maxSortedUsers); } // Round peer-to-peer balance to 0 if below threshold. if (inP2P <= dustThreshold) { supplyBalanceInOf[_poolTokenAddress][_user].inP2P = 0; inP2P = 0; } if (formerValueInP2P != inP2P) { if (formerValueInP2P > 0) suppliersInP2P[_poolTokenAddress].remove(_user); if (inP2P > 0) suppliersInP2P[_poolTokenAddress].insertSorted(_user, inP2P, maxSortedUsers); } if (address(rewardsManager) != address(0)) rewardsManager.accrueUserSupplyUnclaimedRewards( _user, _poolTokenAddress, formerValueOnPool ); } /// @notice Updates `_user` in the borrower data structures. /// @param _poolTokenAddress The address of the market on which to update the borrowers data structure. /// @param _user The address of the user. function _updateBorrowerInDS(address _poolTokenAddress, address _user) internal { uint256 onPool = borrowBalanceInOf[_poolTokenAddress][_user].onPool; uint256 inP2P = borrowBalanceInOf[_poolTokenAddress][_user].inP2P; uint256 formerValueOnPool = borrowersOnPool[_poolTokenAddress].getValueOf(_user); uint256 formerValueInP2P = borrowersInP2P[_poolTokenAddress].getValueOf(_user); // Round pool balance to 0 if below threshold. if (onPool <= dustThreshold) { borrowBalanceInOf[_poolTokenAddress][_user].onPool = 0; onPool = 0; } if (formerValueOnPool != onPool) { if (formerValueOnPool > 0) borrowersOnPool[_poolTokenAddress].remove(_user); if (onPool > 0) borrowersOnPool[_poolTokenAddress].insertSorted(_user, onPool, maxSortedUsers); } // Round peer-to-peer balance to 0 if below threshold. if (inP2P <= dustThreshold) { borrowBalanceInOf[_poolTokenAddress][_user].inP2P = 0; inP2P = 0; } if (formerValueInP2P != inP2P) { if (formerValueInP2P > 0) borrowersInP2P[_poolTokenAddress].remove(_user); if (inP2P > 0) borrowersInP2P[_poolTokenAddress].insertSorted(_user, inP2P, maxSortedUsers); } if (address(rewardsManager) != address(0)) rewardsManager.accrueUserBorrowUnclaimedRewards( _user, _poolTokenAddress, formerValueOnPool ); } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity 0.8.13; import "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./libraries/CompoundMath.sol"; import "../common/libraries/DelegateCall.sol"; import "./MorphoStorage.sol"; /// @title MorphoUtils. /// @author Morpho Labs. /// @custom:contact [email protected] /// @notice Modifiers, getters and other util functions for Morpho. abstract contract MorphoUtils is MorphoStorage { using DoubleLinkedList for DoubleLinkedList.List; using CompoundMath for uint256; using DelegateCall for address; /// ERRORS /// /// @notice Thrown when the Compound's oracle failed. error CompoundOracleFailed(); /// @notice Thrown when the market is not created yet. error MarketNotCreated(); /// @notice Thrown when the market is paused. error MarketPaused(); /// MODIFIERS /// /// @notice Prevents to update a market not created yet. /// @param _poolTokenAddress The address of the market to check. modifier isMarketCreated(address _poolTokenAddress) { if (!marketStatus[_poolTokenAddress].isCreated) revert MarketNotCreated(); _; } /// @notice Prevents a user to trigger a function when market is not created or paused. /// @param _poolTokenAddress The address of the market to check. modifier isMarketCreatedAndNotPaused(address _poolTokenAddress) { Types.MarketStatus memory marketStatus_ = marketStatus[_poolTokenAddress]; if (!marketStatus_.isCreated) revert MarketNotCreated(); if (marketStatus_.isPaused) revert MarketPaused(); _; } /// @notice Prevents a user to trigger a function when market is not created or paused or partial paused. /// @param _poolTokenAddress The address of the market to check. modifier isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolTokenAddress) { Types.MarketStatus memory marketStatus_ = marketStatus[_poolTokenAddress]; if (!marketStatus_.isCreated) revert MarketNotCreated(); if (marketStatus_.isPaused || marketStatus_.isPartiallyPaused) revert MarketPaused(); _; } /// EXTERNAL /// /// @notice Returns all markets entered by a given user. /// @param _user The address of the user. /// @return enteredMarkets_ The list of markets entered by this user. function getEnteredMarkets(address _user) external view returns (address[] memory enteredMarkets_) { return enteredMarkets[_user]; } /// @notice Returns all created markets. /// @return marketsCreated_ The list of market addresses. function getAllMarkets() external view returns (address[] memory marketsCreated_) { return marketsCreated; } /// @notice Gets the head of the data structure on a specific market (for UI). /// @param _poolTokenAddress The address of the market from which to get the head. /// @param _positionType The type of user from which to get the head. /// @return head The head in the data structure. function getHead(address _poolTokenAddress, Types.PositionType _positionType) external view returns (address head) { if (_positionType == Types.PositionType.SUPPLIERS_IN_P2P) head = suppliersInP2P[_poolTokenAddress].getHead(); else if (_positionType == Types.PositionType.SUPPLIERS_ON_POOL) head = suppliersOnPool[_poolTokenAddress].getHead(); else if (_positionType == Types.PositionType.BORROWERS_IN_P2P) head = borrowersInP2P[_poolTokenAddress].getHead(); else if (_positionType == Types.PositionType.BORROWERS_ON_POOL) head = borrowersOnPool[_poolTokenAddress].getHead(); } /// @notice Gets the next user after `_user` in the data structure on a specific market (for UI). /// @param _poolTokenAddress The address of the market from which to get the user. /// @param _positionType The type of user from which to get the next user. /// @param _user The address of the user from which to get the next user. /// @return next The next user in the data structure. function getNext( address _poolTokenAddress, Types.PositionType _positionType, address _user ) external view returns (address next) { if (_positionType == Types.PositionType.SUPPLIERS_IN_P2P) next = suppliersInP2P[_poolTokenAddress].getNext(_user); else if (_positionType == Types.PositionType.SUPPLIERS_ON_POOL) next = suppliersOnPool[_poolTokenAddress].getNext(_user); else if (_positionType == Types.PositionType.BORROWERS_IN_P2P) next = borrowersInP2P[_poolTokenAddress].getNext(_user); else if (_positionType == Types.PositionType.BORROWERS_ON_POOL) next = borrowersOnPool[_poolTokenAddress].getNext(_user); } /// @notice Updates the peer-to-peer indexes. /// @dev Note: This function updates the exchange rate on Compound. As a consequence only a call to exchangeRatesStored() is necessary to get the most up to date exchange rate. /// @param _poolTokenAddress The address of the market to update. function updateP2PIndexes(address _poolTokenAddress) external isMarketCreated(_poolTokenAddress) { _updateP2PIndexes(_poolTokenAddress); } /// INTERNAL /// /// @dev Updates the peer-to-peer indexes. /// @dev Note: This function updates the exchange rate on Compound. As a consequence only a call to exchangeRatesStored() is necessary to get the most up to date exchange rate. /// @param _poolTokenAddress The address of the market to update. function _updateP2PIndexes(address _poolTokenAddress) internal { address(interestRatesManager).functionDelegateCall( abi.encodeWithSelector( interestRatesManager.updateP2PIndexes.selector, _poolTokenAddress ) ); } /// @dev Checks whether the user has enough collateral to maintain such a borrow position. /// @param _user The user to check. /// @param _poolTokenAddress The market to hypothetically withdraw/borrow in. /// @param _withdrawnAmount The amount of tokens to hypothetically withdraw (in underlying). /// @param _borrowedAmount The amount of tokens to hypothetically borrow (in underlying). function _isLiquidatable( address _user, address _poolTokenAddress, uint256 _withdrawnAmount, uint256 _borrowedAmount ) internal view returns (bool) { ICompoundOracle oracle = ICompoundOracle(comptroller.oracle()); uint256 numberOfEnteredMarkets = enteredMarkets[_user].length; Types.AssetLiquidityData memory assetData; uint256 maxDebtValue; uint256 debtValue; uint256 i; while (i < numberOfEnteredMarkets) { address poolTokenEntered = enteredMarkets[_user][i]; assetData = _getUserLiquidityDataForAsset(_user, poolTokenEntered, oracle); maxDebtValue += assetData.maxDebtValue; debtValue += assetData.debtValue; if (_poolTokenAddress == poolTokenEntered) { if (_borrowedAmount > 0) debtValue += _borrowedAmount.mul(assetData.underlyingPrice); if (_withdrawnAmount > 0) maxDebtValue -= _withdrawnAmount.mul(assetData.underlyingPrice).mul( assetData.collateralFactor ); } unchecked { ++i; } } return debtValue > maxDebtValue; } /// @notice Returns the data related to `_poolTokenAddress` for the `_user`. /// @dev Note: Must be called after calling `_updateP2PIndexes()` to have the most up-to-date indexes. /// @param _user The user to determine data for. /// @param _poolTokenAddress The address of the market. /// @param _oracle The oracle used. /// @return assetData The data related to this asset. function _getUserLiquidityDataForAsset( address _user, address _poolTokenAddress, ICompoundOracle _oracle ) internal view returns (Types.AssetLiquidityData memory assetData) { assetData.underlyingPrice = _oracle.getUnderlyingPrice(_poolTokenAddress); if (assetData.underlyingPrice == 0) revert CompoundOracleFailed(); (, assetData.collateralFactor, ) = comptroller.markets(_poolTokenAddress); assetData.collateralValue = _getUserSupplyBalanceInOf(_poolTokenAddress, _user).mul( assetData.underlyingPrice ); assetData.debtValue = _getUserBorrowBalanceInOf(_poolTokenAddress, _user).mul( assetData.underlyingPrice ); assetData.maxDebtValue = assetData.collateralValue.mul(assetData.collateralFactor); } /// @dev Returns the supply balance of `_user` in the `_poolTokenAddress` market. /// @dev Note: Compute the result with the index stored and not the most up to date one. /// @param _user The address of the user. /// @param _poolTokenAddress The market where to get the supply amount. /// @return The supply balance of the user (in underlying). function _getUserSupplyBalanceInOf(address _poolTokenAddress, address _user) internal view returns (uint256) { Types.SupplyBalance memory userSupplyBalance = supplyBalanceInOf[_poolTokenAddress][_user]; return userSupplyBalance.inP2P.mul(p2pSupplyIndex[_poolTokenAddress]) + userSupplyBalance.onPool.mul(ICToken(_poolTokenAddress).exchangeRateStored()); } /// @dev Returns the borrow balance of `_user` in the `_poolTokenAddress` market. /// @param _user The address of the user. /// @param _poolTokenAddress The market where to get the borrow amount. /// @return The borrow balance of the user (in underlying). function _getUserBorrowBalanceInOf(address _poolTokenAddress, address _user) internal view returns (uint256) { Types.BorrowBalance memory userBorrowBalance = borrowBalanceInOf[_poolTokenAddress][_user]; return userBorrowBalance.inP2P.mul(p2pBorrowIndex[_poolTokenAddress]) + userBorrowBalance.onPool.mul(ICToken(_poolTokenAddress).borrowIndex()); } /// @dev Returns the underlying ERC20 token related to the pool token. /// @param _poolTokenAddress The address of the pool token. /// @return The underlying ERC20 token. function _getUnderlying(address _poolTokenAddress) internal view returns (ERC20) { if (_poolTokenAddress == cEth) // cETH has no underlying() function. return ERC20(wEth); else return ERC20(ICToken(_poolTokenAddress).underlying()); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; /// @title CompoundMath. /// @author Morpho Labs. /// @custom:contact [email protected] /// @dev Library emulating in solidity 8+ the behavior of Compound's mulScalarTruncate and divScalarByExpTruncate functions. library CompoundMath { /// ERRORS /// /// @notice Reverts when the number exceeds 224 bits. error NumberExceeds224Bits(); /// @notice Reverts when the number exceeds 32 bits. error NumberExceeds32Bits(); /// INTERNAL /// function mul(uint256 x, uint256 y) internal pure returns (uint256) { return (x * y) / 1e18; } function div(uint256 x, uint256 y) internal pure returns (uint256) { return ((1e18 * x * 1e18) / y) / 1e18; } function safe224(uint256 n) internal pure returns (uint224) { if (n >= 2**224) revert NumberExceeds224Bits(); return uint224(n); } function safe32(uint256 n) internal pure returns (uint32) { if (n >= 2**32) revert NumberExceeds32Bits(); return uint32(n); } function min( uint256 a, uint256 b, uint256 c ) internal pure returns (uint256) { return a < b ? a < c ? a : c : b < c ? b : c; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } function safeSub(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a - b : 0; } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; /// @title Delegate Call Library. /// @author Morpho Labs. /// @custom:contact [email protected] /// @dev Library to perform delegate calls inspired by the OZ Address library: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol. library DelegateCall { /// ERRORS /// /// @notice Thrown when a low delegate call has failed without error message. error LowLevelDelegateCallFailed(); /// INTERNAL /// /// @dev Performs a low-level delegate call to the `_target` contract. /// @dev Note: Unlike the OZ's library this function does not check if the `_target` is a contract. It is the responsibility of the caller to ensure that the `_target` is a contract. /// @param _target The address of the target contract. /// @param _data The data to pass to the function called on the target contract. /// @return The return data from the function called on the target contract. function functionDelegateCall(address _target, bytes memory _data) internal returns (bytes memory) { (bool success, bytes memory returndata) = _target.delegatecall(_data); if (success) return returndata; else { // Look for revert reason and bubble it up if present. if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly. assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else revert LowLevelDelegateCallFailed(); } } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity 0.8.13; import "./interfaces/compound/ICompound.sol"; import "./interfaces/IPositionsManager.sol"; import "./interfaces/IIncentivesVault.sol"; import "./interfaces/IRewardsManager.sol"; import "./interfaces/IInterestRatesManager.sol"; import "../common/libraries/DoubleLinkedList.sol"; import "./libraries/Types.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /// @title MorphoStorage. /// @author Morpho Labs. /// @custom:contact [email protected] /// @notice All storage variables used in Morpho contracts. abstract contract MorphoStorage is OwnableUpgradeable, ReentrancyGuardUpgradeable { /// GLOBAL STORAGE /// uint8 public constant CTOKEN_DECIMALS = 8; // The number of decimals for cToken. uint16 public constant MAX_BASIS_POINTS = 10_000; // 100% in basis points. uint256 public constant WAD = 1e18; uint256 public maxSortedUsers; // The max number of users to sort in the data structure. uint256 public dustThreshold; // The minimum amount to keep in the data structure. Types.MaxGasForMatching public defaultMaxGasForMatching; // The default max gas to consume within loops in matching engine functions. /// POSITIONS STORAGE /// mapping(address => DoubleLinkedList.List) internal suppliersInP2P; // For a given market, the suppliers in peer-to-peer. mapping(address => DoubleLinkedList.List) internal suppliersOnPool; // For a given market, the suppliers on Compound. mapping(address => DoubleLinkedList.List) internal borrowersInP2P; // For a given market, the borrowers in peer-to-peer. mapping(address => DoubleLinkedList.List) internal borrowersOnPool; // For a given market, the borrowers on Compound. mapping(address => mapping(address => Types.SupplyBalance)) public supplyBalanceInOf; // For a given market, the supply balance of a user. cToken -> user -> balances. mapping(address => mapping(address => Types.BorrowBalance)) public borrowBalanceInOf; // For a given market, the borrow balance of a user. cToken -> user -> balances. mapping(address => mapping(address => bool)) public userMembership; // Whether the user is in the market or not. cToken -> user -> bool. mapping(address => address[]) public enteredMarkets; // The markets entered by a user. user -> cTokens. /// MARKETS STORAGE /// address[] public marketsCreated; // Keeps track of the created markets. mapping(address => bool) public p2pDisabled; // Whether the peer-to-peer market is open or not. mapping(address => uint256) public p2pSupplyIndex; // Current index from supply peer-to-peer unit to underlying (in wad). mapping(address => uint256) public p2pBorrowIndex; // Current index from borrow peer-to-peer unit to underlying (in wad). mapping(address => Types.LastPoolIndexes) public lastPoolIndexes; // Last pool index stored. mapping(address => Types.MarketParameters) public marketParameters; // Market parameters. mapping(address => Types.MarketStatus) public marketStatus; // Market status. mapping(address => Types.Delta) public deltas; // Delta parameters for each market. /// CONTRACTS AND ADDRESSES /// IPositionsManager public positionsManager; IIncentivesVault public incentivesVault; IRewardsManager public rewardsManager; IInterestRatesManager public interestRatesManager; IComptroller public comptroller; address public treasuryVault; address public cEth; address public wEth; /// APPENDIX STORAGE /// mapping(address => uint256) public lastBorrowBlock; // Block number of the last borrow of the user. bool public isClaimRewardsPaused; // Whether it's possible to claim rewards or not. /// CONSTRUCTOR /// /// @notice Constructs the contract. /// @dev The contract is automatically marked as initialized when deployed so that nobody can highjack the implementation contract. constructor() initializer {} }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; interface ICEth { function accrueInterest() external returns (uint256); function borrowRate() external returns (uint256); function borrowIndex() external returns (uint256); function borrowBalanceStored(address) external returns (uint256); function mint() external payable; function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function supplyRatePerBlock() external returns (uint256); function redeem(uint256) external returns (uint256); function redeemUnderlying(uint256) external returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address, address, uint256 ) external returns (bool); function transfer(address dst, uint256 amount) external returns (bool); function balanceOf(address) external returns (uint256); function balanceOfUnderlying(address account) external returns (uint256); function borrow(uint256) external returns (uint256); function repayBorrow() external payable; function borrowBalanceCurrent(address) external returns (uint256); function borrowRatePerBlock() external view returns (uint256); } interface IComptroller { struct CompMarketState { /// @notice The market's last updated compBorrowIndex or compSupplyIndex uint224 index; /// @notice The block number the index was last updated at uint32 block; } function liquidationIncentiveMantissa() external view returns (uint256); function closeFactorMantissa() external view returns (uint256); function admin() external view returns (address); function oracle() external view returns (address); function borrowCaps(address) external view returns (uint256); function markets(address) external view returns ( bool isListed, uint256 collateralFactorMantissa, bool isComped ); function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory); function exitMarket(address cToken) external returns (uint256); function mintAllowed( address cToken, address minter, uint256 mintAmount ) external returns (uint256); function mintVerify( address cToken, address minter, uint256 mintAmount, uint256 mintTokens ) external; function redeemAllowed( address cToken, address redeemer, uint256 redeemTokens ) external returns (uint256); function redeemVerify( address cToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens ) external; function borrowAllowed( address cToken, address borrower, uint256 borrowAmount ) external returns (uint256); function borrowVerify( address cToken, address borrower, uint256 borrowAmount ) external; function repayBorrowAllowed( address cToken, address payer, address borrower, uint256 repayAmount ) external returns (uint256); function repayBorrowVerify( address cToken, address payer, address borrower, uint256 repayAmount, uint256 borrowerIndex ) external; function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint256 repayAmount ) external returns (uint256); function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint256 repayAmount, uint256 seizeTokens ) external; function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens ) external returns (uint256); function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens ) external; function transferAllowed( address cToken, address src, address dst, uint256 transferTokens ) external returns (uint256); function transferVerify( address cToken, address src, address dst, uint256 transferTokens ) external; /*** Liquidity/Liquidation Calculations ***/ function liquidateCalculateSeizeTokens( address cTokenBorrowed, address cTokenCollateral, uint256 repayAmount ) external view returns (uint256, uint256); function getAccountLiquidity(address) external view returns ( uint256, uint256, uint256 ); function getHypotheticalAccountLiquidity( address, address, uint256, uint256 ) external returns ( uint256, uint256, uint256 ); function checkMembership(address, address) external view returns (bool); function claimComp(address holder) external; function claimComp(address holder, address[] memory cTokens) external; function compSpeeds(address) external view returns (uint256); function compSupplySpeeds(address) external view returns (uint256); function compBorrowSpeeds(address) external view returns (uint256); function compSupplyState(address) external view returns (CompMarketState memory); function compBorrowState(address) external view returns (CompMarketState memory); function getCompAddress() external view returns (address); function _setPriceOracle(address newOracle) external returns (uint256); function _setMintPaused(ICToken cToken, bool state) external returns (bool); function _setBorrowPaused(ICToken cToken, bool state) external returns (bool); function _setCollateralFactor(ICToken cToken, uint256 newCollateralFactorMantissa) external returns (uint256); function _setCompSpeeds( ICToken[] memory cTokens, uint256[] memory supplySpeeds, uint256[] memory borrowSpeeds ) external; } interface IInterestRateModel { function getBorrowRate( uint256 cash, uint256 borrows, uint256 reserves ) external view returns (uint256); function getSupplyRate( uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa ) external view returns (uint256); } interface ICToken { function isCToken() external returns (bool); function transfer(address dst, uint256 amount) external returns (bool); function transferFrom( address src, address dst, uint256 amount ) external returns (bool); function approve(address spender, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function balanceOfUnderlying(address owner) external returns (uint256); function getAccountSnapshot(address account) external view returns ( uint256, uint256, uint256, uint256 ); function borrowRatePerBlock() external view returns (uint256); function supplyRatePerBlock() external view returns (uint256); function totalBorrowsCurrent() external returns (uint256); function borrowBalanceCurrent(address account) external returns (uint256); function borrowBalanceStored(address account) external view returns (uint256); function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function getCash() external view returns (uint256); function seize( address liquidator, address borrower, uint256 seizeTokens ) external returns (uint256); function borrowRate() external returns (uint256); function borrowIndex() external view returns (uint256); function borrow(uint256) external returns (uint256); function repayBorrow(uint256) external returns (uint256); function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256); function liquidateBorrow( address borrower, uint256 repayAmount, address cTokenCollateral ) external returns (uint256); function underlying() external view returns (address); function mint(uint256) external returns (uint256); function redeemUnderlying(uint256) external returns (uint256); function accrueInterest() external returns (uint256); function totalSupply() external view returns (uint256); function totalBorrows() external view returns (uint256); function accrualBlockNumber() external view returns (uint256); function totalReserves() external view returns (uint256); function interestRateModel() external view returns (IInterestRateModel); function reserveFactorMantissa() external view returns (uint256); function initialExchangeRateMantissa() external view returns (uint256); /*** Admin Functions ***/ function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256); function _acceptAdmin() external returns (uint256); function _setComptroller(IComptroller newComptroller) external returns (uint256); function _setReserveFactor(uint256 newReserveFactorMantissa) external returns (uint256); function _reduceReserves(uint256 reduceAmount) external returns (uint256); function _setInterestRateModel(IInterestRateModel newInterestRateModel) external returns (uint256); } interface ICEther is ICToken { function mint() external payable; function repayBorrow() external payable; } interface ICompoundOracle { function getUnderlyingPrice(address) external view returns (uint256); }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; import "./IOracle.sol"; interface IIncentivesVault { function setOracle(IOracle _newOracle) external; function setMorphoDao(address _newMorphoDao) external; function setBonus(uint256 _newBonus) external; function setPauseStatus(bool _newStatus) external; function transferTokensToDao(address _token, uint256 _amount) external; function tradeCompForMorphoTokens(address _to, uint256 _amount) external; }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; import "./compound/ICompound.sol"; interface IRewardsManager { function initialize(address _morpho) external; function claimRewards(address[] calldata, address) external returns (uint256); function userUnclaimedCompRewards(address) external view returns (uint256); function compSupplierIndex(address, address) external view returns (uint256); function compBorrowerIndex(address, address) external view returns (uint256); function getLocalCompSupplyState(address _cTokenAddress) external view returns (IComptroller.CompMarketState memory); function getLocalCompBorrowState(address _cTokenAddress) external view returns (IComptroller.CompMarketState memory); function accrueUserSupplyUnclaimedRewards( address, address, uint256 ) external; function accrueUserBorrowUnclaimedRewards( address, address, uint256 ) external; }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; interface IInterestRatesManager { function updateP2PIndexes(address _marketAddress) external; }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; /// @title Double Linked List. /// @author Morpho Labs. /// @custom:contact [email protected] /// @notice Modified double linked list with capped sorting insertion. library DoubleLinkedList { /// STRUCTS /// struct Account { address prev; address next; uint256 value; } struct List { mapping(address => Account) accounts; address head; address tail; } /// ERRORS /// /// @notice Thrown when the account is already inserted in the double linked list. error AccountAlreadyInserted(); /// @notice Thrown when the account to remove does not exist. error AccountDoesNotExist(); /// @notice Thrown when the address is zero at insertion. error AddressIsZero(); /// @notice Thrown when the value is zero at insertion. error ValueIsZero(); /// INTERNAL /// /// @notice Returns the `account` linked to `_id`. /// @param _list The list to search in. /// @param _id The address of the account. /// @return The value of the account. function getValueOf(List storage _list, address _id) internal view returns (uint256) { return _list.accounts[_id].value; } /// @notice Returns the address at the head of the `_list`. /// @param _list The list to get the head. /// @return The address of the head. function getHead(List storage _list) internal view returns (address) { return _list.head; } /// @notice Returns the address at the tail of the `_list`. /// @param _list The list to get the tail. /// @return The address of the tail. function getTail(List storage _list) internal view returns (address) { return _list.tail; } /// @notice Returns the next id address from the current `_id`. /// @param _list The list to search in. /// @param _id The address of the account. /// @return The address of the next account. function getNext(List storage _list, address _id) internal view returns (address) { return _list.accounts[_id].next; } /// @notice Returns the previous id address from the current `_id`. /// @param _list The list to search in. /// @param _id The address of the account. /// @return The address of the previous account. function getPrev(List storage _list, address _id) internal view returns (address) { return _list.accounts[_id].prev; } /// @notice Removes an account of the `_list`. /// @param _list The list to search in. /// @param _id The address of the account. function remove(List storage _list, address _id) internal { if (_list.accounts[_id].value == 0) revert AccountDoesNotExist(); Account memory account = _list.accounts[_id]; if (account.prev != address(0)) _list.accounts[account.prev].next = account.next; else _list.head = account.next; if (account.next != address(0)) _list.accounts[account.next].prev = account.prev; else _list.tail = account.prev; delete _list.accounts[_id]; } /// @notice Inserts an account in the `_list` at the right slot based on its `_value`. /// @param _list The list to search in. /// @param _id The address of the account. /// @param _value The value of the account. /// @param _maxIterations The max number of iterations. function insertSorted( List storage _list, address _id, uint256 _value, uint256 _maxIterations ) internal { if (_value == 0) revert ValueIsZero(); if (_id == address(0)) revert AddressIsZero(); if (_list.accounts[_id].value != 0) revert AccountAlreadyInserted(); uint256 numberOfIterations; address next = _list.head; // If not added at the end of the list `_id` will be inserted before `next`. while ( numberOfIterations < _maxIterations && next != _list.tail && _list.accounts[next].value >= _value ) { next = _list.accounts[next].next; unchecked { ++numberOfIterations; } } // Account is not the new tail. if (next != address(0) && _list.accounts[next].value < _value) { // Account is the new head. if (next == _list.head) { _list.accounts[_id] = Account(address(0), next, _value); _list.head = _id; _list.accounts[next].prev = _id; } // Account is not the new head. else { _list.accounts[_id] = Account(_list.accounts[next].prev, next, _value); _list.accounts[_list.accounts[next].prev].next = _id; _list.accounts[next].prev = _id; } } // Account is the new tail. else { // Account is the new head. if (_list.head == address(0)) { _list.accounts[_id] = Account(address(0), address(0), _value); _list.head = _id; _list.tail = _id; } // Account is not the new head. else { _list.accounts[_id] = Account(_list.tail, address(0), _value); _list.accounts[_list.tail].next = _id; _list.tail = _id; } } } }
// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; /// @title Types. /// @author Morpho Labs. /// @custom:contact [email protected] /// @dev Common types and structs used in Moprho contracts. library Types { /// ENUMS /// enum PositionType { SUPPLIERS_IN_P2P, SUPPLIERS_ON_POOL, BORROWERS_IN_P2P, BORROWERS_ON_POOL } /// STRUCTS /// struct SupplyBalance { uint256 inP2P; // In supplier's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the peer-to-peer supply index to get the underlying amount. uint256 onPool; // In cToken. Multiply by the pool supply index to get the underlying amount. } struct BorrowBalance { uint256 inP2P; // In borrower's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the peer-to-peer borrow index to get the underlying amount. uint256 onPool; // In cdUnit, a unit that grows in value, to keep track of the debt increase when borrowers are on Compound. Multiply by the pool borrow index to get the underlying amount. } // Max gas to consume during the matching process for supply, borrow, withdraw and repay functions. struct MaxGasForMatching { uint64 supply; uint64 borrow; uint64 withdraw; uint64 repay; } struct Delta { uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the real peer-to-peer supply amount (in pool supply unit). uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the real peer-to-peer borrow amount (in pool borrow unit). uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply unit). uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow unit). } struct AssetLiquidityData { uint256 collateralValue; // The collateral value of the asset. uint256 maxDebtValue; // The maximum possible debt value of the asset. uint256 debtValue; // The debt value of the asset. uint256 underlyingPrice; // The price of the token. uint256 collateralFactor; // The liquidation threshold applied on this token. } struct LiquidityData { uint256 collateralValue; // The collateral value. uint256 maxDebtValue; // The maximum debt value possible. uint256 debtValue; // The debt value. } // Variables are packed together to save gas (will not exceed their limit during Morpho's lifetime). struct LastPoolIndexes { uint32 lastUpdateBlockNumber; // The last time the peer-to-peer indexes were updated. uint112 lastSupplyPoolIndex; // Last pool supply index. uint112 lastBorrowPoolIndex; // Last pool borrow index. } struct MarketParameters { uint16 reserveFactor; // Proportion of the interest earned by users sent to the DAO for each market, in basis point (100% = 10 000). The value is set at market creation. uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine the weights of the weighted arithmetic average in the indexes computations ((1 - p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point). } struct MarketStatus { bool isCreated; // Whether or not this market is created. bool isPaused; // Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate). bool isPartiallyPaused; // Whether the market is partially paused or not (only supply and borrow are frozen). } }
// 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 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @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: GNU AGPLv3 pragma solidity ^0.8.0; interface IOracle { function consult(uint256 _amountIn) external returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; 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. * * 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 initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "remappings": [ "@aave/core-v3/=lib/aave-v3-core/", "@aave/periphery-v3/=lib/aave-v3-periphery/", "@config/=config/goerli/compound/", "@contracts/=contracts/", "@ensdomains/=node_modules/@ensdomains/", "@morpho/data-structures/=lib/data-structures/", "@openzeppelin/=node_modules/@openzeppelin/", "@rari-capital/solmate/=lib/solmate/", "@uniswap/=node_modules/@uniswap/", "aave-v3-core/=lib/aave-v3-core/", "aave-v3-periphery/=lib/aave-v3-periphery/contracts/", "base64-sol/=node_modules/base64-sol/", "ds-test/=lib/solmate/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "solmate/=lib/solmate/src/", "compound/=contracts/compound/", "test/=test/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "debug": { "revertStrings": "default" }, "libraries": {} }
[{"inputs":[],"name":"AccountAlreadyInserted","type":"error"},{"inputs":[],"name":"AccountDoesNotExist","type":"error"},{"inputs":[],"name":"AddressIsZero","type":"error"},{"inputs":[],"name":"AddressIsZero","type":"error"},{"inputs":[],"name":"AmountAboveWhatAllowedToRepay","type":"error"},{"inputs":[],"name":"AmountIsZero","type":"error"},{"inputs":[],"name":"BorrowOnCompoundFailed","type":"error"},{"inputs":[],"name":"CompoundOracleFailed","type":"error"},{"inputs":[],"name":"LowLevelDelegateCallFailed","type":"error"},{"inputs":[],"name":"MarketNotCreated","type":"error"},{"inputs":[],"name":"MarketPaused","type":"error"},{"inputs":[],"name":"MintOnCompoundFailed","type":"error"},{"inputs":[],"name":"RedeemOnCompoundFailed","type":"error"},{"inputs":[],"name":"RepayOnCompoundFailed","type":"error"},{"inputs":[],"name":"SameBlockBorrowRepay","type":"error"},{"inputs":[],"name":"UnauthorisedBorrow","type":"error"},{"inputs":[],"name":"UnauthorisedLiquidate","type":"error"},{"inputs":[],"name":"UnauthorisedWithdraw","type":"error"},{"inputs":[],"name":"UserNotMemberOfMarket","type":"error"},{"inputs":[],"name":"ValueIsZero","type":"error"},{"inputs":[],"name":"WithdrawTooSmall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"Borrowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"BorrowerPositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"_liquidated","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenBorrowedAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountRepaid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_poolTokenCollateralAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountSeized","type":"uint256"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_p2pSupplyAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_p2pBorrowAmount","type":"uint256"}],"name":"P2PAmountsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_p2pBorrowDelta","type":"uint256"}],"name":"P2PBorrowDeltaUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_p2pSupplyDelta","type":"uint256"}],"name":"P2PSupplyDeltaUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_repayer","type":"address"},{"indexed":true,"internalType":"address","name":"_onBehalf","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"Repaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_supplier","type":"address"},{"indexed":true,"internalType":"address","name":"_onBehalf","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"Supplied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"SupplierPositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_supplier","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":true,"internalType":"address","name":"_poolTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceOnPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_balanceInP2P","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"CTOKEN_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BASIS_POINTS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"borrowBalanceInOf","outputs":[{"internalType":"uint256","name":"inP2P","type":"uint256"},{"internalType":"uint256","name":"onPool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxGasForMatching","type":"uint256"}],"name":"borrowLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cEth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract IComptroller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultMaxGasForMatching","outputs":[{"internalType":"uint64","name":"supply","type":"uint64"},{"internalType":"uint64","name":"borrow","type":"uint64"},{"internalType":"uint64","name":"withdraw","type":"uint64"},{"internalType":"uint64","name":"repay","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deltas","outputs":[{"internalType":"uint256","name":"p2pSupplyDelta","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowDelta","type":"uint256"},{"internalType":"uint256","name":"p2pSupplyAmount","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dustThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"enteredMarkets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"address[]","name":"marketsCreated_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getEnteredMarkets","outputs":[{"internalType":"address[]","name":"enteredMarkets_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"enum Types.PositionType","name":"_positionType","type":"uint8"}],"name":"getHead","outputs":[{"internalType":"address","name":"head","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"enum Types.PositionType","name":"_positionType","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"getNext","outputs":[{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentivesVault","outputs":[{"internalType":"contract IIncentivesVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRatesManager","outputs":[{"internalType":"contract IInterestRatesManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isClaimRewardsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastBorrowBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastPoolIndexes","outputs":[{"internalType":"uint32","name":"lastUpdateBlockNumber","type":"uint32"},{"internalType":"uint112","name":"lastSupplyPoolIndex","type":"uint112"},{"internalType":"uint112","name":"lastBorrowPoolIndex","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenBorrowedAddress","type":"address"},{"internalType":"address","name":"_poolTokenCollateralAddress","type":"address"},{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"liquidateLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"marketParameters","outputs":[{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"uint16","name":"p2pIndexCursor","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"marketStatus","outputs":[{"internalType":"bool","name":"isCreated","type":"bool"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"bool","name":"isPartiallyPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"marketsCreated","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSortedUsers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"p2pBorrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"p2pDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"p2pSupplyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionsManager","outputs":[{"internalType":"contract IPositionsManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"address","name":"_repayer","type":"address"},{"internalType":"address","name":"_onBehalf","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxGasForMatching","type":"uint256"}],"name":"repayLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsManager","outputs":[{"internalType":"contract IRewardsManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"supplyBalanceInOf","outputs":[{"internalType":"uint256","name":"inP2P","type":"uint256"},{"internalType":"uint256","name":"onPool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"address","name":"_supplier","type":"address"},{"internalType":"address","name":"_onBehalf","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxGasForMatching","type":"uint256"}],"name":"supplyLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"updateP2PIndexes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wEth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_supplier","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_maxGasForMatching","type":"uint256"}],"name":"withdrawLogic","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50600054610100900460ff166200002f5760005460ff161562000039565b62000039620000de565b620000a15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000c4576000805461ffff19166101011790555b8015620000d7576000805461ff00191690555b506200010b565b6000620000f630620000fc60201b62001c961760201c565b15905090565b6001600160a01b03163b151590565b6157f5806200011b6000396000f3fe608060405234801561001057600080fd5b50600436106102535760003560e01c8063a086fc2211610146578063d59c9eb6116100c3578063e501ed0411610087578063e501ed04146106bc578063e61c6d6f146106ee578063e8462e8f146106f7578063f2f4ca1614610700578063f2fde38b1461076c578063f4ea93d81461077f57600080fd5b8063d59c9eb6146105bf578063db0577fd14610614578063defe205314610683578063df6d921214610696578063e34b5145146106a957600080fd5b8063b24be6871161010a578063b24be68714610559578063b59ec4781461056c578063b6f2bf1c1461058c578063c2af97871461059f578063cb830d03146105b257600080fd5b8063a086fc22146104c3578063a44026a314610518578063ac0b4b121461052b578063af8b1c6f1461053e578063b0772d0b1461055157600080fd5b80637907016a116101d45780638da5cb5b116101985780638da5cb5b146103f5578063947574ac1461040657806396bd512c1461044d5780639df5a1f2146104965780639fab1036146104b057600080fd5b80637907016a1461037c5780637f3ad0561461038f578063854f7ebb146103a257806385d7334d146103c25780638ccb720b146103d557600080fd5b80635fe3b5671161021b5780635fe3b567146103115780636a14602414610324578063715018a614610333578063720ceb021461033b578063789caa3e1461036957600080fd5b806320c342d9146102585780632ebf4be0146102905780633528e4ce146102be57806352f0f814146102d35780635acff027146102fe575b600080fd5b61027b610266366004615369565b60a36020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102b061029e366004615369565b60a56020526000908152604090205481565b604051908152602001610287565b6102d16102cc366004615369565b61079b565b005b60aa546102e6906001600160a01b031681565b6040516001600160a01b039091168152602001610287565b6102e661030c366004615395565b6107e3565b60ae546102e6906001600160a01b031681565b6102b0670de0b6b3a764000081565b6102d16108dc565b61027b6103493660046153ca565b60a060209081526000928352604080842090915290825290205460ff1681565b6102e6610377366004615403565b610947565b6102d161038a36600461544c565b610a45565b60ad546102e6906001600160a01b031681565b6102b06103b0366004615369565b60a46020526000908152604090205481565b6102d16103d036600461549d565b610e88565b6103e86103e3366004615369565b6113ae565b60405161028791906154f8565b6033546001600160a01b03166102e6565b6104386104143660046153ca565b609f6020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610287565b61047b61045b366004615369565b60a76020526000908152604090205461ffff808216916201000090041682565b6040805161ffff938416815292909116602083015201610287565b61049e600881565b60405160ff9091168152602001610287565b6102d16104be366004615545565b611424565b6104f86104d1366004615369565b60a96020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610287565b60b0546102e6906001600160a01b031681565b6102e661053936600461557a565b6119ac565b60af546102e6906001600160a01b031681565b6103e86119d6565b60ab546102e6906001600160a01b031681565b6102b061057a366004615369565b60b26020526000908152604090205481565b6102d161059a366004615593565b611a38565b6102d16105ad36600461549d565b611aff565b60b35461027b9060ff1681565b6105f56105cd366004615369565b60a86020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805193151584529115156020840152151590820152606001610287565b610657610622366004615369565b60a66020526000908152604090205463ffffffff8116906001600160701b036401000000008204811691600160901b90041683565b6040805163ffffffff90941684526001600160701b039283166020850152911690820152606001610287565b60ac546102e6906001600160a01b031681565b60b1546102e6906001600160a01b031681565b6102e66106b73660046155ee565b611b93565b6104386106ca3660046153ca565b609e6020908152600092835260408084209091529082529020805460019091015482565b6102b060975481565b6102b060985481565b6099546107389067ffffffffffffffff80821691680100000000000000008104821691600160801b8204811691600160c01b90041684565b6040805167ffffffffffffffff95861681529385166020850152918416918301919091529091166060820152608001610287565b6102d161077a366004615369565b611bcb565b61078861271081565b60405161ffff9091168152602001610287565b6001600160a01b038116600090815260a86020526040902054819060ff166107d6576040516396e1352960e01b815260040160405180910390fd5b6107df82611ca5565b5050565b6000808260038111156107f8576107f861561a565b03610823576001600160a01b038381166000908152609a6020526040902060010154165b90506108d6565b60018260038111156108375761083761561a565b0361085f576001600160a01b038381166000908152609b60205260409020600101541661081c565b60028260038111156108735761087361561a565b0361089b576001600160a01b038381166000908152609c60205260409020600101541661081c565b60038260038111156108af576108af61561a565b036108d6576001600160a01b038381166000908152609d6020526040902060010154165b90505b92915050565b6033546001600160a01b0316331461093b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6109456000611cf7565b565b60008083600381111561095c5761095c61561a565b0361098a576001600160a01b0384166000908152609a602052604090206109839083611d49565b9050610a3e565b600183600381111561099e5761099e61561a565b036109c5576001600160a01b0384166000908152609b602052604090206109839083611d49565b60028360038111156109d9576109d961561a565b03610a00576001600160a01b0384166000908152609c602052604090206109839083611d49565b6003836003811115610a1457610a1461561a565b03610a3e576001600160a01b0384166000908152609d60205260409020610a3b9083611d49565b90505b9392505050565b6001600160a01b03808516600090815260a0602090815260408083209386168352929052205460ff161580610aa057506001600160a01b03808416600090815260a0602090815260408083209386168352929052205460ff16155b15610abe576040516301187a4360e61b815260040160405180910390fd5b610ac784611ca5565b610ad083611ca5565b610ade826000806000611d6c565b610afb5760405163b3165ffd60e01b815260040160405180910390fd5b610b2d6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b610b378584611f2d565b60208083019190915260ae546040805163743aaa2360e11b81529051610bb8936001600160a01b039093169263e875544692600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bad9190615630565b602083015190611fdd565b821115610bd857604051633b1b989f60e01b815260040160405180910390fd5b610be6853385856000611ffc565b60ae54604080516307dc0d1d60e41b815290516000926001600160a01b031691637dc0d1d09160048083019260209291908290030181865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190615649565b60405163fc57d4df60e01b81526001600160a01b0387811660048301529192509082169063fc57d4df90602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190615630565b825260405163fc57d4df60e01b81526001600160a01b03878116600483015282169063fc57d4df90602401602060405180830381865afa158015610d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2e9190615630565b606083015281511580610d4357506060820151155b15610d6157604051634b6b62e560e01b815260040160405180910390fd5b610e10610e018360000151610dfb8560600151610df560ae60009054906101000a90046001600160a01b03166001600160a01b0316634ada90af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dee9190615630565b8990611fdd565b90611fdd565b90612999565b610e0b87876129cb565b612a69565b60808301819052610e2690869086336000612a7f565b60808201516040805133815260208101869052908101919091526001600160a01b0380871691888216918716907fc2c75a73164c2efcbb9f74bfa511cd0866489d90687831a7217b3dbeeb6970889060600160405180910390a4505050505050565b6001600160a01b038316610eaf5760405163867915ab60e01b815260040160405180910390fd5b81600003610ed0576040516310eb483f60e21b815260040160405180910390fd5b610ed985611ca5565b610ee3858461341a565b6000610eee866134a6565b9050610f056001600160a01b038216863086613537565b6001600160a01b038616600090815260a960209081526040808320815160608101835284815292830184905290820192909252876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a9190615630565b6020820152848152600182015415611096576000610fc982602001518460010154611fdd90919063ffffffff16565b825190915081111561101c578151604083018051610fe890839061567c565b90525060208201518251610ffb91612999565b83600101600082825461100e9190615694565b90915550506000825261104d565b808260400181815161102e919061567c565b90525060006001840155815181908390611049908390615694565b9052505b886001600160a01b03167f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df6846001015460405161108c91815260200190565b60405180910390a2505b8051158015906110bf57506001600160a01b038816600090815260a3602052604090205460ff16155b80156110fe57506001600160a01b0388166000908152609d602052604081206110f290600101546001600160a01b031690565b6001600160a01b031614155b15611185576000611114898360000151876135ba565b509050801561118357808260400181815161112f919061567c565b905250815181908390611143908390615694565b9052506001600160a01b038916600090815260a5602052604090205461116a908290612999565b83600301600082825461117d919061567c565b90915550505b505b604081015115611262576001600160a01b038816600090815260a4602052604080822054908301516111b691612999565b9050808360020160008282546111cc919061567c565b90915550506001600160a01b03808a166000908152609e60209081526040808320938b168352929052908120805483929061120890849061567c565b9250508190555061121e89858460400151613853565b886001600160a01b03166000805160206157a083398151915284600201548560030154604051611258929190918252602082015260400190565b60405180910390a2505b805115611324576112d6886001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615630565b825190612999565b6001600160a01b03808a166000908152609e60209081526040808320938b168352929052908120600101805490919061131090849061567c565b909155505080516113249089908590613a3a565b61132e8887613b86565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518c8152938401919091529082015291929091908a16907f11adb3570ba55fd255b1f04252ca0071ae6639c86d4fd69e7c1bf1688afb493f906060015b60405180910390a45050505050505050565b6001600160a01b038116600090815260a1602090815260409182902080548351818402810184019094528084526060939283018282801561141857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113fa575b50505050509050919050565b81600003611445576040516310eb483f60e21b815260040160405180910390fd5b61144e83611ca5565b611458833361341a565b33600081815260b2602052604081204390556114779190859085611d6c565b156114955760405163df9db46360e01b815260040160405180910390fd5b60006114a0846134a6565b6001600160a01b038516600081815260a960209081526040808320815163182df0f560e01b815291519596508895939490938593919263182df0f59260048083019391928290030181865afa1580156114fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115219190615630565b604051633af9e66960e01b81523060048201529091506000906001600160a01b038a1690633af9e669906024016020604051808303816000875af115801561156d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115919190615630565b83549091501561166c5782546000906115aa9084611fdd565b9050858111806115b957508181115b1561160d5760006115ca8784612a69565b90506115d6818761567c565b95506115e28185612999565b8560000160008282546115f59190615694565b9091555061160590508188615694565b96505061162a565b611617818661567c565b6000855594506116278187615694565b95505b83546040519081526001600160a01b038b16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a2505b60008511801561169557506001600160a01b038916600090815260a3602052604090205460ff16155b80156116d457506001600160a01b0389166000908152609b602052604081206116c890600101546001600160a01b031690565b6001600160a01b031614155b1561176c5760006116f38a6116ed88610e0b8987615694565b8a613d99565b509050801561176a57611706818661567c565b94506117128187615694565b6001600160a01b038b16600090815260a46020526040902054909650611739908290612999565b6001600160a01b038b16600090815260a960205260408120600201805490919061176490849061567c565b90915550505b505b8315611863576001600160a01b038916600090815260a56020526040812054611796908690612999565b6001600160a01b038b16600090815260a960205260408120600301805492935083929091906117c690849061567c565b90915550506001600160a01b038a166000908152609f60209081526040808320338452909152812080548392906117fe90849061567c565b9091555050600284015460038501546040516001600160a01b038d16926000805160206157a08339815191529261183d92918252602082015260400190565b60405180910390a260006118518685612999565b1115611861576118618a86614014565b505b841561191b576118d5896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ce9190615630565b8690612999565b6001600160a01b038a166000908152609f602090815260408083203384529091528120600101805490919061190b90849061567c565b9091555061191b90508986614120565b61192589336141a9565b6119396001600160a01b038716338a614386565b6001600160a01b0389166000818152609f6020908152604080832033808552908352928190206001810154905482518e81529384019190915282820152517fc1cba78646fef030830d099fc25cb498953709c9d47d883848f81fd207174c9f9181900360600190a3505050505050505050565b60a281815481106119bc57600080fd5b6000918252602090912001546001600160a01b0316905081565b606060a2805480602002602001604051908101604052809291908181526020018280548015611a2e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611a10575b5050505050905090565b83600003611a59576040516310eb483f60e21b815260040160405180910390fd5b6001600160a01b03808616600090815260a0602090815260408083209387168352929052205460ff16611a9f576040516301187a4360e61b815260040160405180910390fd5b611aa885611ca5565b6000611abd611ab787866129cb565b86612a69565b9050611acc8487836000611d6c565b15611aea57604051630cba3c5f60e21b815260040160405180910390fd5b611af78682868686612a7f565b505050505050565b81600003611b20576040516310eb483f60e21b815260040160405180910390fd5b6001600160a01b03808616600090815260a0602090815260408083209387168352929052205460ff16611b66576040516301187a4360e61b815260040160405180910390fd5b611b6f85611ca5565b6000611b84611b7e8786611f2d565b84612a69565b9050611af78686868486611ffc565b60a16020528160005260406000208181548110611baf57600080fd5b6000918252602090912001546001600160a01b03169150829050565b6033546001600160a01b03163314611c255760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610932565b6001600160a01b038116611c8a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610932565b611c9381611cf7565b50565b6001600160a01b03163b151590565b604080516001600160a01b038381166024808401919091528351808403909101815260449092019092526020810180516001600160e01b0316631a94726760e11b17905260ad546107df921690614404565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0390811660009081526020929092526040909120600101541690565b60008060ae60009054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de69190615649565b6001600160a01b038716600090815260a16020908152604080832054815160a08101835284815292830184905290820183905260608201839052608082018390529293509080805b84811015611f1f576001600160a01b038b16600090815260a160205260408120805483908110611e6057611e606156ab565b6000918252602090912001546001600160a01b03169050611e828c828961449e565b9450846020015184611e94919061567c565b9350846040015183611ea6919061567c565b9250806001600160a01b03168b6001600160a01b031603611f16578815611ee4576060850151611ed7908a90611fdd565b611ee1908461567c565b92505b8915611f1657611f098560800151610df587606001518d611fdd90919063ffffffff16565b611f139085615694565b93505b50600101611e2e565b501198975050505050505050565b6001600160a01b038083166000818152609f602090815260408083209486168352938152838220845180860186528154815260019091015481830152845163aa5af0fd60e01b8152945192949093611fa793909263aa5af0fd92600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b6001600160a01b038516600090815260a560205260409020548251611fcb91611fdd565b611fd5919061567c565b949350505050565b6000670de0b6b3a7640000611ff283856156c1565b6108d391906156e0565b6001600160a01b038316600090815260b260205260409020544390036120355760405163dff88f5160e01b815260040160405180910390fd5b6000612040866134a6565b90506120576001600160a01b038216863086613537565b6120a66040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60208082018590528382526040805163aa5af0fd60e01b815290516001600160a01b038a169263aa5af0fd92600480820193918290030181865afa1580156120f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121169190615630565b60608201526001600160a01b038088166000908152609f602090815260408083209389168352929052206001015460c08201819052156122c457606081015160c082015161216391611fdd565b6040820181905260208201511015612277576020810151610100820181905260c0820151606083015161219992610e0b91612999565b6001600160a01b038089166000908152609f60209081526040808320938a16835292905290812060010180549091906121d3908490615694565b909155506121e3905087866141a9565b6121f38783836101000151613853565b6121fd878661461f565b6001600160a01b038781166000818152609f602090815260408083208a8616808552908352928190206001810154905482518b815293840191909152828201525192939192918a16917f7b417e520d2b905fc5a1689d29d329358dd55efc60ed115aa165b0a2b64232c69181900360600190a45050612992565b60408101516101008201819052602082018051612295908390615694565b9052506001600160a01b038088166000908152609f602090815260408083209389168352929052908120600101555b6001600160a01b03808816600081815260a96020908152604080832060a4835281842054608088015284845260a583528184205460a08801908152948452609f8352818420958b1684529482529091205491519084015161232a9291610e0b9190612999565b6001600160a01b03808a166000908152609f60209081526040808320938b1683529290529081208054909190612361908490615694565b90915550612371905088876141a9565b60008260200151118015612389575060008160010154115b1561251f5760006123ab83606001518360010154611fdd90919063ffffffff16565b9050826020015181111561243557606083015160208401516123cc91612999565b8260010160008282546123df9190615694565b909155505060a083015160208401516123f791612999565b82600301600082825461240a9190615694565b909155505060208301516101008401805161242690839061567c565b90525060006020840152612494565b6000600183015560a083015161244c908290612999565b82600301600082825461245f9190615694565b92505081905550808361010001818151612479919061567c565b905250602083018051829190612490908390615694565b9052505b886001600160a01b03167f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df683600101546040516124d391815260200190565b60405180910390a2886001600160a01b03166000805160206157a083398151915283600201548460030154604051612515929190918252602082015260400190565b60405180910390a2505b602082015115612679576125d66125478360a001518360030154611fdd90919063ffffffff16565b6125b48a6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ac9190615630565b845490611fdd565b608085015160028501546125c791611fdd565b6125d19190615694565b614897565b60e08301819052156126795760006125f68360e001518460200151612a69565b9050808360200181815161260a9190615694565b90525060a083015161261d908290612999565b8260030160008282546126309190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a08339815191529261266f92918252602082015260400190565b60405180910390a2505b600082602001511180156126a657506001600160a01b038816600090815260a3602052604090205460ff16155b80156126e557506001600160a01b0388166000908152609d602052604081206126d990600101546001600160a01b031690565b6001600160a01b031614155b15612765576000806127008a856020015186600001516135ba565b9150915080846000015111612718576000845261272e565b808460000181815161272a9190615694565b9052505b81156127625781846020018181516127469190615694565b9052506101008401805183919061275e90839061567c565b9052505b50505b6127758884846101000151613853565b60208201511561291657600061279489846020015185600001516148b2565b9050826020015181101561287057612817896001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128079190615630565b828560200151610dfb9190615694565b82600001600082825461282a919061567c565b909155505081546040519081526001600160a01b038a16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a25b6080830151612880908290612999565b8260020160008282546128939190615694565b909155505060a083015160208401516128ab91612999565b8260030160008282546128be9190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a0833981519152926128fd92918252602082015260400190565b60405180910390a261291489858560200151613a3a565b505b612920888761461f565b6001600160a01b038881166000818152609f602090815260408083208b8616808552908352928190206001810154905482518c8152938401919091529082015291929091908a16907f7b417e520d2b905fc5a1689d29d329358dd55efc60ed115aa165b0a2b64232c69060600161139c565b5050505050565b6000670de0b6b3a7640000826129af85836156c1565b6129c190670de0b6b3a76400006156c1565b611ff291906156e0565b6001600160a01b038083166000818152609e602090815260408083209486168352938152838220845180860186528154815260019091015481830152845163182df0f560e01b8152945192949093612a4593909263182df0f592600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b6001600160a01b038516600090815260a460205260409020548251611fcb91611fdd565b6000818310612a7857816108d3565b5090919050565b83600003612aa0576040516310eb483f60e21b815260040160405180910390fd5b612ae96040518060e0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b612af2866134a6565b6001600160a01b0390811660c083015260208201869052828252604051633af9e66960e01b815230600482015290871690633af9e669906024016020604051808303816000875af1158015612b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6f9190615630565b816080018181525050856001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bda9190615630565b60408201819052612bec908690612999565b600003612c0c576040516393c76c6f60e01b815260040160405180910390fd5b6001600160a01b038087166000908152609e60209081526040808320938816835292905220600101548015612e23576000612c54836040015183611fdd90919063ffffffff16565b90508260200151811180612c6b5750826080015181115b15612cf557612c8283602001518460800151612a69565b60a08401819052602084018051612c9a908390615694565b905250604083015160a0840151612cb091612999565b6001600160a01b03808a166000908152609e60209081526040808320938b1683529290529081206001018054909190612cea908490615694565b90915550612d3f9050565b60a08301819052602083018051829190612d10908390615694565b9052506001600160a01b038089166000908152609e60209081526040808320938a168352929052908120600101555b8260200151600003612e2157612d558887613b86565b612d5f888761461f565b6000612d7c84604001518560a0015161299990919063ffffffff16565b1115612d9057612d90888460a00151614014565b60c0830151612da9906001600160a01b03168689614386565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518e815293840191909152828201525192938916927f378f9d375cd79e36c19c26a9e57791fe7cd5953b61986c01ebf980c0efb928019181900360600190a4505050612992565b505b6001600160a01b03808816600081815260a96020908152604080832060a483528184205460608901908152948452609e8352818420958b16845294825290912054915190850151612e799291610e0b9190612999565b6001600160a01b03808a166000908152609e60209081526040808320938b1683529290529081208054909190612eb0908490615694565b90915550612ec090508887613b86565b60008360200151118015612ed45750805415155b156130a15760408301518154600091612eed9190611fdd565b90508360200151811180612f1357508360a001518460800151612f109190615694565b81115b15612fc4576000612f3685602001518660a001518760800151610e0b9190615694565b9050612f4f85604001518261299990919063ffffffff16565b836000016000828254612f629190615694565b90915550506060850151612f77908290612999565b836002016000828254612f8a9190615694565b92505081905550808560a001818151612fa3919061567c565b905250602085018051829190612fba908390615694565b90525061301d9050565b808460a001818151612fd6919061567c565b905250602084018051829190612fed908390615694565b905250600082556060840151613004908290612999565b8260020160008282546130179190615694565b90915550505b81546040519081526001600160a01b038a16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a2886001600160a01b03166000805160206157a083398151915283600201548460030154604051613097929190918252602082015260400190565b60405180910390a2505b600083602001511180156130ce57506001600160a01b038816600090815260a3602052604090205460ff16155b801561310d57506001600160a01b0388166000908152609b6020526040812061310190600101546001600160a01b031690565b6001600160a01b031614155b156131a05760008061313c8a61313587602001518860a001518960800151610e0b9190615694565b8751613d99565b9150915080856000015111613154576000855261316a565b80856000018181516131669190615694565b9052505b811561319d5781856020018181516131829190615694565b90525060a08501805183919061319990839061567c565b9052505b50505b60006131bd84604001518560a0015161299990919063ffffffff16565b11156131d1576131d1888460a00151614014565b6020830151156133885760006131f08985602001518660000151614b35565b905083602001518110156132cf57613273896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561323f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132639190615630565b828660200151610dfb9190615694565b826001016000828254613286919061567c565b909155505060018201546040519081526001600160a01b038a16907f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df69060200160405180910390a25b606084015160208501516132e291612999565b8260020160008282546132f59190615694565b90915550506001600160a01b038916600090815260a5602052604090205461331e908290612999565b8260030160008282546133319190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a08339815191529261337092918252602082015260400190565b60405180910390a2613386898560200151614120565b505b613392888761461f565b60c08301516133ab906001600160a01b03168689614386565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518e8152938401919091529082015291928816917f378f9d375cd79e36c19c26a9e57791fe7cd5953b61986c01ebf980c0efb928019060600161139c565b6001600160a01b03808316600090815260a0602090815260408083209385168352929052205460ff166107df576001600160a01b03808316600081815260a0602090815260408083209486168352938152838220805460ff1916600190811790915560a18252938220805494850181558252902090910180546001600160a01b03191690911790555050565b60b0546000906001600160a01b03908116908316036134d057505060b1546001600160a01b031690565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d69190615649565b919050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129925760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610932565b600080826000036135d05750600090508061384b565b6136026040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136649190615630565b6040808301919091526001600160a01b038716600090815260a5602052908120548252805a60808401525b86851080156136d457506001600160a01b0388166000908152609d602052604081206136c590600101546001600160a01b031690565b9250826001600160a01b031614155b80156136ee5750855a84608001516136ec9190615694565b105b1561383557506001600160a01b038088166000908152609f60209081526040808320938516835292905281902090830151600182015461372d91611fdd565b606084015260008080613740888b615694565b905080866060015111613782578551606087015161375d91612999565b8454613769919061567c565b915085606001518861377b919061567c565b97506137c3565b6040860151613792908290612999565b84600101546137a19190615694565b86519093506137b1908290612999565b84546137bd919061567c565b91508997505b600184018390558184556137d78b866141a9565b8a6001600160a01b0316856001600160a01b03167f0aec3812ec00f2d2f0eacc89fd13923091a68f30c3b3d0336e364544322b97588585604051613825929190918252602082015260400190565b60405180910390a350505061368f565b5a83608001516138459190615694565b93505050505b935093915050565b6040516305eff7ef60e21b81523060048201526138c39082906001600160a01b038616906317bfdfbc906024016020604051808303816000875af115801561389f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0b9190615630565b90508015613a355760b0546001600160a01b03908116908416036139985760b154604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b15801561392757600080fd5b505af115801561393b573d6000803e3d6000fd5b50505050826001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397a57600080fd5b505af115801561398e573d6000803e3d6000fd5b5050505050505050565b6139ac6001600160a01b0383168483614da2565b60405163073a938160e11b8152600481018290526001600160a01b03841690630e752702906024016020604051808303816000875af11580156139f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a179190615630565b15613a3557604051637112354b60e01b815260040160405180910390fd5b505050565b60b0546001600160a01b0390811690841603613ae95760b154604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015613a9657600080fd5b505af1158015613aaa573d6000803e3d6000fd5b50505050826001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397a57600080fd5b613afd6001600160a01b0383168483614da2565b60405163140e25ad60e31b8152600481018290526001600160a01b0384169063a0712d68906024016020604051808303816000875af1158015613b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b689190615630565b15613a355760405163757d648760e11b815260040160405180910390fd5b6001600160a01b038281166000818152609e6020908152604080832094861680845294825280832060018101549054858552609b84528285208786528452828520600290810154968652609a855283862097865296909352922090930154609854919392918411613c21576001600160a01b038087166000908152609e60209081526040808320938916835292905290812060010181905593505b838214613c7e578115613c50576001600160a01b0386166000908152609b60205260409020613c509086614e19565b8315613c7e576097546001600160a01b0387166000908152609b60205260409020613c7e9187908790614fae565b6098548311613cb4576001600160a01b038087166000908152609e60209081526040808320938916835292905290812081905592505b828114613d11578015613ce3576001600160a01b0386166000908152609a60205260409020613ce39086614e19565b8215613d11576097546001600160a01b0387166000908152609a60205260409020613d119187908690614fae565b60ac546001600160a01b031615611af75760ac5460405163636c55d360e01b81526001600160a01b0387811660048301528881166024830152604482018590529091169063636c55d3906064015b600060405180830381600087803b158015613d7957600080fd5b505af1158015613d8d573d6000803e3d6000fd5b50505050505050505050565b60008082600003613daf5750600090508061384b565b613de16040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b856001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e439190615630565b6040808301919091526001600160a01b038716600090815260a4602052908120548252805a60808401525b8685108015613eb357506001600160a01b0388166000908152609b60205260408120613ea490600101546001600160a01b031690565b9250826001600160a01b031614155b8015613ecd5750855a8460800151613ecb9190615694565b105b1561383557506001600160a01b038088166000908152609e602090815260408083209385168352929052819020908301516001820154613f0c91611fdd565b606084015260008080613f1f888b615694565b905080866060015111613f615785516060870151613f3c91612999565b8454613f48919061567c565b9150856060015188613f5a919061567c565b9750613fa2565b6040860151613f71908290612999565b8460010154613f809190615694565b8651909350613f90908290612999565b8454613f9c919061567c565b91508997505b60018401839055818455613fb68b86613b86565b8a6001600160a01b0316856001600160a01b03167f76908587112671ab2dcd9323f0d9b27d193156f95fe5e1251411a151c20e82dd8585604051614004929190918252602082015260400190565b60405180910390a3505050613e6e565b60405163852a12e360e01b8152600481018290526001600160a01b0383169063852a12e3906024016020604051808303816000875af115801561405b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407f9190615630565b1561409d57604051637d47a0c360e01b815260040160405180910390fd5b60b0546001600160a01b03908116908316036107df5760b160009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561410357600080fd5b505af1158015614117573d6000803e3d6000fd5b50505050505050565b60405163317afabb60e21b8152600481018290526001600160a01b0383169063c5ebeaec906024016020604051808303816000875af1158015614167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061418b9190615630565b1561409d576040516302738d6b60e11b815260040160405180910390fd5b6001600160a01b038281166000818152609f6020908152604080832094861680845294825280832060018101549054858552609d84528285208786528452828520600290810154968652609c855283862097865296909352922090930154609854919392918411614244576001600160a01b038087166000908152609f60209081526040808320938916835292905290812060010181905593505b8382146142a1578115614273576001600160a01b0386166000908152609d602052604090206142739086614e19565b83156142a1576097546001600160a01b0387166000908152609d602052604090206142a19187908790614fae565b60985483116142d7576001600160a01b038087166000908152609f60209081526040808320938916835292905290812081905592505b828114614334578015614306576001600160a01b0386166000908152609c602052604090206143069086614e19565b8215614334576097546001600160a01b0387166000908152609c602052604090206143349187908690614fae565b60ac546001600160a01b031615611af75760ac5460405163a9de645d60e01b81526001600160a01b0387811660048301528881166024830152604482018590529091169063a9de645d90606401613d5f565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806143fe5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610932565b50505050565b6060600080846001600160a01b0316846040516144219190615702565b600060405180830381855af49150503d806000811461445c576040519150601f19603f3d011682016040523d82523d6000602084013e614461565b606091505b509150915081156144755791506108d69050565b8051156144855780518082602001fd5b60405163037b81af60e11b815260040160405180910390fd5b6144d06040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405163fc57d4df60e01b81526001600160a01b03848116600483015283169063fc57d4df90602401602060405180830381865afa158015614516573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061453a9190615630565b6060820181905260000361456157604051634b6b62e560e01b815260040160405180910390fd5b60ae54604051638e8f294b60e01b81526001600160a01b03858116600483015290911690638e8f294b90602401606060405180830381865afa1580156145ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145cf919061574d565b5060808301525060608101516145e990610df585876129cb565b815260608101516145fe90610df58587611f2d565b60408201526080810151815161461391611fdd565b60208201529392505050565b6001600160a01b03808316600090815260a0602090815260408083209385168352929052205460ff16801561467757506001600160a01b038083166000908152609e6020908152604080832093851683529290522054155b80156146a957506001600160a01b038083166000908152609e6020908152604080832093851683529290522060010154155b80156146d857506001600160a01b038083166000908152609f6020908152604080832093851683529290522054155b801561470a57506001600160a01b038083166000908152609f6020908152604080832093851683529290522060010154155b156107df5760005b6001600160a01b03828116600090815260a16020526040902080549185169183908110614741576147416156ab565b6000918252602090912001546001600160a01b03161461476357600101614712565b6001600160a01b03808416600090815260a0602090815260408083209386168352928152828220805460ff1916905560a1905220546147a3600182615694565b8214614848576001600160a01b038316600090815260a1602052604090206147cc600183615694565b815481106147dc576147dc6156ab565b60009182526020808320909101546001600160a01b03868116845260a19092526040909220805491909216919084908110614819576148196156ab565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6001600160a01b038316600090815260a16020526040902080548061486f5761486f615789565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b6000818310156148a85760006108d3565b6108d38284615694565b6000816000036148c457506000610a3e565b6148f66040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b846001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015614934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149589190615630565b6040808301919091526001600160a01b038616600090815260a460205290812054825280855a60808501525b6000811180156149ca57506001600160a01b0388166000908152609a602052604081206149bb90600101546001600160a01b031690565b9350836001600160a01b031614155b80156149e45750855a85608001516149e29190615694565b105b15614b1f576001600160a01b038089166000908152609e6020908152604080832093871683529290522084518154919350614a1f9190611fdd565b6060850181905260009081908310614a6c5760408601516060870151614a4491612999565b8460010154614a53919061567c565b9150856060015183614a659190615694565b9250614aae565b6040860151614a7c908490612999565b8460010154614a8b919061567c565b8651909250614a9b908490612999565b8454614aa79190615694565b9050600092505b60018401829055808455614ac28a86613b86565b896001600160a01b0316856001600160a01b03167f76908587112671ab2dcd9323f0d9b27d193156f95fe5e1251411a151c20e82dd8484604051614b10929190918252602082015260400190565b60405180910390a35050614984565b614b298188615694565b98975050505050505050565b600081600003614b4757506000610a3e565b614b796040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b846001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614bb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bdb9190615630565b6040808301919091526001600160a01b038616600090815260a560205290812054825280855a60808501525b600081118015614c4d57506001600160a01b0388166000908152609c60205260408120614c3e90600101546001600160a01b031690565b9350836001600160a01b031614155b8015614c675750855a8560800151614c659190615694565b105b15614b1f576001600160a01b038089166000908152609f6020908152604080832093871683529290522084518154919350614ca29190611fdd565b6060850181905260009081908310614cef5760408601516060870151614cc791612999565b8460010154614cd6919061567c565b9150856060015183614ce89190615694565b9250614d31565b6040860151614cff908490612999565b8460010154614d0e919061567c565b8651909250614d1e908490612999565b8454614d2a9190615694565b9050600092505b60018401829055808455614d458a866141a9565b896001600160a01b0316856001600160a01b03167f0aec3812ec00f2d2f0eacc89fd13923091a68f30c3b3d0336e364544322b97588484604051614d93929190918252602082015260400190565b60405180910390a35050614c07565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806143fe5760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610932565b6001600160a01b0381166000908152602083905260408120600201549003614e545760405163e76ea87f60e01b815260040160405180910390fd5b6001600160a01b038082166000908152602084815260409182902082516060810184528154851680825260018301549095169281019290925260020154918101919091529015614edd5760208181015182516001600160a01b03908116600090815292869052604090922060010180546001600160a01b03191692909116919091179055614f04565b60208101516001840180546001600160a01b0319166001600160a01b039092169190911790555b60208101516001600160a01b031615614f505780516020808301516001600160a01b03908116600090815291869052604090912080546001600160a01b03191691909216179055614f74565b80516002840180546001600160a01b0319166001600160a01b039092169190911790555b506001600160a01b031660009081526020919091526040812080546001600160a01b03199081168255600182018054909116905560020155565b81600003614fcf5760405163ba3b5b5960e01b815260040160405180910390fd5b6001600160a01b038316614ff65760405163867915ab60e01b815260040160405180910390fd5b6001600160a01b038316600090815260208590526040902060020154156150305760405163f5ab373160e01b815260040160405180910390fd5b60018401546000906001600160a01b03165b8282108015615061575060028601546001600160a01b03828116911614155b801561508857506001600160a01b0381166000908152602087905260409020600201548411155b156150b5576001600160a01b03908116600090815260208790526040902060019081015492019116615042565b6001600160a01b038116158015906150e757506001600160a01b03811660009081526020879052604090206002015484115b156152285760018601546001600160a01b039081169082160361518f576040805160608101825260008082526001600160a01b0384811660208085018281528587018b81528c8516808752928e9052878620965187549086166001600160a01b0319918216178855915160018089018054929097169184169190911790955551600290960195909555918b018054851683179055825292902080549091169091179055611af7565b604080516060810182526001600160a01b03808416600081815260208b81528582208054851686528186018481528688018c81528d8716808652938f9052888520975188549088166001600160a01b0319918216178955915160018981018054928a1692851692909217909155905160029098019790975581549095168352958220909401805484168517905552825416179055611af7565b60018601546001600160a01b03166152bf5760408051606081018252600080825260208083018281528385018981526001600160a01b038b8116808652938d905295909320935184549086166001600160a01b031991821617855590516001808601805492909716918316919091179095559151600293840155928901805482168417905590880180549091169091179055611af7565b505060408051606081018252600286810180546001600160a01b03908116845260006020808601828152868801998a529983168083529a9052858120945185549083166001600160a01b0319918216178655985160018087018054928516928c169290921790915597519490930193909355805490921681529190912090920180548416851790555080549091169091179055565b6001600160a01b0381168114611c9357600080fd5b60006020828403121561537b57600080fd5b8135610a3e81615354565b80356004811061353257600080fd5b600080604083850312156153a857600080fd5b82356153b381615354565b91506153c160208401615386565b90509250929050565b600080604083850312156153dd57600080fd5b82356153e881615354565b915060208301356153f881615354565b809150509250929050565b60008060006060848603121561541857600080fd5b833561542381615354565b925061543160208501615386565b9150604084013561544181615354565b809150509250925092565b6000806000806080858703121561546257600080fd5b843561546d81615354565b9350602085013561547d81615354565b9250604085013561548d81615354565b9396929550929360600135925050565b600080600080600060a086880312156154b557600080fd5b85356154c081615354565b945060208601356154d081615354565b935060408601356154e081615354565b94979396509394606081013594506080013592915050565b6020808252825182820181905260009190848201906040850190845b818110156155395783516001600160a01b031683529284019291840191600101615514565b50909695505050505050565b60008060006060848603121561555a57600080fd5b833561556581615354565b95602085013595506040909401359392505050565b60006020828403121561558c57600080fd5b5035919050565b600080600080600060a086880312156155ab57600080fd5b85356155b681615354565b94506020860135935060408601356155cd81615354565b925060608601356155dd81615354565b949793965091946080013592915050565b6000806040838503121561560157600080fd5b823561560c81615354565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561564257600080fd5b5051919050565b60006020828403121561565b57600080fd5b8151610a3e81615354565b634e487b7160e01b600052601160045260246000fd5b6000821982111561568f5761568f615666565b500190565b6000828210156156a6576156a6615666565b500390565b634e487b7160e01b600052603260045260246000fd5b60008160001904831182151516156156db576156db615666565b500290565b6000826156fd57634e487b7160e01b600052601260045260246000fd5b500490565b6000825160005b818110156157235760208186018101518583015201615709565b81811115615732576000828501525b509190910192915050565b8051801515811461353257600080fd5b60008060006060848603121561576257600080fd5b61576b8461573d565b9250602084015191506157806040850161573d565b90509250925092565b634e487b7160e01b600052603160045260246000fdfeaa997145358327b99ccedf396e9b7719eb7999623af1a7b38605739996c2ccfaa26469706673582212202f243efffddf1230e77365bc816a0d7943a79e28337a7a9f1d10d92e414b847e64736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102535760003560e01c8063a086fc2211610146578063d59c9eb6116100c3578063e501ed0411610087578063e501ed04146106bc578063e61c6d6f146106ee578063e8462e8f146106f7578063f2f4ca1614610700578063f2fde38b1461076c578063f4ea93d81461077f57600080fd5b8063d59c9eb6146105bf578063db0577fd14610614578063defe205314610683578063df6d921214610696578063e34b5145146106a957600080fd5b8063b24be6871161010a578063b24be68714610559578063b59ec4781461056c578063b6f2bf1c1461058c578063c2af97871461059f578063cb830d03146105b257600080fd5b8063a086fc22146104c3578063a44026a314610518578063ac0b4b121461052b578063af8b1c6f1461053e578063b0772d0b1461055157600080fd5b80637907016a116101d45780638da5cb5b116101985780638da5cb5b146103f5578063947574ac1461040657806396bd512c1461044d5780639df5a1f2146104965780639fab1036146104b057600080fd5b80637907016a1461037c5780637f3ad0561461038f578063854f7ebb146103a257806385d7334d146103c25780638ccb720b146103d557600080fd5b80635fe3b5671161021b5780635fe3b567146103115780636a14602414610324578063715018a614610333578063720ceb021461033b578063789caa3e1461036957600080fd5b806320c342d9146102585780632ebf4be0146102905780633528e4ce146102be57806352f0f814146102d35780635acff027146102fe575b600080fd5b61027b610266366004615369565b60a36020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102b061029e366004615369565b60a56020526000908152604090205481565b604051908152602001610287565b6102d16102cc366004615369565b61079b565b005b60aa546102e6906001600160a01b031681565b6040516001600160a01b039091168152602001610287565b6102e661030c366004615395565b6107e3565b60ae546102e6906001600160a01b031681565b6102b0670de0b6b3a764000081565b6102d16108dc565b61027b6103493660046153ca565b60a060209081526000928352604080842090915290825290205460ff1681565b6102e6610377366004615403565b610947565b6102d161038a36600461544c565b610a45565b60ad546102e6906001600160a01b031681565b6102b06103b0366004615369565b60a46020526000908152604090205481565b6102d16103d036600461549d565b610e88565b6103e86103e3366004615369565b6113ae565b60405161028791906154f8565b6033546001600160a01b03166102e6565b6104386104143660046153ca565b609f6020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610287565b61047b61045b366004615369565b60a76020526000908152604090205461ffff808216916201000090041682565b6040805161ffff938416815292909116602083015201610287565b61049e600881565b60405160ff9091168152602001610287565b6102d16104be366004615545565b611424565b6104f86104d1366004615369565b60a96020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610287565b60b0546102e6906001600160a01b031681565b6102e661053936600461557a565b6119ac565b60af546102e6906001600160a01b031681565b6103e86119d6565b60ab546102e6906001600160a01b031681565b6102b061057a366004615369565b60b26020526000908152604090205481565b6102d161059a366004615593565b611a38565b6102d16105ad36600461549d565b611aff565b60b35461027b9060ff1681565b6105f56105cd366004615369565b60a86020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805193151584529115156020840152151590820152606001610287565b610657610622366004615369565b60a66020526000908152604090205463ffffffff8116906001600160701b036401000000008204811691600160901b90041683565b6040805163ffffffff90941684526001600160701b039283166020850152911690820152606001610287565b60ac546102e6906001600160a01b031681565b60b1546102e6906001600160a01b031681565b6102e66106b73660046155ee565b611b93565b6104386106ca3660046153ca565b609e6020908152600092835260408084209091529082529020805460019091015482565b6102b060975481565b6102b060985481565b6099546107389067ffffffffffffffff80821691680100000000000000008104821691600160801b8204811691600160c01b90041684565b6040805167ffffffffffffffff95861681529385166020850152918416918301919091529091166060820152608001610287565b6102d161077a366004615369565b611bcb565b61078861271081565b60405161ffff9091168152602001610287565b6001600160a01b038116600090815260a86020526040902054819060ff166107d6576040516396e1352960e01b815260040160405180910390fd5b6107df82611ca5565b5050565b6000808260038111156107f8576107f861561a565b03610823576001600160a01b038381166000908152609a6020526040902060010154165b90506108d6565b60018260038111156108375761083761561a565b0361085f576001600160a01b038381166000908152609b60205260409020600101541661081c565b60028260038111156108735761087361561a565b0361089b576001600160a01b038381166000908152609c60205260409020600101541661081c565b60038260038111156108af576108af61561a565b036108d6576001600160a01b038381166000908152609d6020526040902060010154165b90505b92915050565b6033546001600160a01b0316331461093b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6109456000611cf7565b565b60008083600381111561095c5761095c61561a565b0361098a576001600160a01b0384166000908152609a602052604090206109839083611d49565b9050610a3e565b600183600381111561099e5761099e61561a565b036109c5576001600160a01b0384166000908152609b602052604090206109839083611d49565b60028360038111156109d9576109d961561a565b03610a00576001600160a01b0384166000908152609c602052604090206109839083611d49565b6003836003811115610a1457610a1461561a565b03610a3e576001600160a01b0384166000908152609d60205260409020610a3b9083611d49565b90505b9392505050565b6001600160a01b03808516600090815260a0602090815260408083209386168352929052205460ff161580610aa057506001600160a01b03808416600090815260a0602090815260408083209386168352929052205460ff16155b15610abe576040516301187a4360e61b815260040160405180910390fd5b610ac784611ca5565b610ad083611ca5565b610ade826000806000611d6c565b610afb5760405163b3165ffd60e01b815260040160405180910390fd5b610b2d6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b610b378584611f2d565b60208083019190915260ae546040805163743aaa2360e11b81529051610bb8936001600160a01b039093169263e875544692600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bad9190615630565b602083015190611fdd565b821115610bd857604051633b1b989f60e01b815260040160405180910390fd5b610be6853385856000611ffc565b60ae54604080516307dc0d1d60e41b815290516000926001600160a01b031691637dc0d1d09160048083019260209291908290030181865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190615649565b60405163fc57d4df60e01b81526001600160a01b0387811660048301529192509082169063fc57d4df90602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190615630565b825260405163fc57d4df60e01b81526001600160a01b03878116600483015282169063fc57d4df90602401602060405180830381865afa158015610d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2e9190615630565b606083015281511580610d4357506060820151155b15610d6157604051634b6b62e560e01b815260040160405180910390fd5b610e10610e018360000151610dfb8560600151610df560ae60009054906101000a90046001600160a01b03166001600160a01b0316634ada90af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dee9190615630565b8990611fdd565b90611fdd565b90612999565b610e0b87876129cb565b612a69565b60808301819052610e2690869086336000612a7f565b60808201516040805133815260208101869052908101919091526001600160a01b0380871691888216918716907fc2c75a73164c2efcbb9f74bfa511cd0866489d90687831a7217b3dbeeb6970889060600160405180910390a4505050505050565b6001600160a01b038316610eaf5760405163867915ab60e01b815260040160405180910390fd5b81600003610ed0576040516310eb483f60e21b815260040160405180910390fd5b610ed985611ca5565b610ee3858461341a565b6000610eee866134a6565b9050610f056001600160a01b038216863086613537565b6001600160a01b038616600090815260a960209081526040808320815160608101835284815292830184905290820192909252876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a9190615630565b6020820152848152600182015415611096576000610fc982602001518460010154611fdd90919063ffffffff16565b825190915081111561101c578151604083018051610fe890839061567c565b90525060208201518251610ffb91612999565b83600101600082825461100e9190615694565b90915550506000825261104d565b808260400181815161102e919061567c565b90525060006001840155815181908390611049908390615694565b9052505b886001600160a01b03167f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df6846001015460405161108c91815260200190565b60405180910390a2505b8051158015906110bf57506001600160a01b038816600090815260a3602052604090205460ff16155b80156110fe57506001600160a01b0388166000908152609d602052604081206110f290600101546001600160a01b031690565b6001600160a01b031614155b15611185576000611114898360000151876135ba565b509050801561118357808260400181815161112f919061567c565b905250815181908390611143908390615694565b9052506001600160a01b038916600090815260a5602052604090205461116a908290612999565b83600301600082825461117d919061567c565b90915550505b505b604081015115611262576001600160a01b038816600090815260a4602052604080822054908301516111b691612999565b9050808360020160008282546111cc919061567c565b90915550506001600160a01b03808a166000908152609e60209081526040808320938b168352929052908120805483929061120890849061567c565b9250508190555061121e89858460400151613853565b886001600160a01b03166000805160206157a083398151915284600201548560030154604051611258929190918252602082015260400190565b60405180910390a2505b805115611324576112d6886001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615630565b825190612999565b6001600160a01b03808a166000908152609e60209081526040808320938b168352929052908120600101805490919061131090849061567c565b909155505080516113249089908590613a3a565b61132e8887613b86565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518c8152938401919091529082015291929091908a16907f11adb3570ba55fd255b1f04252ca0071ae6639c86d4fd69e7c1bf1688afb493f906060015b60405180910390a45050505050505050565b6001600160a01b038116600090815260a1602090815260409182902080548351818402810184019094528084526060939283018282801561141857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113fa575b50505050509050919050565b81600003611445576040516310eb483f60e21b815260040160405180910390fd5b61144e83611ca5565b611458833361341a565b33600081815260b2602052604081204390556114779190859085611d6c565b156114955760405163df9db46360e01b815260040160405180910390fd5b60006114a0846134a6565b6001600160a01b038516600081815260a960209081526040808320815163182df0f560e01b815291519596508895939490938593919263182df0f59260048083019391928290030181865afa1580156114fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115219190615630565b604051633af9e66960e01b81523060048201529091506000906001600160a01b038a1690633af9e669906024016020604051808303816000875af115801561156d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115919190615630565b83549091501561166c5782546000906115aa9084611fdd565b9050858111806115b957508181115b1561160d5760006115ca8784612a69565b90506115d6818761567c565b95506115e28185612999565b8560000160008282546115f59190615694565b9091555061160590508188615694565b96505061162a565b611617818661567c565b6000855594506116278187615694565b95505b83546040519081526001600160a01b038b16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a2505b60008511801561169557506001600160a01b038916600090815260a3602052604090205460ff16155b80156116d457506001600160a01b0389166000908152609b602052604081206116c890600101546001600160a01b031690565b6001600160a01b031614155b1561176c5760006116f38a6116ed88610e0b8987615694565b8a613d99565b509050801561176a57611706818661567c565b94506117128187615694565b6001600160a01b038b16600090815260a46020526040902054909650611739908290612999565b6001600160a01b038b16600090815260a960205260408120600201805490919061176490849061567c565b90915550505b505b8315611863576001600160a01b038916600090815260a56020526040812054611796908690612999565b6001600160a01b038b16600090815260a960205260408120600301805492935083929091906117c690849061567c565b90915550506001600160a01b038a166000908152609f60209081526040808320338452909152812080548392906117fe90849061567c565b9091555050600284015460038501546040516001600160a01b038d16926000805160206157a08339815191529261183d92918252602082015260400190565b60405180910390a260006118518685612999565b1115611861576118618a86614014565b505b841561191b576118d5896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ce9190615630565b8690612999565b6001600160a01b038a166000908152609f602090815260408083203384529091528120600101805490919061190b90849061567c565b9091555061191b90508986614120565b61192589336141a9565b6119396001600160a01b038716338a614386565b6001600160a01b0389166000818152609f6020908152604080832033808552908352928190206001810154905482518e81529384019190915282820152517fc1cba78646fef030830d099fc25cb498953709c9d47d883848f81fd207174c9f9181900360600190a3505050505050505050565b60a281815481106119bc57600080fd5b6000918252602090912001546001600160a01b0316905081565b606060a2805480602002602001604051908101604052809291908181526020018280548015611a2e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611a10575b5050505050905090565b83600003611a59576040516310eb483f60e21b815260040160405180910390fd5b6001600160a01b03808616600090815260a0602090815260408083209387168352929052205460ff16611a9f576040516301187a4360e61b815260040160405180910390fd5b611aa885611ca5565b6000611abd611ab787866129cb565b86612a69565b9050611acc8487836000611d6c565b15611aea57604051630cba3c5f60e21b815260040160405180910390fd5b611af78682868686612a7f565b505050505050565b81600003611b20576040516310eb483f60e21b815260040160405180910390fd5b6001600160a01b03808616600090815260a0602090815260408083209387168352929052205460ff16611b66576040516301187a4360e61b815260040160405180910390fd5b611b6f85611ca5565b6000611b84611b7e8786611f2d565b84612a69565b9050611af78686868486611ffc565b60a16020528160005260406000208181548110611baf57600080fd5b6000918252602090912001546001600160a01b03169150829050565b6033546001600160a01b03163314611c255760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610932565b6001600160a01b038116611c8a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610932565b611c9381611cf7565b50565b6001600160a01b03163b151590565b604080516001600160a01b038381166024808401919091528351808403909101815260449092019092526020810180516001600160e01b0316631a94726760e11b17905260ad546107df921690614404565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0390811660009081526020929092526040909120600101541690565b60008060ae60009054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de69190615649565b6001600160a01b038716600090815260a16020908152604080832054815160a08101835284815292830184905290820183905260608201839052608082018390529293509080805b84811015611f1f576001600160a01b038b16600090815260a160205260408120805483908110611e6057611e606156ab565b6000918252602090912001546001600160a01b03169050611e828c828961449e565b9450846020015184611e94919061567c565b9350846040015183611ea6919061567c565b9250806001600160a01b03168b6001600160a01b031603611f16578815611ee4576060850151611ed7908a90611fdd565b611ee1908461567c565b92505b8915611f1657611f098560800151610df587606001518d611fdd90919063ffffffff16565b611f139085615694565b93505b50600101611e2e565b501198975050505050505050565b6001600160a01b038083166000818152609f602090815260408083209486168352938152838220845180860186528154815260019091015481830152845163aa5af0fd60e01b8152945192949093611fa793909263aa5af0fd92600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b6001600160a01b038516600090815260a560205260409020548251611fcb91611fdd565b611fd5919061567c565b949350505050565b6000670de0b6b3a7640000611ff283856156c1565b6108d391906156e0565b6001600160a01b038316600090815260b260205260409020544390036120355760405163dff88f5160e01b815260040160405180910390fd5b6000612040866134a6565b90506120576001600160a01b038216863086613537565b6120a66040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60208082018590528382526040805163aa5af0fd60e01b815290516001600160a01b038a169263aa5af0fd92600480820193918290030181865afa1580156120f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121169190615630565b60608201526001600160a01b038088166000908152609f602090815260408083209389168352929052206001015460c08201819052156122c457606081015160c082015161216391611fdd565b6040820181905260208201511015612277576020810151610100820181905260c0820151606083015161219992610e0b91612999565b6001600160a01b038089166000908152609f60209081526040808320938a16835292905290812060010180549091906121d3908490615694565b909155506121e3905087866141a9565b6121f38783836101000151613853565b6121fd878661461f565b6001600160a01b038781166000818152609f602090815260408083208a8616808552908352928190206001810154905482518b815293840191909152828201525192939192918a16917f7b417e520d2b905fc5a1689d29d329358dd55efc60ed115aa165b0a2b64232c69181900360600190a45050612992565b60408101516101008201819052602082018051612295908390615694565b9052506001600160a01b038088166000908152609f602090815260408083209389168352929052908120600101555b6001600160a01b03808816600081815260a96020908152604080832060a4835281842054608088015284845260a583528184205460a08801908152948452609f8352818420958b1684529482529091205491519084015161232a9291610e0b9190612999565b6001600160a01b03808a166000908152609f60209081526040808320938b1683529290529081208054909190612361908490615694565b90915550612371905088876141a9565b60008260200151118015612389575060008160010154115b1561251f5760006123ab83606001518360010154611fdd90919063ffffffff16565b9050826020015181111561243557606083015160208401516123cc91612999565b8260010160008282546123df9190615694565b909155505060a083015160208401516123f791612999565b82600301600082825461240a9190615694565b909155505060208301516101008401805161242690839061567c565b90525060006020840152612494565b6000600183015560a083015161244c908290612999565b82600301600082825461245f9190615694565b92505081905550808361010001818151612479919061567c565b905250602083018051829190612490908390615694565b9052505b886001600160a01b03167f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df683600101546040516124d391815260200190565b60405180910390a2886001600160a01b03166000805160206157a083398151915283600201548460030154604051612515929190918252602082015260400190565b60405180910390a2505b602082015115612679576125d66125478360a001518360030154611fdd90919063ffffffff16565b6125b48a6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ac9190615630565b845490611fdd565b608085015160028501546125c791611fdd565b6125d19190615694565b614897565b60e08301819052156126795760006125f68360e001518460200151612a69565b9050808360200181815161260a9190615694565b90525060a083015161261d908290612999565b8260030160008282546126309190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a08339815191529261266f92918252602082015260400190565b60405180910390a2505b600082602001511180156126a657506001600160a01b038816600090815260a3602052604090205460ff16155b80156126e557506001600160a01b0388166000908152609d602052604081206126d990600101546001600160a01b031690565b6001600160a01b031614155b15612765576000806127008a856020015186600001516135ba565b9150915080846000015111612718576000845261272e565b808460000181815161272a9190615694565b9052505b81156127625781846020018181516127469190615694565b9052506101008401805183919061275e90839061567c565b9052505b50505b6127758884846101000151613853565b60208201511561291657600061279489846020015185600001516148b2565b9050826020015181101561287057612817896001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128079190615630565b828560200151610dfb9190615694565b82600001600082825461282a919061567c565b909155505081546040519081526001600160a01b038a16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a25b6080830151612880908290612999565b8260020160008282546128939190615694565b909155505060a083015160208401516128ab91612999565b8260030160008282546128be9190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a0833981519152926128fd92918252602082015260400190565b60405180910390a261291489858560200151613a3a565b505b612920888761461f565b6001600160a01b038881166000818152609f602090815260408083208b8616808552908352928190206001810154905482518c8152938401919091529082015291929091908a16907f7b417e520d2b905fc5a1689d29d329358dd55efc60ed115aa165b0a2b64232c69060600161139c565b5050505050565b6000670de0b6b3a7640000826129af85836156c1565b6129c190670de0b6b3a76400006156c1565b611ff291906156e0565b6001600160a01b038083166000818152609e602090815260408083209486168352938152838220845180860186528154815260019091015481830152845163182df0f560e01b8152945192949093612a4593909263182df0f592600480820193918290030181865afa158015610b89573d6000803e3d6000fd5b6001600160a01b038516600090815260a460205260409020548251611fcb91611fdd565b6000818310612a7857816108d3565b5090919050565b83600003612aa0576040516310eb483f60e21b815260040160405180910390fd5b612ae96040518060e0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b612af2866134a6565b6001600160a01b0390811660c083015260208201869052828252604051633af9e66960e01b815230600482015290871690633af9e669906024016020604051808303816000875af1158015612b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6f9190615630565b816080018181525050856001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bda9190615630565b60408201819052612bec908690612999565b600003612c0c576040516393c76c6f60e01b815260040160405180910390fd5b6001600160a01b038087166000908152609e60209081526040808320938816835292905220600101548015612e23576000612c54836040015183611fdd90919063ffffffff16565b90508260200151811180612c6b5750826080015181115b15612cf557612c8283602001518460800151612a69565b60a08401819052602084018051612c9a908390615694565b905250604083015160a0840151612cb091612999565b6001600160a01b03808a166000908152609e60209081526040808320938b1683529290529081206001018054909190612cea908490615694565b90915550612d3f9050565b60a08301819052602083018051829190612d10908390615694565b9052506001600160a01b038089166000908152609e60209081526040808320938a168352929052908120600101555b8260200151600003612e2157612d558887613b86565b612d5f888761461f565b6000612d7c84604001518560a0015161299990919063ffffffff16565b1115612d9057612d90888460a00151614014565b60c0830151612da9906001600160a01b03168689614386565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518e815293840191909152828201525192938916927f378f9d375cd79e36c19c26a9e57791fe7cd5953b61986c01ebf980c0efb928019181900360600190a4505050612992565b505b6001600160a01b03808816600081815260a96020908152604080832060a483528184205460608901908152948452609e8352818420958b16845294825290912054915190850151612e799291610e0b9190612999565b6001600160a01b03808a166000908152609e60209081526040808320938b1683529290529081208054909190612eb0908490615694565b90915550612ec090508887613b86565b60008360200151118015612ed45750805415155b156130a15760408301518154600091612eed9190611fdd565b90508360200151811180612f1357508360a001518460800151612f109190615694565b81115b15612fc4576000612f3685602001518660a001518760800151610e0b9190615694565b9050612f4f85604001518261299990919063ffffffff16565b836000016000828254612f629190615694565b90915550506060850151612f77908290612999565b836002016000828254612f8a9190615694565b92505081905550808560a001818151612fa3919061567c565b905250602085018051829190612fba908390615694565b90525061301d9050565b808460a001818151612fd6919061567c565b905250602084018051829190612fed908390615694565b905250600082556060840151613004908290612999565b8260020160008282546130179190615694565b90915550505b81546040519081526001600160a01b038a16907f1cf8705a784a46d32023f3694b5e8149137d563085a870fde2f54a6cc5c59df79060200160405180910390a2886001600160a01b03166000805160206157a083398151915283600201548460030154604051613097929190918252602082015260400190565b60405180910390a2505b600083602001511180156130ce57506001600160a01b038816600090815260a3602052604090205460ff16155b801561310d57506001600160a01b0388166000908152609b6020526040812061310190600101546001600160a01b031690565b6001600160a01b031614155b156131a05760008061313c8a61313587602001518860a001518960800151610e0b9190615694565b8751613d99565b9150915080856000015111613154576000855261316a565b80856000018181516131669190615694565b9052505b811561319d5781856020018181516131829190615694565b90525060a08501805183919061319990839061567c565b9052505b50505b60006131bd84604001518560a0015161299990919063ffffffff16565b11156131d1576131d1888460a00151614014565b6020830151156133885760006131f08985602001518660000151614b35565b905083602001518110156132cf57613273896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561323f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132639190615630565b828660200151610dfb9190615694565b826001016000828254613286919061567c565b909155505060018201546040519081526001600160a01b038a16907f8113f59ef078158acce9021327489b70d6ab15d0c107c36455c3505248648df69060200160405180910390a25b606084015160208501516132e291612999565b8260020160008282546132f59190615694565b90915550506001600160a01b038916600090815260a5602052604090205461331e908290612999565b8260030160008282546133319190615694565b9091555050600282015460038301546040516001600160a01b038c16926000805160206157a08339815191529261337092918252602082015260400190565b60405180910390a2613386898560200151614120565b505b613392888761461f565b60c08301516133ab906001600160a01b03168689614386565b6001600160a01b038881166000818152609e602090815260408083208b8616808552908352928190206001810154905482518e8152938401919091529082015291928816917f378f9d375cd79e36c19c26a9e57791fe7cd5953b61986c01ebf980c0efb928019060600161139c565b6001600160a01b03808316600090815260a0602090815260408083209385168352929052205460ff166107df576001600160a01b03808316600081815260a0602090815260408083209486168352938152838220805460ff1916600190811790915560a18252938220805494850181558252902090910180546001600160a01b03191690911790555050565b60b0546000906001600160a01b03908116908316036134d057505060b1546001600160a01b031690565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d69190615649565b919050565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129925760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610932565b600080826000036135d05750600090508061384b565b6136026040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136649190615630565b6040808301919091526001600160a01b038716600090815260a5602052908120548252805a60808401525b86851080156136d457506001600160a01b0388166000908152609d602052604081206136c590600101546001600160a01b031690565b9250826001600160a01b031614155b80156136ee5750855a84608001516136ec9190615694565b105b1561383557506001600160a01b038088166000908152609f60209081526040808320938516835292905281902090830151600182015461372d91611fdd565b606084015260008080613740888b615694565b905080866060015111613782578551606087015161375d91612999565b8454613769919061567c565b915085606001518861377b919061567c565b97506137c3565b6040860151613792908290612999565b84600101546137a19190615694565b86519093506137b1908290612999565b84546137bd919061567c565b91508997505b600184018390558184556137d78b866141a9565b8a6001600160a01b0316856001600160a01b03167f0aec3812ec00f2d2f0eacc89fd13923091a68f30c3b3d0336e364544322b97588585604051613825929190918252602082015260400190565b60405180910390a350505061368f565b5a83608001516138459190615694565b93505050505b935093915050565b6040516305eff7ef60e21b81523060048201526138c39082906001600160a01b038616906317bfdfbc906024016020604051808303816000875af115801561389f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0b9190615630565b90508015613a355760b0546001600160a01b03908116908416036139985760b154604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b15801561392757600080fd5b505af115801561393b573d6000803e3d6000fd5b50505050826001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397a57600080fd5b505af115801561398e573d6000803e3d6000fd5b5050505050505050565b6139ac6001600160a01b0383168483614da2565b60405163073a938160e11b8152600481018290526001600160a01b03841690630e752702906024016020604051808303816000875af11580156139f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a179190615630565b15613a3557604051637112354b60e01b815260040160405180910390fd5b505050565b60b0546001600160a01b0390811690841603613ae95760b154604051632e1a7d4d60e01b8152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015613a9657600080fd5b505af1158015613aaa573d6000803e3d6000fd5b50505050826001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397a57600080fd5b613afd6001600160a01b0383168483614da2565b60405163140e25ad60e31b8152600481018290526001600160a01b0384169063a0712d68906024016020604051808303816000875af1158015613b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b689190615630565b15613a355760405163757d648760e11b815260040160405180910390fd5b6001600160a01b038281166000818152609e6020908152604080832094861680845294825280832060018101549054858552609b84528285208786528452828520600290810154968652609a855283862097865296909352922090930154609854919392918411613c21576001600160a01b038087166000908152609e60209081526040808320938916835292905290812060010181905593505b838214613c7e578115613c50576001600160a01b0386166000908152609b60205260409020613c509086614e19565b8315613c7e576097546001600160a01b0387166000908152609b60205260409020613c7e9187908790614fae565b6098548311613cb4576001600160a01b038087166000908152609e60209081526040808320938916835292905290812081905592505b828114613d11578015613ce3576001600160a01b0386166000908152609a60205260409020613ce39086614e19565b8215613d11576097546001600160a01b0387166000908152609a60205260409020613d119187908690614fae565b60ac546001600160a01b031615611af75760ac5460405163636c55d360e01b81526001600160a01b0387811660048301528881166024830152604482018590529091169063636c55d3906064015b600060405180830381600087803b158015613d7957600080fd5b505af1158015613d8d573d6000803e3d6000fd5b50505050505050505050565b60008082600003613daf5750600090508061384b565b613de16040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b856001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e439190615630565b6040808301919091526001600160a01b038716600090815260a4602052908120548252805a60808401525b8685108015613eb357506001600160a01b0388166000908152609b60205260408120613ea490600101546001600160a01b031690565b9250826001600160a01b031614155b8015613ecd5750855a8460800151613ecb9190615694565b105b1561383557506001600160a01b038088166000908152609e602090815260408083209385168352929052819020908301516001820154613f0c91611fdd565b606084015260008080613f1f888b615694565b905080866060015111613f615785516060870151613f3c91612999565b8454613f48919061567c565b9150856060015188613f5a919061567c565b9750613fa2565b6040860151613f71908290612999565b8460010154613f809190615694565b8651909350613f90908290612999565b8454613f9c919061567c565b91508997505b60018401839055818455613fb68b86613b86565b8a6001600160a01b0316856001600160a01b03167f76908587112671ab2dcd9323f0d9b27d193156f95fe5e1251411a151c20e82dd8585604051614004929190918252602082015260400190565b60405180910390a3505050613e6e565b60405163852a12e360e01b8152600481018290526001600160a01b0383169063852a12e3906024016020604051808303816000875af115801561405b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407f9190615630565b1561409d57604051637d47a0c360e01b815260040160405180910390fd5b60b0546001600160a01b03908116908316036107df5760b160009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561410357600080fd5b505af1158015614117573d6000803e3d6000fd5b50505050505050565b60405163317afabb60e21b8152600481018290526001600160a01b0383169063c5ebeaec906024016020604051808303816000875af1158015614167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061418b9190615630565b1561409d576040516302738d6b60e11b815260040160405180910390fd5b6001600160a01b038281166000818152609f6020908152604080832094861680845294825280832060018101549054858552609d84528285208786528452828520600290810154968652609c855283862097865296909352922090930154609854919392918411614244576001600160a01b038087166000908152609f60209081526040808320938916835292905290812060010181905593505b8382146142a1578115614273576001600160a01b0386166000908152609d602052604090206142739086614e19565b83156142a1576097546001600160a01b0387166000908152609d602052604090206142a19187908790614fae565b60985483116142d7576001600160a01b038087166000908152609f60209081526040808320938916835292905290812081905592505b828114614334578015614306576001600160a01b0386166000908152609c602052604090206143069086614e19565b8215614334576097546001600160a01b0387166000908152609c602052604090206143349187908690614fae565b60ac546001600160a01b031615611af75760ac5460405163a9de645d60e01b81526001600160a01b0387811660048301528881166024830152604482018590529091169063a9de645d90606401613d5f565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806143fe5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610932565b50505050565b6060600080846001600160a01b0316846040516144219190615702565b600060405180830381855af49150503d806000811461445c576040519150601f19603f3d011682016040523d82523d6000602084013e614461565b606091505b509150915081156144755791506108d69050565b8051156144855780518082602001fd5b60405163037b81af60e11b815260040160405180910390fd5b6144d06040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405163fc57d4df60e01b81526001600160a01b03848116600483015283169063fc57d4df90602401602060405180830381865afa158015614516573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061453a9190615630565b6060820181905260000361456157604051634b6b62e560e01b815260040160405180910390fd5b60ae54604051638e8f294b60e01b81526001600160a01b03858116600483015290911690638e8f294b90602401606060405180830381865afa1580156145ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145cf919061574d565b5060808301525060608101516145e990610df585876129cb565b815260608101516145fe90610df58587611f2d565b60408201526080810151815161461391611fdd565b60208201529392505050565b6001600160a01b03808316600090815260a0602090815260408083209385168352929052205460ff16801561467757506001600160a01b038083166000908152609e6020908152604080832093851683529290522054155b80156146a957506001600160a01b038083166000908152609e6020908152604080832093851683529290522060010154155b80156146d857506001600160a01b038083166000908152609f6020908152604080832093851683529290522054155b801561470a57506001600160a01b038083166000908152609f6020908152604080832093851683529290522060010154155b156107df5760005b6001600160a01b03828116600090815260a16020526040902080549185169183908110614741576147416156ab565b6000918252602090912001546001600160a01b03161461476357600101614712565b6001600160a01b03808416600090815260a0602090815260408083209386168352928152828220805460ff1916905560a1905220546147a3600182615694565b8214614848576001600160a01b038316600090815260a1602052604090206147cc600183615694565b815481106147dc576147dc6156ab565b60009182526020808320909101546001600160a01b03868116845260a19092526040909220805491909216919084908110614819576148196156ab565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6001600160a01b038316600090815260a16020526040902080548061486f5761486f615789565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b6000818310156148a85760006108d3565b6108d38284615694565b6000816000036148c457506000610a3e565b6148f66040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b846001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015614934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149589190615630565b6040808301919091526001600160a01b038616600090815260a460205290812054825280855a60808501525b6000811180156149ca57506001600160a01b0388166000908152609a602052604081206149bb90600101546001600160a01b031690565b9350836001600160a01b031614155b80156149e45750855a85608001516149e29190615694565b105b15614b1f576001600160a01b038089166000908152609e6020908152604080832093871683529290522084518154919350614a1f9190611fdd565b6060850181905260009081908310614a6c5760408601516060870151614a4491612999565b8460010154614a53919061567c565b9150856060015183614a659190615694565b9250614aae565b6040860151614a7c908490612999565b8460010154614a8b919061567c565b8651909250614a9b908490612999565b8454614aa79190615694565b9050600092505b60018401829055808455614ac28a86613b86565b896001600160a01b0316856001600160a01b03167f76908587112671ab2dcd9323f0d9b27d193156f95fe5e1251411a151c20e82dd8484604051614b10929190918252602082015260400190565b60405180910390a35050614984565b614b298188615694565b98975050505050505050565b600081600003614b4757506000610a3e565b614b796040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b846001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614bb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bdb9190615630565b6040808301919091526001600160a01b038616600090815260a560205290812054825280855a60808501525b600081118015614c4d57506001600160a01b0388166000908152609c60205260408120614c3e90600101546001600160a01b031690565b9350836001600160a01b031614155b8015614c675750855a8560800151614c659190615694565b105b15614b1f576001600160a01b038089166000908152609f6020908152604080832093871683529290522084518154919350614ca29190611fdd565b6060850181905260009081908310614cef5760408601516060870151614cc791612999565b8460010154614cd6919061567c565b9150856060015183614ce89190615694565b9250614d31565b6040860151614cff908490612999565b8460010154614d0e919061567c565b8651909250614d1e908490612999565b8454614d2a9190615694565b9050600092505b60018401829055808455614d458a866141a9565b896001600160a01b0316856001600160a01b03167f0aec3812ec00f2d2f0eacc89fd13923091a68f30c3b3d0336e364544322b97588484604051614d93929190918252602082015260400190565b60405180910390a35050614c07565b600060405163095ea7b360e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806143fe5760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610932565b6001600160a01b0381166000908152602083905260408120600201549003614e545760405163e76ea87f60e01b815260040160405180910390fd5b6001600160a01b038082166000908152602084815260409182902082516060810184528154851680825260018301549095169281019290925260020154918101919091529015614edd5760208181015182516001600160a01b03908116600090815292869052604090922060010180546001600160a01b03191692909116919091179055614f04565b60208101516001840180546001600160a01b0319166001600160a01b039092169190911790555b60208101516001600160a01b031615614f505780516020808301516001600160a01b03908116600090815291869052604090912080546001600160a01b03191691909216179055614f74565b80516002840180546001600160a01b0319166001600160a01b039092169190911790555b506001600160a01b031660009081526020919091526040812080546001600160a01b03199081168255600182018054909116905560020155565b81600003614fcf5760405163ba3b5b5960e01b815260040160405180910390fd5b6001600160a01b038316614ff65760405163867915ab60e01b815260040160405180910390fd5b6001600160a01b038316600090815260208590526040902060020154156150305760405163f5ab373160e01b815260040160405180910390fd5b60018401546000906001600160a01b03165b8282108015615061575060028601546001600160a01b03828116911614155b801561508857506001600160a01b0381166000908152602087905260409020600201548411155b156150b5576001600160a01b03908116600090815260208790526040902060019081015492019116615042565b6001600160a01b038116158015906150e757506001600160a01b03811660009081526020879052604090206002015484115b156152285760018601546001600160a01b039081169082160361518f576040805160608101825260008082526001600160a01b0384811660208085018281528587018b81528c8516808752928e9052878620965187549086166001600160a01b0319918216178855915160018089018054929097169184169190911790955551600290960195909555918b018054851683179055825292902080549091169091179055611af7565b604080516060810182526001600160a01b03808416600081815260208b81528582208054851686528186018481528688018c81528d8716808652938f9052888520975188549088166001600160a01b0319918216178955915160018981018054928a1692851692909217909155905160029098019790975581549095168352958220909401805484168517905552825416179055611af7565b60018601546001600160a01b03166152bf5760408051606081018252600080825260208083018281528385018981526001600160a01b038b8116808652938d905295909320935184549086166001600160a01b031991821617855590516001808601805492909716918316919091179095559151600293840155928901805482168417905590880180549091169091179055611af7565b505060408051606081018252600286810180546001600160a01b03908116845260006020808601828152868801998a529983168083529a9052858120945185549083166001600160a01b0319918216178655985160018087018054928516928c169290921790915597519490930193909355805490921681529190912090920180548416851790555080549091169091179055565b6001600160a01b0381168114611c9357600080fd5b60006020828403121561537b57600080fd5b8135610a3e81615354565b80356004811061353257600080fd5b600080604083850312156153a857600080fd5b82356153b381615354565b91506153c160208401615386565b90509250929050565b600080604083850312156153dd57600080fd5b82356153e881615354565b915060208301356153f881615354565b809150509250929050565b60008060006060848603121561541857600080fd5b833561542381615354565b925061543160208501615386565b9150604084013561544181615354565b809150509250925092565b6000806000806080858703121561546257600080fd5b843561546d81615354565b9350602085013561547d81615354565b9250604085013561548d81615354565b9396929550929360600135925050565b600080600080600060a086880312156154b557600080fd5b85356154c081615354565b945060208601356154d081615354565b935060408601356154e081615354565b94979396509394606081013594506080013592915050565b6020808252825182820181905260009190848201906040850190845b818110156155395783516001600160a01b031683529284019291840191600101615514565b50909695505050505050565b60008060006060848603121561555a57600080fd5b833561556581615354565b95602085013595506040909401359392505050565b60006020828403121561558c57600080fd5b5035919050565b600080600080600060a086880312156155ab57600080fd5b85356155b681615354565b94506020860135935060408601356155cd81615354565b925060608601356155dd81615354565b949793965091946080013592915050565b6000806040838503121561560157600080fd5b823561560c81615354565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561564257600080fd5b5051919050565b60006020828403121561565b57600080fd5b8151610a3e81615354565b634e487b7160e01b600052601160045260246000fd5b6000821982111561568f5761568f615666565b500190565b6000828210156156a6576156a6615666565b500390565b634e487b7160e01b600052603260045260246000fd5b60008160001904831182151516156156db576156db615666565b500290565b6000826156fd57634e487b7160e01b600052601260045260246000fd5b500490565b6000825160005b818110156157235760208186018101518583015201615709565b81811115615732576000828501525b509190910192915050565b8051801515811461353257600080fd5b60008060006060848603121561576257600080fd5b61576b8461573d565b9250602084015191506157806040850161573d565b90509250925092565b634e487b7160e01b600052603160045260246000fdfeaa997145358327b99ccedf396e9b7719eb7999623af1a7b38605739996c2ccfaa26469706673582212202f243efffddf1230e77365bc816a0d7943a79e28337a7a9f1d10d92e414b847e64736f6c634300080d0033
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.