Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 7 from a total of 7 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Enter Farm ETH | 18307133 | 385 days ago | IN | 0.22 ETH | 0.01009749 | ||||
Enter Farm ETH | 18284520 | 388 days ago | IN | 5 ETH | 0.01064207 | ||||
Exit Farm | 18278764 | 389 days ago | IN | 0 ETH | 0.01078952 | ||||
Enter Farm ETH | 18278761 | 389 days ago | IN | 1 ETH | 0.01363003 | ||||
Exit Farm | 18278736 | 389 days ago | IN | 0 ETH | 0.01273074 | ||||
Enter Farm ETH | 18278718 | 389 days ago | IN | 0.25 ETH | 0.01687954 | ||||
0x61022060 | 18278661 | 389 days ago | IN | 0 ETH | 0.08435257 |
Latest 18 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18307133 | 385 days ago | 3.3 ETH | ||||
18307133 | 385 days ago | 3.3 ETH | ||||
18307133 | 385 days ago | 0.22 ETH | ||||
18284520 | 388 days ago | 35 ETH | ||||
18284520 | 388 days ago | 35 ETH | ||||
18284520 | 388 days ago | 5 ETH | ||||
18278764 | 389 days ago | 0.99782899 ETH | ||||
18278764 | 389 days ago | 3 ETH | ||||
18278764 | 389 days ago | 3.99782899 ETH | ||||
18278761 | 389 days ago | 4 ETH | ||||
18278761 | 389 days ago | 4 ETH | ||||
18278761 | 389 days ago | 1 ETH | ||||
18278736 | 389 days ago | 0.2479793 ETH | ||||
18278736 | 389 days ago | 3.50000001 ETH | ||||
18278736 | 389 days ago | 3.74797931 ETH | ||||
18278718 | 389 days ago | 3.75 ETH | ||||
18278718 | 389 days ago | 3.75 ETH | ||||
18278718 | 389 days ago | 0.25 ETH |
Loading...
Loading
Contract Name:
wstETHManager
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "./wstETHFarm.sol"; import "../../OwnableMaster.sol"; contract wstETHManager is ERC721Enumerable, OwnableMaster, wstETHFarm { string public baseURI; string public baseExtension; // Tracks increment of keys uint256 public totalMinted; // Tracks reserved counter uint256 public totalReserved; // Tracks amount of reusable NFTs uint256 public availableNFTCount; // Maps access to wiseLendingNFT through farmNFT mapping(uint256 => uint256) public farmingKeys; // Tracks reusable wiseLendingNFTs after burn mapping(uint256 => uint256) public availableNFTs; // Tracks reserved NFTs mapped to address mapping(address => uint256) public reserved; modifier onlyKeyOwner( uint256 _keyId ) { if (isOwner(_keyId, msg.sender) == false) { revert InvalidOwner(); } _; } constructor( string memory _name, string memory _symbol, string memory _initBaseURI, address _wiseLendingAddress, uint256 _collateralFactor ) ERC721( _name, _symbol ) OwnableMaster( msg.sender ) wstETHFarm( _wiseLendingAddress, _collateralFactor ) { baseURI = _initBaseURI; } function _incrementReserved() internal returns (uint256) { return ++totalReserved; } function changeMinDeposit( uint256 _newMinDeposit ) external onlyMaster { minDepositUsdAmount = _newMinDeposit; emit MinDepositChange( _newMinDeposit, block.timestamp ); } function _getNextReserveKey() internal returns (uint256) { return totalMinted + _incrementReserved(); } function _reserveKey( address _userAddress, uint256 _wiseLendingNFT ) internal returns (uint256) { if (reserved[_userAddress] > 0) { revert AlreadyReserved(); } uint256 keyId = _getNextReserveKey(); reserved[_userAddress] = keyId; farmingKeys[keyId] = _wiseLendingNFT; return keyId; } function getMinAmountOut( uint256 _keyId, uint256 _slippage ) external view returns (uint256) { uint256 collateral = _getPostionCollateralToken( farmingKeys[_keyId] ); uint256 amountStETH = WST_ETH.getStETHByWstETH( collateral ); uint256 amountOut = CURVE.get_dy( 1, 0, amountStETH ); return amountOut * _slippage / PRECISION_FACTOR_E18; } /** * @dev External function deactivating the power farm by * disableing the openPosition function. Allowing user * to manualy payback and withdraw. */ function shutdownFarm( bool _state ) external onlyMaster { isShutdown = _state; emit FarmStatus( _state, block.timestamp ); } /** * @dev Standard receive functions forwarding * directly send ETH to the master address. */ receive() external payable { emit ETHReceived( msg.value, msg.sender ); } /** * @dev External set function to change referral address * for lido staking. Can only be called by master. */ function changeRefAddress( address _newAddress ) external onlyMaster { referralAddress = _newAddress; emit ReferralUpdate( _newAddress, block.timestamp ); } function enterFarm( uint256 _amount, uint256 _leverage ) external isActive updatePools returns (uint256) { uint256 wiseLendingNFT = _getWiseLendingNFT(); _safeTransferFrom( WETH_ADDRESS, msg.sender, address(this), _amount ); _openPosition( wiseLendingNFT, _amount, _leverage ); uint256 keyId = _reserveKey( msg.sender, wiseLendingNFT ); emit FarmEntry( keyId, wiseLendingNFT, _leverage, _amount, block.timestamp ); return keyId; } function enterFarmETH( uint256 _leverage ) external payable isActive updatePools returns (uint256) { uint256 wiseLendingNFT = _getWiseLendingNFT(); _wrapETH( msg.value ); _openPosition( wiseLendingNFT, msg.value, _leverage ); uint256 keyId = _reserveKey( msg.sender, wiseLendingNFT ); emit FarmEntry( keyId, wiseLendingNFT, _leverage, msg.value, block.timestamp ); return keyId; } function _getWiseLendingNFT() internal returns (uint256) { if (availableNFTCount == 0) { uint256 nftId = POSITION_NFT.mintPositionForUser( address(this) ); _registrationFarm( nftId ); POSITION_NFT.approve( AAVE_HUB_ADDRESS, nftId ); return nftId; } return availableNFTs[ availableNFTCount-- ]; } function exitFarm( uint256 _keyId, uint256 _minOutAmount, bool _ethBack ) external updatePools onlyKeyOwner(_keyId) { uint256 wiseLendingNFT = farmingKeys[ _keyId ]; delete farmingKeys[ _keyId ]; if (reserved[msg.sender] == _keyId) { reserved[msg.sender] = 0; } else { _burn( _keyId ); } emit FarmExit( _keyId, wiseLendingNFT, _minOutAmount, block.timestamp ); availableNFTs[ ++availableNFTCount ] = wiseLendingNFT; _closingPosition( wiseLendingNFT, _minOutAmount, _ethBack ); } function manuallyPaybackShares( uint256 _keyId, uint256 _paybackShares ) external updatePools { _manuallyPaybackShares( farmingKeys[_keyId], _paybackShares ); emit ManualPaybackShares( _keyId, farmingKeys[_keyId], _paybackShares, block.timestamp ); } function manuallyWithdrawShares( uint256 _keyId, uint256 _withdrawShares ) external updatePools onlyKeyOwner(_keyId) { _manuallyWithdrawShares( farmingKeys[_keyId], _withdrawShares ); emit ManualWithdrawShares( _keyId, farmingKeys[_keyId], _withdrawShares, block.timestamp ); } function isOwner( uint256 _keyId, address _owner ) public view returns (bool) { if (reserved[_owner] == _keyId) { return true; } if (ownerOf(_keyId) == _owner) { return true; } return false; } function _mintKeyForUser( uint256 _keyId, address _userAddress ) internal returns (uint256) { if (_keyId == 0) { revert InvalidKey(); } delete reserved[ _userAddress ]; _mint( _userAddress, _keyId ); totalMinted++; totalReserved--; return _keyId; } function approveMint( address _spender, uint256 _keyId ) external { if (reserved[msg.sender] == _keyId) { _mintKeyForUser( _keyId, msg.sender ); } approve( _spender, _keyId ); } function mintReserved() external returns (uint256) { return _mintKeyForUser( reserved[ msg.sender ], msg.sender ); } /** * @dev Returns positions of owner */ function walletOfOwner( address _owner ) external view returns (uint256[] memory) { uint256 reservedId = reserved[ _owner ]; uint256 ownerTokenCount = balanceOf( _owner ); uint256 reservedCount; if (reservedId > 0) { reservedCount = 1; } uint256[] memory tokenIds = new uint256[]( ownerTokenCount + reservedCount ); uint256 i; for (i; i < ownerTokenCount; ++i) { tokenIds[i] = tokenOfOwnerByIndex( _owner, i ); } if (reservedId > 0) { tokenIds[i] = reservedId; } return tokenIds; } /** * @dev Allows to update base target for MetaData. */ function setBaseURI( string memory _newBaseURI ) external onlyMaster { baseURI = _newBaseURI; emit BaseUrlChange( _newBaseURI, block.timestamp ); } function setBaseExtension( string memory _newBaseExtension ) external onlyMaster { baseExtension = _newBaseExtension; emit BaseExtensionChange( _newBaseExtension, block.timestamp ); } /** * @dev Returns path to MetaData URI */ function tokenURI( uint256 _tokenId ) public view override returns (string memory) { require( _exists(_tokenId) == true, "wstETHManager: WRONG_TOKEN" ); string memory currentBaseURI = baseURI; if (bytes(currentBaseURI).length == 0) { return ""; } return string( abi.encodePacked( currentBaseURI, _toString(_tokenId), baseExtension ) ); } /** * @dev Converts tokenId uint to string. */ function _toString( uint256 _tokenId ) internal pure returns (string memory str) { if (_tokenId == 0) { return "0"; } uint256 j = _tokenId; uint256 length; while (j != 0) { length++; j /= 10; } bytes memory bstr = new bytes( length ); uint256 k = length; j = _tokenId; while (j != 0) { bstr[--k] = bytes1( uint8( 48 + j % 10 ) ); j /= 10; } str = string( bstr ); } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; error NotMaster(); error NotProposed(); contract OwnableMaster { address public master; address public proposedMaster; address constant ZERO_ADDRESS = address(0x0); modifier onlyProposed() { _onlyProposed(); _; } function _onlyMaster() private view { if (msg.sender == master) { return; } revert NotMaster(); } modifier onlyMaster() { _onlyMaster(); _; } function _onlyProposed() private view { if (msg.sender == proposedMaster) { return; } revert NotProposed(); } constructor( address _master ) { master = _master; } /** * @dev Allows to propose next master. * Must be claimed by proposer. */ function proposeOwner( address _proposedOwner ) external onlyMaster { proposedMaster = _proposedOwner; } /** * @dev Allows to claim master role. * Must be called by proposer. */ function claimOwnership() external onlyProposed { master = proposedMaster; } /** * @dev Removes master role. * No ability to be in control. */ function renounceOwnership() external onlyMaster { master = ZERO_ADDRESS; proposedMaster = ZERO_ADDRESS; } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; /** * @author Christoph Krpoun * @author René Hochmuth * @author Vitally Marinchenko */ import "./wstETHFarmLeverageLogic.sol"; /** * @dev The wstETH power farm is an automated leverage contract working as a * second layer for Wise lending. It needs to be registed inside the latter one * to have access to the pools. It uses BALANCER FLASHLOANS as well as CURVE POOLS and * the LIDO contracts for staked ETH and wrapped staked ETH. * The corresponding contract addresses can be found in {wstETHFarmDeclarations.sol}. * * It allows to open leverage positions with wrapped ETH in form of aave wrapped ETH. * For opening a position the user needs to have {_initalAmount} of ETH or WETH in the wallet. * A maximum of 15x leverage is possible. Once the user registers with its position NFT that * NFT is locked for ALL other interactions with wise lending as long as the positon is open! * * For more infos see {https://wisesoft.gitbook.io/wise/} */ contract wstETHFarm is wstETHFarmLeverageLogic { constructor( address _wiseLendingAddress, uint256 _collateralFactor ) wstETHFarmDeclarations( _wiseLendingAddress, _collateralFactor ) {} /** * @dev External view function approximating the * new resulting net APY for a position setup. * * Note: Not 100% accurate because no syncPool is performed. */ function getApproxNetAPY( uint256 _initialAmount, uint256 _leverage, uint256 _wstETHAPY ) external view returns ( uint256, bool ) { return _getApproxNetAPY( _initialAmount, _leverage, _wstETHAPY ); } /** * @dev External view function approximating the * new borrow amount for the pool when {_borrowAmount} * is borrowed. * * Note: Not 100% accurate because no syncPool is performed. */ function getNewBorrowRate( uint256 _borrowAmount ) external view returns (uint256) { return _getNewBorrowRate( _borrowAmount ); } /** * @dev View functions returning the current * debt ratio of the postion with {_nftId} */ function getLiveDebtRatio( uint256 _nftId ) external view returns (uint256) { uint256 totalCollateral = getTotalWeightedCollateralUSD( _nftId ); if (totalCollateral == 0) { return 0; } return getPositionBorrowUSD(_nftId) * PRECISION_FACTOR_E18 / totalCollateral; } /** * @dev Liquidation function for open power farm * postions which have a debtratio greater 100 %. * * NOTE: The borrow token is defined by the power farm * and is always aave wrapped ETH. * The receiving token is always wrapped staked ETH. */ function liquidatePartiallyFromToken( uint256 _nftId, uint256 _nftIdLiquidator, uint256 _shareAmountToPay ) external updatePools returns ( uint256 paybackAmount, uint256 receivingAmount ) { return _coreLiquidation( _nftId, _nftIdLiquidator, _shareAmountToPay ); } /** * @dev Manually payback function for users. Takes * {_paybackShares} which can be converted * into token with {paybackAmount()} or vice verse * with {calculateBorrowShares()} from wise lending * contract. */ function _manuallyPaybackShares( uint256 _nftId, uint256 _paybackShares ) internal { uint256 paybackAmount = WISE_LENDING.paybackAmount( AAVE_WETH_ADDRESS, _paybackShares ); _safeTransferFrom( AAVE_WETH_ADDRESS, msg.sender, address(this), paybackAmount ); WISE_LENDING.paybackExactShares( _nftId, AAVE_WETH_ADDRESS, _paybackShares ); } /** * @dev Manually withdraw function for users. Takes * {_withdrawShares} which can be converted * into token with {cashoutAmount()} or vice verse * with {calculateLendingShares()} from wise lending * contract. */ function _manuallyWithdrawShares( uint256 _nftId, uint256 _withdrawShares ) internal { uint256 withdrawAmount = WISE_LENDING.cashoutAmount( WST_ETH_ADDRESS, _withdrawShares ); if (_checkBorrowLimit(_nftId, withdrawAmount) == false) { revert ResultsInBadDebt(); } withdrawAmount = WISE_LENDING.withdrawExactShares( _nftId, WST_ETH_ADDRESS, _withdrawShares ); _safeTransfer( WST_ETH_ADDRESS, msg.sender, withdrawAmount ); } /** * @dev Internal function combining the core * logic for {openPosition()}. */ function _openPosition( uint256 _nftId, uint256 _initialAmount, uint256 _leverage ) internal { if (_leverage > MAX_LEVERAGE) { revert LeverageTooHigh(); } uint256 leveragedAmount = getLeverageAmount( _initialAmount, _leverage ); uint256 flashloanAmount = leveragedAmount - _initialAmount; if (_aboveMinDepositAmount(leveragedAmount) == false) { revert AmountTooSmall(); } _executeBalancerFlashLoan( { _nftId: _nftId, _amount: flashloanAmount, _initialAmount: _initialAmount, _lendingShares: 0, _borrowShares: 0, _minAmountOut: 0, _ethBack: false } ); } /** * @dev Internal function combining the core * logic for {closingPosition()}. * * Note: {_minOutAmount} passed through UI by querring * {get_dy()} from curve pool contract. */ function _closingPosition( uint256 _nftId, uint256 _minOutAmount, bool _ethBack ) internal { uint256 borrowShares = _getPositionBorrowShares( _nftId ); uint256 lendingShares = _getPositionLendingShares( _nftId ); uint256 borrowAmount = _getPositionBorrowToken( _nftId ); _executeBalancerFlashLoan( { _nftId: _nftId, _amount: borrowAmount, _initialAmount: 0, _lendingShares: lendingShares, _borrowShares: borrowShares, _minAmountOut: _minOutAmount, _ethBack: _ethBack } ); } /** * @dev Makes a call to WISE_LENDING to * register {_nftId} for specific farm use. */ function _registrationFarm( uint256 _nftId ) internal { WISE_LENDING.setRegistrationIsolationPool( _nftId, true ); emit RegistrationFarm( _nftId, block.timestamp ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev See {ERC721-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); if (batchSize > 1) { // Will only trigger during construction. Batch transferring (minting) is not available afterwards. revert("ERC721Enumerable: consecutive transfers not supported"); } uint256 tokenId = firstTokenId; if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "./wstETHFarmMathLogic.sol"; abstract contract wstETHFarmLeverageLogic is wstETHFarmMathLogic, IFlashLoanRecipient { /** * @dev Wrapper function preparing balancer flashloan and * loading data to pass into receiver. */ function _executeBalancerFlashLoan( uint256 _nftId, uint256 _amount, uint256 _initialAmount, uint256 _lendingShares, uint256 _borrowShares, uint256 _minAmountOut, bool _ethBack ) internal { bytes memory data = abi.encode( _nftId, _initialAmount, _lendingShares, _borrowShares, _minAmountOut, msg.sender, _ethBack ); globalTokens.push( WETH ); globalAmounts.push( _amount ); allowEnter = true; BALANCER_VAULT.flashLoan( this, globalTokens, globalAmounts, data ); globalTokens.pop(); globalAmounts.pop(); } /** * @dev Receive function from balancer flashloan. Body * is called from balancer at the end of their {flashLoan()} * logic. Overwritten with opening flows. */ function receiveFlashLoan( IERC20[] memory _flashloanToken, uint256[] memory _amounts, uint256[] memory _feeAmounts, bytes memory _userData ) external { if (allowEnter == false) { revert AccessDenied(); } allowEnter = false; if (_flashloanToken.length == 0) { revert InvalidParam(); } if (msg.sender != BALANCER_ADDRESS) { revert NotBalancerVault(); } uint256 flashloanAmount = _amounts[0]; uint256 totalDebtBalancer = flashloanAmount + _feeAmounts[0]; ( uint256 nftId, uint256 initialAmount, uint256 lendingShares, uint256 borrowShares, uint256 minOutAmount, address caller, bool ethBack ) = abi.decode( _userData, ( uint256, uint256, uint256, uint256, uint256, address, bool ) ); if (initialAmount == 0) { _logicClosePosition( nftId, borrowShares, lendingShares, totalDebtBalancer, minOutAmount, caller, ethBack ); return; } _logicOpenPosition( nftId, flashloanAmount + initialAmount, totalDebtBalancer ); } /** * @dev Core logic for closing a position using balancer * flashloans. */ function _logicClosePosition( uint256 _nftId, uint256 _borrowShares, uint256 _lendingShares, uint256 _totalDebtBalancer, uint256 _minOutAmount, address _caller, bool _ethBack ) internal { AAVE_HUB.paybackExactShares( _nftId, WETH_ADDRESS, _borrowShares ); uint256 withdrawAmount = WISE_LENDING.withdrawExactShares( _nftId, WST_ETH_ADDRESS, _lendingShares ); uint256 stETHAmount = WST_ETH.unwrap( withdrawAmount ); uint256 ethAmount = _swapStETHintoETH( stETHAmount, _minOutAmount ); if (_ethBack == true) { _closingRouteETH( ethAmount, _totalDebtBalancer, _caller ); return; } _closingRouteWETH( ethAmount, _totalDebtBalancer, _caller ); } /** * @dev Internal wrapper function for a closing route * which returns WETH to the owner in the end. */ function _closingRouteWETH( uint256 _ethAmount, uint256 _totalDebtBalancer, address _caller ) internal { _wrapETH( _ethAmount ); _safeTransfer( WETH_ADDRESS, msg.sender, _totalDebtBalancer ); _safeTransfer( WETH_ADDRESS, _caller, _ethAmount - _totalDebtBalancer ); } /** * @dev Internal wrapper function for a closing route * which returns ETH to the owner in the end. */ function _closingRouteETH( uint256 _ethAmount, uint256 _totalDebtBalancer, address _caller ) internal { _wrapETH( _totalDebtBalancer ); _safeTransfer( WETH_ADDRESS, msg.sender, _totalDebtBalancer ); payable(_caller).transfer( _ethAmount - _totalDebtBalancer ); } /** * @dev Internal wrapper function for curve swap * of stETH into ETH. */ function _swapStETHintoETH( uint256 _swapAmount, uint256 _minOutAmount ) internal returns (uint256) { return CURVE.exchange( { fromIndex: 1, toIndex: 0, exactAmountFrom: _swapAmount, minReceiveAmount: _minOutAmount } ); } /** * @dev Internal function executing the * collateral deposit by converting ETH * into wstETH, adding it as collateral and * borrowing the flashloan token (WETH) to pay * back {_totalDebtBalancer}. */ function _logicOpenPosition( uint256 _nftId, uint256 _depositAmount, uint256 _totalDebtBalancer ) internal { _unwrapETH( _depositAmount ); uint256 stETHShares = ST_ETH.submit{ value: _depositAmount }( referralAddress ); uint256 stETHAmount = ST_ETH.getPooledEthByShares( stETHShares ); uint256 wstETHAmount = WST_ETH.wrap( stETHAmount ); WISE_LENDING.depositExactAmount( _nftId, WST_ETH_ADDRESS, wstETHAmount ); AAVE_HUB.borrowExactAmount( _nftId, WETH_ADDRESS, _totalDebtBalancer ); if (_checkDebtRatio(_nftId) == false) { revert DebtRatioTooHigh(); } _safeTransfer( WETH_ADDRESS, BALANCER_ADDRESS, _totalDebtBalancer ); } /** * @dev Internal function summarizing liquidation * checks and interface call for core liquidation * from wise lending. */ function _coreLiquidation( uint256 _nftId, uint256 _nftIdLiquidator, uint256 _shareAmountToPay ) internal returns ( uint256 paybackAmount, uint256 receivingAmount ) { if (_checkDebtRatio(_nftId) == true) { revert DebtRatioTooLow(); } paybackAmount = WISE_LENDING.paybackAmount( AAVE_WETH_ADDRESS, _shareAmountToPay ); receivingAmount = WISE_LENDING.coreLiquidationIsolationPools( _nftId, _nftIdLiquidator, msg.sender, msg.sender, AAVE_WETH_ADDRESS, WST_ETH_ADDRESS, paybackAmount, _shareAmountToPay ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "./wstETHFarmDeclarations.sol"; abstract contract wstETHFarmMathLogic is wstETHFarmDeclarations { /** * @dev Wrapper for wrapping * ETH call. */ function _wrapETH( uint256 _value ) internal { WETH.deposit{ value: _value }(); } /** * @dev Wrapper for unwrapping * ETH call. */ function _unwrapETH( uint256 _value ) internal { WETH.withdraw( _value ); } modifier updatePools() { _updatePools(); _; } /** * @dev Update logic for pools via wise lending * interfaces */ function _updatePools() private { WISE_LENDING.preparePool( WST_ETH_ADDRESS ); WISE_LENDING.preparePool( AAVE_WETH_ADDRESS ); } /** * @dev Internal function getting the * borrow shares from position {_nftId} * with token {_borrowToken} */ function _getPositionBorrowShares( uint256 _nftId ) internal view returns (uint256) { return WISE_LENDING.getPositionBorrowShares( _nftId, AAVE_WETH_ADDRESS ); } /** * @dev Internal function converting * borrow shares into tokens. */ function _getPositionBorrowToken( uint256 _nftId ) internal view returns(uint256) { return WISE_LENDING.paybackAmount( AAVE_WETH_ADDRESS, _getPositionBorrowShares( _nftId ) ); } /** * @dev Internal function getting the * lending shares from position {_nftId} * with token {_borrowToken} */ function _getPositionLendingShares( uint256 _nftId ) internal view returns (uint256) { return WISE_LENDING.getPositionLendingShares( _nftId, WST_ETH_ADDRESS ); } /** * @dev Internal function converting * lending shares into tokens. */ function _getPostionCollateralToken( uint256 _nftId ) internal view returns(uint256) { return WISE_LENDING.cashoutAmount( WST_ETH_ADDRESS, _getPositionLendingShares( _nftId ) ); } /** * @dev Read function returning the total * borrow amount in USD from postion {_nftId} */ function getPositionBorrowUSD( uint256 _nftId ) public view returns (uint256) { return ORACLE_HUB.getTokensInUSD( AAVE_WETH_ADDRESS, _getPositionBorrowToken( _nftId ) ); } /** * @dev Read function returning the total * lending amount in USD from postion {_nftId} */ function getTotalWeightedCollateralUSD( uint256 _nftId ) public view returns (uint256) { return ORACLE_HUB.getTokensInUSD( WST_ETH_ADDRESS, _getPostionCollateralToken(_nftId) ) * collateralFactor / PRECISION_FACTOR_E18; } /** * @dev Internal function checking if a position * with {_nftId} is still used to lock it for * unregister function. */ function getLeverageAmount( uint256 _initialAmount, uint256 _leverage ) public pure returns (uint256) { return _initialAmount * _leverage / PRECISION_FACTOR_E18; } /** * @dev Internal function with math logic for approximating * the net APY for the postion aftrer creation. */ function _getApproxNetAPY( uint256 _initialAmount, uint256 _leverage, uint256 _wstETHAPY ) internal view returns ( uint256, bool ) { if (_leverage < PRECISION_FACTOR_E18) { return (0, false); } uint256 leveragedAmount = getLeverageAmount( _initialAmount, _leverage ); uint256 flashloanAmount = leveragedAmount - _initialAmount; uint256 newBorrowRate = _getNewBorrowRate( flashloanAmount ); uint256 leveragedPositivAPY = _wstETHAPY * _leverage / PRECISION_FACTOR_E18; uint256 leveragedNegativeAPY = newBorrowRate * (_leverage - PRECISION_FACTOR_E18) / PRECISION_FACTOR_E18; bool isPositive = leveragedPositivAPY >= leveragedNegativeAPY; uint256 netAPY = isPositive == true ? leveragedPositivAPY - leveragedNegativeAPY : leveragedNegativeAPY - leveragedPositivAPY; return ( netAPY, isPositive ); } /** * @dev Internal function with math logic for approximating * the new borrow APY. */ function _getNewBorrowRate( uint256 _borrowAmount ) internal view returns (uint256) { uint256 totalPool = WISE_LENDING.getTotalPool( AAVE_WETH_ADDRESS ); uint256 pseudoPool = WISE_LENDING.getPseudoTotalPool( AAVE_WETH_ADDRESS ); if (totalPool > pseudoPool) { return 0; } uint256 newUtilization = PRECISION_FACTOR_E18 - (PRECISION_FACTOR_E18 * (totalPool - _borrowAmount) / pseudoPool ); uint256 pole = WISE_LENDING.borrowRatesData( AAVE_WETH_ADDRESS ).pole; uint256 mulFactor = WISE_LENDING.borrowRatesData( AAVE_WETH_ADDRESS ).multiplicativeFactor; uint256 baseDivider = pole * (pole - newUtilization); return mulFactor * PRECISION_FACTOR_E18 * newUtilization / baseDivider; } /** * @dev Internal function checking if a position * with {_nftId} has a debt ratio under 100%. */ function _checkDebtRatio( uint256 _nftId ) internal view returns (bool res) { res = getTotalWeightedCollateralUSD(_nftId) > getPositionBorrowUSD(_nftId); } /** * @dev Internal function checking if the debt * ratio threshold fof 100 % is reached when a * manually withdraw is performed. */ function _checkBorrowLimit( uint256 _nftId, uint256 _amount ) internal view returns (bool) { uint256 borrowAmount = getPositionBorrowUSD( _nftId ); if (borrowAmount == 0) { return true; } uint256 withdrawValue = ORACLE_HUB.getTokensInUSD( WST_ETH_ADDRESS, _amount ) * collateralFactor / PRECISION_FACTOR_E18; return getTotalWeightedCollateralUSD(_nftId) - withdrawValue > borrowAmount; } /** * @dev Internal function checking if the leveraged * amount is above 5000 USD in value. */ function _aboveMinDepositAmount( uint256 _amount ) internal view returns (bool) { uint256 equivUSD = ORACLE_HUB.getTokensInUSD( WETH_ADDRESS, _amount ); return equivUSD >= minDepositUsdAmount; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "../../InterfaceHub/IWETH.sol"; import "../../InterfaceHub/IAave.sol"; import "../../InterfaceHub/IStETH.sol"; import "../../InterfaceHub/ICurve.sol"; import "../../InterfaceHub/IWstETH.sol"; import "../../InterfaceHub/IAaveHub.sol"; import "../../InterfaceHub/IWiseLending.sol"; import "../../InterfaceHub/IWiseSecurity.sol"; import "../../InterfaceHub/IPositionNFTs.sol"; import "../../InterfaceHub/IWiseOracleHub.sol"; import "../../InterfaceHub/IBalancerFlashloan.sol"; import "../../TransferHub/TransferHelper.sol"; import "../../TransferHub/ApprovalHelper.sol"; error InvalidKey(); error Deactivated(); error InvalidParam(); error InvalidOwner(); error AccessDenied(); error AmountTooSmall(); error AlreadyReserved(); error LeverageTooHigh(); error DebtRatioTooLow(); error NotBalancerVault(); error DebtRatioTooHigh(); error ResultsInBadDebt(); contract wstETHFarmDeclarations is TransferHelper, ApprovalHelper { // Bool indicating that a power farm is deactivated bool public isShutdown; // Bool indicating transaction in progress bool internal allowEnter; // Array of ERC20 interfaces for balancer flashloan IERC20[] public globalTokens; // Array of token amounts for balancer flashloan uint256[] public globalAmounts; // Corresponding Aave borrow token used by farm address public immutable aaveTokenAddresses; // Borrow token used by farm address public immutable borrowTokenAddresses; // Referral address used for lido address public referralAddress; // Collateral factor used for sDAI collateral uint256 public collateralFactor; IWETH public immutable WETH; IAave public immutable AAVE; ICurve public immutable CURVE; IStETH public immutable ST_ETH; IWstETH public immutable WST_ETH; IAaveHub public immutable AAVE_HUB; IWiseLending public immutable WISE_LENDING; IWiseOracleHub public immutable ORACLE_HUB; IWiseSecurity public immutable WISE_SECURITY; IBalancerVault public immutable BALANCER_VAULT; IPositionNFTs public immutable POSITION_NFT; // @TODO: need to fetch from AAVE_HUB address constant AAVE_ADDRESS = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2; // @TODO: need to fetch from WISE_LENDING address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // @TODO: can we fetch this from somewhere dynamically? if not pass in constructor address constant ST_ETH_ADDRESS = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; // @TODO: can we fetch this from somewhere dynamically? if not pass in constructor address constant WST_ETH_ADDRESS = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; // @TODO: can we fetch this from somewhere dynamically? if not pass in constructor address constant BALANCER_ADDRESS = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; // @TODO: need to fetch from WISE_LENDING address constant AAVE_HUB_ADDRESS = 0x4307d8207f2C429f0dCbd9051b5B1d638c3b7fbB; // @TODO: need to fetch from AAVE_HUB address constant AAVE_WETH_ADDRESS = 0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8; // @TODO: can we fetch this from somewhere dynamically? if not pass in constructor address constant CURVE_POOL_ADDRESS = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022; // Math constant for computations uint256 constant PRECISION_FACTOR_E18 = 1E18; // Maximal allowed leverage factor uint256 constant MAX_LEVERAGE = 15 * PRECISION_FACTOR_E18; // Minimal required deposit amount for leveraged postion in USD uint256 public minDepositUsdAmount = 5000 * PRECISION_FACTOR_E18; // Max possible amount for uint256 uint256 constant MAX_AMOUNT = type(uint256).max; event FarmEntry( uint256 indexed keyId, uint256 indexed wiseLendingNFT, uint256 indexed leverage, uint256 amount, uint256 timestamp ); event FarmExit( uint256 indexed keyId, uint256 indexed wiseLendingNFT, uint256 amount, uint256 timestamp ); event FarmStatus( bool indexed state, uint256 timestamp ); event ReferralUpdate( address indexed referralAddress, uint256 timestamp ); event ManualPaybackShares( uint256 indexed keyId, uint256 indexed wiseLendingNFT, uint256 amount, uint256 timestamp ); event ManualWithdrawShares( uint256 indexed keyId, uint256 indexed wiseLendingNFT, uint256 amount, uint256 timestamp ); event BaseUrlChange( string baseUrl, uint256 timestamp ); event BaseExtensionChange( string baseExtension, uint256 timestamp ); event MinDepositChange( uint256 minDepositUsdAmount, uint256 timestamp ); event ERC721Received( address operator, address from, uint256 tokenId, bytes _data ); event ETHReceived( uint256 amount, address from ); event RegistrationFarm( uint256 nftId, uint256 timestamp ); constructor( address _wiseLendingAddress, uint256 _collateralFactor ) { WISE_LENDING = IWiseLending( _wiseLendingAddress ); ORACLE_HUB = IWiseOracleHub( WISE_LENDING.WISE_ORACLE() ); BALANCER_VAULT = IBalancerVault( BALANCER_ADDRESS ); WISE_SECURITY = IWiseSecurity( WISE_LENDING.WISE_SECURITY() ); AAVE = IAave( AAVE_ADDRESS ); WETH = IWETH( WETH_ADDRESS ); ST_ETH = IStETH( ST_ETH_ADDRESS ); WST_ETH = IWstETH( WST_ETH_ADDRESS ); AAVE_HUB = IAaveHub( AAVE_HUB_ADDRESS ); CURVE = ICurve( CURVE_POOL_ADDRESS ); POSITION_NFT = IPositionNFTs( WISE_LENDING.POSITION_NFT() ); collateralFactor = _collateralFactor; borrowTokenAddresses = WETH_ADDRESS; aaveTokenAddresses = AAVE_WETH_ADDRESS; _doApprovals( _wiseLendingAddress ); } function doApprovals() external { _doApprovals( address(WISE_LENDING) ); } function _doApprovals( address _wiseLendingAddress ) internal { _safeApprove( AAVE_WETH_ADDRESS, _wiseLendingAddress, MAX_AMOUNT ); _safeApprove( WETH_ADDRESS, AAVE_HUB_ADDRESS, MAX_AMOUNT ); _safeApprove( ST_ETH_ADDRESS, WST_ETH_ADDRESS, MAX_AMOUNT ); _safeApprove( WST_ETH_ADDRESS, address(WISE_LENDING), MAX_AMOUNT ); _safeApprove( ST_ETH_ADDRESS, CURVE_POOL_ADDRESS, MAX_AMOUNT ); } modifier isActive() { if (isShutdown == true) { revert Deactivated(); } _; } function onERC721Received( address _operator, address _from, uint256 _tokenId, bytes calldata _data ) external returns (bytes4) { emit ERC721Received( _operator, _from, _tokenId, _data ); return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "./CallOptionalReturn.sol"; contract ApprovalHelper is CallOptionalReturn { bytes4 constant approveSelector = IERC20 .approve .selector; /** * @dev * Allows to execute safe approve for a token */ function _safeApprove( address _token, address _spender, uint256 _value ) internal { _callOptionalReturn( _token, abi.encodeWithSelector( approveSelector, _spender, _value ) ); } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "./CallOptionalReturn.sol"; contract TransferHelper is CallOptionalReturn { bytes4 constant transferSelector = IERC20 .transfer .selector; bytes4 constant transferFromSelector = IERC20 .transferFrom .selector; /** * @dev * Allows to execute safe transfer for a token */ function _safeTransfer( address _token, address _to, uint256 _value ) internal { _callOptionalReturn( _token, abi.encodeWithSelector( transferSelector, _to, _value ) ); } /** * @dev * Allows to execute safe transferFrom for a token */ function _safeTransferFrom( address _token, address _from, address _to, uint256 _value ) internal { _callOptionalReturn( _token, abi.encodeWithSelector( transferFromSelector, _from, _to, _value ) ); } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "../InterfaceHub/IERC20.sol"; interface IBalancerVault { /** * @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it, * and then reverting unless the tokens plus a proportional protocol fee have been returned. * * The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount * for each token contract. `tokens` must be sorted in ascending order. * * The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the * `receiveFlashLoan` call. * * Emits `FlashLoan` events. */ function flashLoan( IFlashLoanRecipient _recipient, IERC20[] memory _tokens, uint256[] memory _amounts, bytes memory _userData ) external; } interface IFlashLoanRecipient { /** * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient. * * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the * Vault, or else the entire flash loan will revert. * * `userData` is the same value passed in the `IVault.flashLoan` call. */ function receiveFlashLoan( IERC20[] memory _tokens, uint256[] memory _amounts, uint256[] memory _feeAmounts, bytes memory _userData ) external; }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IWiseOracleHub { function latestResolver( address _tokenAddress ) external view returns (uint256); function getTokensFromUSD( address _tokenAddress, uint256 _usdValue ) external view returns (uint256); function getTokensInUSD( address _tokenAddress, uint256 _amount ) external view returns (uint256); function chainLinkIsDead( address _tokenAddress ) external view returns (bool); function decimalsUSD() external pure returns (uint8); function previousValue( address _tokenAddress ) external view returns (uint256); function setPreviousValue( address _tokenAddress ) external; function addOracle( address _tokenAddress, address _priceFeedAddress, address[] memory _underlyingFeedTokens ) external; function recalibrate( address _tokenAddress ) external; function recalibratePreview( address _tokenAddress ) external view returns (uint256); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IPositionNFTs { function ownerOf( uint256 _nftId ) external view returns (address); function getOwner( uint256 _nftId ) external view returns (address); function totalSupply() external view returns (uint256); function reserved( address _owner ) external view returns (uint256); function reservePosition() external; function mintPosition() external; function tokenOfOwnerByIndex( address _owner, uint256 _index ) external view returns (uint256); function mintPositionForUser( address _user ) external returns (uint256); function reservePositionForUser( address _user ) external returns (uint256); function getApproved( uint256 _nftId ) external returns (address); function approve( address _to, uint256 _nftId ) external; }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; struct CurveSwapStructToken { uint256 curvePoolTokenIndexFrom; uint256 curvePoolTokenIndexTo; uint256 curveMetaPoolTokenIndexFrom; uint256 curveMetaPoolTokenIndexTo; } struct CurveSwapStructData { address curvePool; address curveMetaPool; bytes swapBytesPool; bytes swapBytesMeta; } interface IWiseSecurity { function overallUSDBorrowHeartbeat( uint256 _nftId ) external view returns (uint256 buffer); function checkBadDebt( uint256 _nftId ) external; function getFullCollateralUSD( uint256 _nftId, address _poolToken ) external view returns (uint256); function checksLiquidation( uint256 _nftIdLiquidate, address _tokenToPayback, uint256 _shareAmountToPay ) external view; function getPositionBorrowAmount( uint256 _nftId, address _poolToken ) external view returns (uint256); function getPositionLendingAmount( uint256 _nftId, address _poolToken ) external view returns (uint256); function getLiveDebtRatioNormalPool( uint256 _nftId ) external view returns (uint256); function overallUSDCollateralsBare( uint256 _nftId ) external view returns (uint256 amount); function FEE_MANAGER() external returns (address); function AAVE_HUB() external returns (address); function curveSecurityCheck( address _poolAddress ) external; function prepareCurvePools( address _poolToken, CurveSwapStructData memory _curveSwapStructData, CurveSwapStructToken memory _curveSwapStructToken ) external; function checksWithdraw( uint256 _nftId, address _caller, address _poolToken, uint256 _amount ) external view; function checksBorrow( uint256 _nftId, address _caller, address _poolToken, uint256 _amount ) external view; function checksSolelyWithdraw( uint256 _nftId, address _caller, address _poolToken, uint256 _amount ) external view; function checkOwnerPosition( uint256 _nftId, address _caller ) external view; function checksCollateralizeDeposit( uint256 _nftIdCaller, address _caller, address _poolAddress ) external view; function calculateWishPercentage( uint256 _nftId, address _receiveToken, uint256 _paybackUSD, uint256 _maxFeeUSD, uint256 _baseRewardLiquidation ) external view returns (uint256); function checksDecollateralizeDeposit( uint256 _nftIdCaller, address _poolToken ) external view; function checkBorrowLimit( uint256 _nftId, address _poolToken, uint256 _amount ) external view; function checkPositionLocked( uint256 _nftId, address _caller ) external view; function checkPaybackLendingShares( uint256 _nftIdReceiver, uint256 _nftIdCaller, address _caller, address _poolToken, uint256 _amount ) external view; function maxFeeUSD() external view returns (uint256); function maxFeeFarmUSD() external view returns (uint256); function baseRewardLiquidation() external view returns (uint256); function baseRewardLiquidationFarm() external view returns (uint256); function checksRegister( uint256 _nftId, address _caller ) external view; function getLendingRate( address _poolToken ) external view returns (uint256); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; struct GlobalPoolEntry { uint256 totalPool; uint256 utilization; uint256 totalBareToken; uint256 poolFee; } struct BorrowPoolEntry { bool allowBorrow; uint256 pseudoTotalBorrowAmount; uint256 totalBorrowShares; uint256 borrowRate; } struct LendingPoolEntry { uint256 pseudoTotalPool; uint256 totalDepositShares; uint256 collateralFactor; } struct PoolEntry { uint256 totalPool; uint256 utilization; uint256 totalBareToken; uint256 poolFee; } struct BorrowRatesEntry { uint256 pole; uint256 deltaPole; uint256 minPole; uint256 maxPole; uint256 multiplicativeFactor; } interface IWiseLending { function borrowRatesData( address _pooToken ) external view returns (BorrowRatesEntry memory); function newBorrowRate( address _poolToken ) external; function calculateBorrowShares( address _poolToken, uint256 _amount ) external view returns (uint256); function borrowPoolData( address _poolToken ) external view returns (BorrowPoolEntry memory); function lendingPoolData( address _poolToken ) external view returns (LendingPoolEntry memory); function getPositionBorrowShares( uint256 _nftId, address _poolToken ) external view returns (uint256); function getTimeStamp( address _poolToken ) external view returns (uint256); function getPureCollateralAmount( uint256 _nftId, address _poolToken ) external view returns (uint256); function isDecollteralized( uint256 _nftId, address _poolToken ) external view returns (bool); function veryfiedIsolationPool( address _poolAddress ) external view returns (bool); function positionLocked( uint256 _nftId ) external view returns (bool); function getTotalBareToken( address _poolToken ) external view returns (uint256); function maxDepositValueToken( address _poolToken ) external view returns (uint256); function master() external view returns (address); function WETH_ADDRESS() external view returns (address); function WISE_ORACLE() external view returns (address); function POSITION_NFT() external view returns (address); function FEE_MANAGER() external view returns (address); function WISE_SECURITY() external view returns (address); function lastUpdated( address _poolAddress ) external view returns (uint256); function isolationPoolRegistered( uint256 _nftId, address _isolationPool ) external view returns (bool); function calculateLendingShares( address _poolToken, uint256 _amount ) external view returns (uint256); function positionPureCollateralAmount( uint256 _nftId, address _poolToken ) external returns (uint256); function getTotalPool( address _poolToken ) external view returns (uint256); function depositExactAmount( uint256 _nftId, address _poolToken, uint256 _amount ) external returns (uint256); function withdrawOnBehalfExactAmount( uint256 _nftId, address _poolToken, uint256 _amount ) external returns (uint256); function syncManually( address _poolToken ) external; function withdrawOnBehalfExactShares( uint256 _nftId, address _poolToken, uint256 _shares ) external returns (uint256); function borrowOnBehalfExactAmount( uint256 _nftId, address _poolToken, uint256 _amount ) external returns (uint256); function borrowExactAmount( uint256 _nftId, address _poolToken, uint256 _amount ) external returns (uint256); function solelyDeposit( uint256 _nftId, address _poolToken, uint256 _amount ) external; function solelyWithdrawOnBehalf( uint256 _nftId, address _poolToken, uint256 _amount ) external; function paybackExactAmount( uint256 _nftId, address _poolToken, uint256 _amount ) external returns (uint256); function paybackExactShares( uint256 _nftId, address _poolToken, uint256 _shares ) external returns (uint256); function setPoolFee( address _poolToken, uint256 _newFee ) external; function getPositionLendingShares( uint256 _nftId, address _poolToken ) external view returns (uint256); function withdrawExactShares( uint256 _nftId, address _poolToken, uint256 _shares ) external returns (uint256); function poolTokenAddresses() external returns (address[] memory); function corePaybackFeeManager( address _poolToken, uint256 _nftId, uint256 _amount, uint256 _shares ) external; function coreLiquidationIsolationPools( uint256 _nftId, uint256 _nftIdLiquidator, address _caller, address _receiver, address _tokenToPayback, address _tokenToRecieve, uint256 _paybackAmount, uint256 _shareAmountToPay ) external returns (uint256 reveiveAmount); function preparePool( address _poolToken ) external; function getPositionBorrowTokenLength( uint256 _nftId ) external view returns (uint256); function getPositionBorrowTokenByIndex( uint256 _nftId, uint256 _index ) external view returns (address); function getPositionLendingTokenByIndex( uint256 _nftId, uint256 _index ) external view returns (address); function getPositionLendingTokenLength( uint256 _nftId ) external view returns (uint256); function globalPoolData( address _poolToken ) external view returns (GlobalPoolEntry memory); function getGlobalBorrowAmount( address _token ) external view returns (uint256); function getPseudoTotalBorrowAmount( address _token ) external view returns (uint256); function getInitialBorrowAmountUser( address _user, address _token ) external view returns (uint256); function getPseudoTotalPool( address _token ) external view returns (uint256); function getInitialDepositAmountUser( address _user, address _token ) external view returns (uint256); function getGlobalDepositAmount( address _token ) external view returns (uint256); function paybackAmount( address _token, uint256 _shares ) external view returns (uint256); function getPositionLendingShares( address _user, address _token ) external view returns (uint256); function cashoutAmount( address _token, uint256 _shares ) external view returns (uint256); function getTotalDepositShares( address _token ) external view returns (uint256); function getTotalBorrowShares( address _token ) external view returns (uint256); function checkPositionLocked( uint256 _nftId, address _caller ) external view; function checkDeposit( uint256 _nftId, address _caller, address _poolToken, uint256 _amount ) external view; function setRegistrationIsolationPool( uint256 _nftId, bool _state ) external; }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IAaveHub { function AAVE_ADDRESS() external view returns (address); function aaveTokenAddress( address _underlyingToken ) external view returns (address); function borrowExactAmount( uint256 _nftId, address _underlyingAsset, uint256 _borrowAmount ) external returns (uint256); function paybackExactShares( uint256 _nftId, address _underlyingAsset, uint256 _shares ) external returns (uint256); function paybackExactAmount( uint256 _nftId, address _underlyingAsset, uint256 _shares ) external returns (uint256); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IWstETH { function wrap( uint256 _stETHAmount ) external returns (uint256); function unwrap( uint256 _wstETHAmount ) external returns (uint256); function getStETHByWstETH( uint256 _wstETHAmount ) external view returns (uint256); function decimals() external view returns (uint8); function balanceOf( address _account ) external view returns (uint256); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface ICurve { function add_liquidity( address _pool, uint256[4] memory _depositAmounts, uint256 _minOutAmount ) external returns (uint256); function balanceOf( address _userAddress ) external view returns (uint256); function get_dy( int128 i, int128 j, uint256 dx ) external view returns (uint256); function get_dy_underlying( int128 i, int128 j, uint256 dx ) external view returns (uint256); function exchange( int128 fromIndex, int128 toIndex, uint256 exactAmountFrom, uint256 minReceiveAmount ) external returns (uint256); function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy ) external; function remove_liquidity( address _pool, uint256 _burnAmount, uint256[4] memory coins ) external; function remove_liquidity_one_coin( address _addy, uint256 _burnAmount, int128 _i, uint256 _minReceived ) external; function coins( uint256 arg0 ) external view returns (address); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balances( uint256 arg0 ) external view returns (uint256); function approve( address _spender, uint256 _amount ) external returns (bool); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IStETH { function submit( address _referral ) external payable returns (uint256); function balanceOf( address _account ) external view returns (uint256); function getPooledEthByShares( uint256 _sharesAmount ) external view returns (uint256); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IAave { struct ReserveData { // Stores the reserve configuration ReserveConfigurationMap configuration; // Liquidity index. Expressed in ray uint128 liquidityIndex; // Current supply rate. Expressed in ray uint128 currentLiquidityRate; // Variable borrow index. Expressed in ray uint128 variableBorrowIndex; // Current variable borrow rate. Expressed in ray uint128 currentVariableBorrowRate; // Current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate; // Timestamp of last update uint40 lastUpdateTimestamp; // Id of the reserve. uint16 id; // aToken address address aTokenAddress; // stableDebtToken address address stableDebtTokenAddress; // VariableDebtToken address address variableDebtTokenAddress; // Address of the interest rate strategy address interestRateStrategyAddress; // Current treasury balance, scaled uint128 accruedToTreasury; // Outstanding unbacked aTokens minted through the bridging feature uint128 unbacked; // Outstanding debt borrowed against this asset in isolation mode uint128 isolationModeTotalDebt; } struct ReserveConfigurationMap { uint256 data; } function deposit( address _token, uint256 _amount, address _owner, uint16 _referralCode ) external; function withdraw( address _token, uint256 _amount, address _recipient ) external returns (uint256); function getReserveData( address asset ) external view returns (ReserveData memory); }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "./IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw( uint256 ) external; }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; import "../InterfaceHub/IERC20.sol"; error CallFailed(); contract CallOptionalReturn { /** * @dev * Helper function to do low-level call */ function _callOptionalReturn( address token, bytes memory data ) internal returns (bool call) { ( bool success, bytes memory returndata ) = token.call( data ); bool results = returndata.length == 0 || abi.decode( returndata, (bool) ); call = success && results && token.code.length > 0; if (call == false) { revert CallFailed(); } } }
// SPDX-License-Identifier: -- WISE -- pragma solidity =0.8.21; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf( address _account ) external view returns (uint256); function transferFrom( address _sender, address _recipient, uint256 _amount ) external returns (bool); function transfer( address _recipient, uint256 _amount ) external returns (bool); function allowance( address owner, address spender ) external view returns (uint256); function approve( address _spender, uint256 _amount ) external returns (bool); function decimals() external view returns (uint8); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); event Deposit( address indexed dst, uint wad ); event Withdrawal( address indexed src, uint wad ); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_initBaseURI","type":"string"},{"internalType":"address","name":"_wiseLendingAddress","type":"address"},{"internalType":"uint256","name":"_collateralFactor","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AlreadyReserved","type":"error"},{"inputs":[],"name":"AmountTooSmall","type":"error"},{"inputs":[],"name":"CallFailed","type":"error"},{"inputs":[],"name":"Deactivated","type":"error"},{"inputs":[],"name":"DebtRatioTooHigh","type":"error"},{"inputs":[],"name":"DebtRatioTooLow","type":"error"},{"inputs":[],"name":"InvalidKey","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[],"name":"LeverageTooHigh","type":"error"},{"inputs":[],"name":"NotBalancerVault","type":"error"},{"inputs":[],"name":"NotMaster","type":"error"},{"inputs":[],"name":"NotProposed","type":"error"},{"inputs":[],"name":"ResultsInBadDebt","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseExtension","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BaseExtensionChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseUrl","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BaseUrlChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC721Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"}],"name":"ETHReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keyId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wiseLendingNFT","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"leverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FarmEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keyId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wiseLendingNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FarmExit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"state","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FarmStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keyId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wiseLendingNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ManualPaybackShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keyId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wiseLendingNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ManualWithdrawShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minDepositUsdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MinDepositChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referralAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ReferralUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RegistrationFarm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"contract IAave","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AAVE_HUB","outputs":[{"internalType":"contract IAaveHub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BALANCER_VAULT","outputs":[{"internalType":"contract IBalancerVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_HUB","outputs":[{"internalType":"contract IWiseOracleHub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POSITION_NFT","outputs":[{"internalType":"contract IPositionNFTs","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ST_ETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WISE_LENDING","outputs":[{"internalType":"contract IWiseLending","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WISE_SECURITY","outputs":[{"internalType":"contract IWiseSecurity","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WST_ETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aaveTokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_keyId","type":"uint256"}],"name":"approveMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"availableNFTCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"availableNFTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseExtension","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowTokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMinDeposit","type":"uint256"}],"name":"changeMinDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"changeRefAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_leverage","type":"uint256"}],"name":"enterFarm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_leverage","type":"uint256"}],"name":"enterFarmETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keyId","type":"uint256"},{"internalType":"uint256","name":"_minOutAmount","type":"uint256"},{"internalType":"bool","name":"_ethBack","type":"bool"}],"name":"exitFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"farmingKeys","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialAmount","type":"uint256"},{"internalType":"uint256","name":"_leverage","type":"uint256"},{"internalType":"uint256","name":"_wstETHAPY","type":"uint256"}],"name":"getApproxNetAPY","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialAmount","type":"uint256"},{"internalType":"uint256","name":"_leverage","type":"uint256"}],"name":"getLeverageAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nftId","type":"uint256"}],"name":"getLiveDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keyId","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"}],"name":"getMinAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowAmount","type":"uint256"}],"name":"getNewBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nftId","type":"uint256"}],"name":"getPositionBorrowUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nftId","type":"uint256"}],"name":"getTotalWeightedCollateralUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"globalAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"globalTokens","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keyId","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nftId","type":"uint256"},{"internalType":"uint256","name":"_nftIdLiquidator","type":"uint256"},{"internalType":"uint256","name":"_shareAmountToPay","type":"uint256"}],"name":"liquidatePartiallyFromToken","outputs":[{"internalType":"uint256","name":"paybackAmount","type":"uint256"},{"internalType":"uint256","name":"receivingAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keyId","type":"uint256"},{"internalType":"uint256","name":"_paybackShares","type":"uint256"}],"name":"manuallyPaybackShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keyId","type":"uint256"},{"internalType":"uint256","name":"_withdrawShares","type":"uint256"}],"name":"manuallyWithdrawShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"master","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositUsdAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintReserved","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_proposedOwner","type":"address"}],"name":"proposeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposedMaster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"_flashloanToken","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"_feeAmounts","type":"uint256[]"},{"internalType":"bytes","name":"_userData","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"referralAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reserved","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newBaseExtension","type":"string"}],"name":"setBaseExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"shutdownFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReserved","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6102206040526200001b670de0b6b3a764000061138862000525565b6010553480156200002a575f80fd5b5060405162005feb38038062005feb8339810160408190526200004d9162000631565b818181813389895f62000061838262000764565b50600162000070828262000764565b5050600a80546001600160a01b0319166001600160a01b0393841617905550821661018081905260408051637cc97da560e01b81529051637cc97da5916004808201926020929091908290030181865afa158015620000d1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620000f791906200082c565b6001600160a01b039081166101a05273ba12222222228d8ba445958a75a0704d566bf2c86101e0526101805160408051630f9f234d60e01b815290519190921691630f9f234d9160048083019260209291908290030181865afa15801562000161573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200018791906200082c565b6001600160a01b039081166101c0527387870bca3f3fd6335c3f4ce8392d69350b4fa4e260e05273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260c05273ae7ab96520de3a18e5e111b5eaab095312d7fe8461012052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca061014052734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb6101605273dc24316b9ae028f1497c275eb9192a3ea0f67022610100526101805160408051637c854ec760e01b815290519190921691637c854ec79160048083019260209291908290030181865afa1580156200026c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200029291906200082c565b6001600160a01b031661020052600f81905573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260a052734d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8608052620002df8262000300565b505050508260119081620002f4919062000764565b5050505050506200088d565b62000322734d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8825f19620003f2565b6200035873c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb5f19620003f2565b6200038e73ae7ab96520de3a18e5e111b5eaab095312d7fe84737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05f19620003f2565b620003b9737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0610180515f19620003f260201b60201c565b620003ef73ae7ab96520de3a18e5e111b5eaab095312d7fe8473dc24316b9ae028f1497c275eb9192a3ea0f670225f19620003f2565b50565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200044a9185916200045016565b50505050565b5f805f846001600160a01b0316846040516200046d91906200084f565b5f604051808303815f865af19150503d805f8114620004a8576040519150601f19603f3d011682016040523d82523d5f602084013e620004ad565b606091505b50915091505f81515f1480620004d4575081806020019051810190620004d491906200086c565b9050828015620004e15750805b8015620004f757505f866001600160a01b03163b115b93508315155f036200051c57604051633204506f60e01b815260040160405180910390fd5b50505092915050565b80820281158282048414176200054957634e487b7160e01b5f52601160045260245ffd5b92915050565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200057f57818101518382015260200162000565565b50505f910152565b5f82601f83011262000597575f80fd5b81516001600160401b0380821115620005b457620005b46200054f565b604051601f8301601f19908116603f01168101908282118183101715620005df57620005df6200054f565b81604052838152866020858801011115620005f8575f80fd5b6200060b84602083016020890162000563565b9695505050505050565b80516001600160a01b03811681146200062c575f80fd5b919050565b5f805f805f60a0868803121562000646575f80fd5b85516001600160401b03808211156200065d575f80fd5b6200066b89838a0162000587565b9650602088015191508082111562000681575f80fd5b6200068f89838a0162000587565b95506040880151915080821115620006a5575f80fd5b50620006b48882890162000587565b935050620006c56060870162000615565b9150608086015190509295509295909350565b600181811c90821680620006ed57607f821691505b6020821081036200070c57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200075f575f81815260208120601f850160051c810160208610156200073a5750805b601f850160051c820191505b818110156200075b5782815560010162000746565b5050505b505050565b81516001600160401b038111156200078057620007806200054f565b6200079881620007918454620006d8565b8462000712565b602080601f831160018114620007ce575f8415620007b65750858301515b5f19600386901b1c1916600185901b1785556200075b565b5f85815260208120601f198616915b82811015620007fe57888601518255948401946001909101908401620007dd565b50858210156200081c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f602082840312156200083d575f80fd5b620008488262000615565b9392505050565b5f82516200086281846020870162000563565b9190910192915050565b5f602082840312156200087d575f80fd5b8151801515811462000848575f80fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051610200516155b862000a335f395f8181610a58015281816126e7015261277b01525f8181610c79015261417a01525f61054e01525f8181610add015281816112a90152818161179601528181613fbf015261434901525f8181610c0801528181611a28015281816125ea015281816126690152818161298a01528181612a1401528181612ac901528181612b7f01528181612cb601528181612d7d01528181612eaa01528181612fb30152818161309701528181613342015281816133da015281816134bf01528181613550015281816136d0015281816139f401528181613e5b0152818161428301526142e501525f8181610a10015281816136290152613a9201525f81816108820152818161162201528181613779015261397001525f81816106d00152818161385401526138e401525f8181610703015281816116bb015261459801525f6107a001525f8181610bd501528181612f06015281816140f001526146d401525f61094501525f61069d01526155b85ff3fe608060405260043610610419575f3560e01c806370a0823111610220578063b56453e411610129578063da3ef23f116100b3578063e9f7b59a11610078578063e9f7b59a14610df3578063ec8c890414610e12578063ee97f7f314610e26578063f04f270714610e45578063fae8ccf014610e64575f80fd5b8063da3ef23f14610d22578063da9425e214610d41578063df011c4114610d6c578063e985e9c514610d81578063e9b2e0d714610dc8575f80fd5b8063bf86d690116100f9578063bf86d69014610c9b578063c668286214610cbb578063c71b0e1c14610ccf578063c87b56dd14610ce4578063d3573a3314610d03575f80fd5b8063b56453e414610bf7578063b5ed298a14610c2a578063b88d4fde14610c49578063bc16384614610c68575f80fd5b806395d89b41116101aa578063a1c44ae01161017a578063a1c44ae014610b52578063a22cb46514610b71578063a2309ff814610b90578063a96bb61114610ba5578063ad5c464814610bc4575f80fd5b806395d89b4114610ab85780639751a63f14610acc5780639a8a8c5314610aff5780639cba355914610b33575f80fd5b8063730e695d116101f0578063730e695d146109ff57806376c4b7db14610a325780637c854ec714610a475780638221e78114610a7a57806395d0de6014610a99575f80fd5b806370a082311461099a578063715018a6146109b95780637246bea1146109cd57806372d8a06c146109ec575f80fd5b806342842e0e116103225780635664cb48116102ac5780635ba6b9481161027c5780635ba6b948146109015780635d4f774214610920578063620c1ee9146109345780636352211e146109675780636c0360eb14610986575f80fd5b80635664cb481461087157806358fff2bc146108a45780635a5d096c146108c35780635aa79a4e146108e2575f80fd5b80634cacc937116102f25780634cacc937146107e15780634e71e0c8146108005780634f6ccce71461081457806353528bc01461083357806355f804b314610852575f80fd5b806342842e0e14610744578063438b63001461076357806348ccda3c1461078f5780634b2a12da146107c2575f80fd5b806318160ddd116103a35780632f745c59116103735780632f745c591461066d5780632fc0b9f41461068c578063338346d2146106bf5780633a3c3b87146106f25780633a74e87814610725575f80fd5b806318160ddd146105e657806323b872dd1461060457806327a4986b146106235780632d02bea21461064e575f80fd5b8063095ea7b3116103e9578063095ea7b31461051c5780630f9f234d1461053d57806313b39b9c14610570578063150b7a021461058f57806315a88d22146105c7575f80fd5b806301ffc9a71461045c57806306fdde0314610490578063081812fc146104b15780630861f2fd146104e8575f80fd5b3661045857604080513481523360208201527f49109bdae8e3bbdcbeb7fe5b25b1c75a6bc84fd3f27c6ee0633d41fe197f2aba910160405180910390a1005b5f80fd5b348015610467575f80fd5b5061047b6104763660046148df565b610e79565b60405190151581526020015b60405180910390f35b34801561049b575f80fd5b506104a4610ea3565b6040516104879190614947565b3480156104bc575f80fd5b506104d06104cb366004614959565b610f32565b6040516001600160a01b039091168152602001610487565b3480156104f3575f80fd5b50610507610502366004614970565b610f57565b60408051928352901515602083015201610487565b348015610527575f80fd5b5061053b6105363660046149ad565b610f71565b005b348015610548575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b34801561057b575f80fd5b5061053b61058a3660046149ad565b61108a565b34801561059a575f80fd5b506105ae6105a93660046149d7565b6110ba565b6040516001600160e01b03199091168152602001610487565b3480156105d2575f80fd5b50600e546104d0906001600160a01b031681565b3480156105f1575f80fd5b506008545b604051908152602001610487565b34801561060f575f80fd5b5061053b61061e366004614a6e565b61110c565b34801561062e575f80fd5b506105f661063d366004614959565b60166020525f908152604090205481565b348015610659575f80fd5b506105f6610668366004614aac565b61113d565b348015610678575f80fd5b506105f66106873660046149ad565b611206565b348015610697575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ca575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b3480156106fd575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610730575f80fd5b506105f661073f366004614959565b61129a565b34801561074f575f80fd5b5061053b61075e366004614a6e565b61135d565b34801561076e575f80fd5b5061078261077d366004614acc565b611377565b6040516104879190614ae7565b34801561079a575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b3480156107cd575f80fd5b5061053b6107dc366004614959565b611468565b3480156107ec575f80fd5b5061053b6107fb366004614aac565b6114b1565b34801561080b575f80fd5b5061053b61152a565b34801561081f575f80fd5b506105f661082e366004614959565b611556565b34801561083e575f80fd5b506105f661084d366004614aac565b6115e6565b34801561085d575f80fd5b5061053b61086c366004614bc4565b61174d565b34801561087c575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b3480156108af575f80fd5b506105f66108be366004614959565b611793565b3480156108ce575f80fd5b5061047b6108dd366004614c09565b611836565b3480156108ed575f80fd5b5061053b6108fc366004614c44565b61188e565b34801561090c575f80fd5b5061053b61091b366004614aac565b61197d565b34801561092b575f80fd5b5061053b611a23565b34801561093f575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610972575f80fd5b506104d0610981366004614959565b611a4e565b348015610991575f80fd5b506104a4611aad565b3480156109a5575f80fd5b506105f66109b4366004614acc565b611b39565b3480156109c4575f80fd5b5061053b611bbd565b3480156109d8575f80fd5b5061053b6109e7366004614acc565b611be3565b6105f66109fa366004614959565b611c40565b348015610a0a575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610a3d575f80fd5b506105f660155481565b348015610a52575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610a85575f80fd5b5061053b610a94366004614c7a565b611cf1565b348015610aa4575f80fd5b506104d0610ab3366004614959565b611d46565b348015610ac3575f80fd5b506104a4611d6e565b348015610ad7575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610b0a575f80fd5b50610b1e610b19366004614970565b611d7d565b60408051928352602083019190915201610487565b348015610b3e575f80fd5b506105f6610b4d366004614959565b611d92565b348015610b5d575f80fd5b506105f6610b6c366004614aac565b611db1565b348015610b7c575f80fd5b5061053b610b8b366004614c95565b611dd6565b348015610b9b575f80fd5b506105f660135481565b348015610bb0575f80fd5b506105f6610bbf366004614959565b611de1565b348015610bcf575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610c02575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610c35575f80fd5b5061053b610c44366004614acc565b611e1a565b348015610c54575f80fd5b5061053b610c63366004614cdf565b611e44565b348015610c73575f80fd5b506104d07f000000000000000000000000000000000000000000000000000000000000000081565b348015610ca6575f80fd5b50600b5461047b90600160a01b900460ff1681565b348015610cc6575f80fd5b506104a4611e7c565b348015610cda575f80fd5b506105f660145481565b348015610cef575f80fd5b506104a4610cfe366004614959565b611e89565b348015610d0e575f80fd5b50600b546104d0906001600160a01b031681565b348015610d2d575f80fd5b5061053b610d3c366004614bc4565b611fd4565b348015610d4c575f80fd5b506105f6610d5b366004614acc565b60186020525f908152604090205481565b348015610d77575f80fd5b506105f6600f5481565b348015610d8c575f80fd5b5061047b610d9b366004614d47565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205460ff1690565b348015610dd3575f80fd5b506105f6610de2366004614959565b60176020525f908152604090205481565b348015610dfe575f80fd5b506105f6610e0d366004614959565b61201a565b348015610e1d575f80fd5b506105f6612024565b348015610e31575f80fd5b50600a546104d0906001600160a01b031681565b348015610e50575f80fd5b5061053b610e5f366004614dfe565b612044565b348015610e6f575f80fd5b506105f660105481565b5f6001600160e01b0319821663780e9d6360e01b1480610e9d5750610e9d82612189565b92915050565b60605f8054610eb190614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054610edd90614ef4565b8015610f285780601f10610eff57610100808354040283529160200191610f28565b820191905f5260205f20905b815481529060010190602001808311610f0b57829003601f168201915b5050505050905090565b5f610f3c826121d8565b505f908152600460205260409020546001600160a01b031690565b5f80610f64858585612239565b915091505b935093915050565b5f610f7b82611a4e565b9050806001600160a01b0316836001600160a01b031603610fed5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061100957506110098133610d9b565b61107b5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610fe4565b61108583836122fd565b505050565b335f908152601860205260409020548190036110ac576110aa813361236a565b505b6110b68282610f71565b5050565b5f7fa05d90f300156ad1b545bc5d8197024456f21d22a708f5af04dd293e3d60525186868686866040516110f2959493929190614f2c565b60405180910390a150630a85bd0160e11b95945050505050565b61111633826123dc565b6111325760405162461bcd60e51b8152600401610fe490614f7e565b611085838383612459565b600b545f90600160a01b900460ff16151560010361116e57604051630450a9a360e21b815260040160405180910390fd5b6111766125c8565b5f61117f6126c6565b90506111a173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2333087612824565b6111ac81858561288f565b5f6111b73383612915565b90508382827fb4cd18e02d5df7efacb0a9e243523322a5a1198e3e5c8624729139ba232ab1a988426040516111f6929190918252602082015260400190565b60405180910390a4949350505050565b5f61121083611b39565b82106112725760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610fe4565b506001600160a01b03919091165f908152600660209081526040808320938352929052205490565b5f670de0b6b3a7640000600f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ebebdeaf5f805160206155438339815191526112ed87612987565b6040518363ffffffff1660e01b815260040161130a929190614fcb565b602060405180830381865afa158015611325573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113499190614fe4565b611353919061500f565b610e9d919061503a565b61108583838360405180602001604052805f815250611e44565b6001600160a01b0381165f9081526018602052604081205460609161139b84611b39565b90505f82156113a8575060015b5f6113b3828461504d565b67ffffffffffffffff8111156113cb576113cb614b2a565b6040519080825280602002602001820160405280156113f4578160200160208202803683370190505b5090505f5b838110156114385761140b8782611206565b82828151811061141d5761141d615060565b602090810291909101015261143181615074565b90506113f9565b841561145e578482828151811061145157611451615060565b6020026020010181815250505b5095945050505050565b6114706129ce565b6010819055604080518281524260208201527f6d41ef415406b2fbd2e8e6c2fa40f471038209962c13e3e9280a9bdf3219983c91015b60405180910390a150565b6114b96125c8565b5f828152601660205260409020546114d190826129fb565b60165f8381526020019081526020015f2054827fa30b3c2ccf1776c70e08f1e8f7d7eb571fe975803f15f61c7526e7947d7504ff834260405161151e929190918252602082015260400190565b60405180910390a35050565b611532612b4f565b600b54600a80546001600160a01b0319166001600160a01b03909216919091179055565b5f61156060085490565b82106115c35760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610fe4565b600882815481106115d6576115d6615060565b905f5260205f2001549050919050565b5f8281526016602052604081205481906115ff90612987565b604051632eca54bf60e21b8152600481018290529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bb2952fc90602401602060405180830381865afa158015611667573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061168b9190614fe4565b604051635e0d443f60e01b8152600160048201525f60248201819052604482018390529192506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635e0d443f90606401602060405180830381865afa158015611700573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117249190614fe4565b9050670de0b6b3a7640000611739868361500f565b611743919061503a565b9695505050505050565b6117556129ce565b601161176182826150d1565b507f94bd9a3c5b04dfd2358148322fefc59aee617cb939f7adc02a60d7053a43325481426040516114a692919061518d565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ebebdeaf5f805160206155638339815191526117da85612b7c565b6040518363ffffffff1660e01b81526004016117f7929190614fcb565b602060405180830381865afa158015611812573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e9d9190614fe4565b6001600160a01b0381165f9081526018602052604081205483900361185d57506001610e9d565b816001600160a01b031661187084611a4e565b6001600160a01b03160361188657506001610e9d565b505f92915050565b6118966125c8565b826118a18133611836565b15155f036118c2576040516349e27cff60e01b815260040160405180910390fd5b5f8481526016602090815260408083208054908490553384526018909252909120548590036118ff57335f90815260186020526040812055611908565b61190885612bc3565b60408051858152426020820152829187917f79b2e2d00a00811102e4c45a3a4d9866abcbe9f9471572632098aab13aedb52a910160405180910390a38060175f60155f815461195690615074565b9182905550815260208101919091526040015f2055611976818585612c62565b5050505050565b6119856125c8565b816119908133611836565b15155f036119b1576040516349e27cff60e01b815260040160405180910390fd5b5f838152601660205260409020546119c99083612c9d565b60165f8481526020019081526020015f2054837f54f4c57f40abbe4603bbaf72e5e1d421b094a958865111157f36f674a40cd69a8442604051611a16929190918252602082015260400190565b60405180910390a3505050565b611a4c7f0000000000000000000000000000000000000000000000000000000000000000612e1d565b565b5f818152600260205260408120546001600160a01b031680610e9d5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610fe4565b60118054611aba90614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054611ae690614ef4565b8015611b315780601f10611b0857610100808354040283529160200191611b31565b820191905f5260205f20905b815481529060010190602001808311611b1457829003601f168201915b505050505081565b5f6001600160a01b038216611ba25760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610fe4565b506001600160a01b03165f9081526003602052604090205490565b611bc56129ce565b600a80546001600160a01b0319908116909155600b80549091169055565b611beb6129ce565b600e80546001600160a01b0319166001600160a01b0383169081179091556040514281527fa68fac7ee2725ea373813039d3d466e1dbd7d27dfc4bb8896b39ec530faa78a8906020015b60405180910390a250565b600b545f90600160a01b900460ff161515600103611c7157604051630450a9a360e21b815260040160405180910390fd5b611c796125c8565b5f611c826126c6565b9050611c8d34612f04565b611c9881348561288f565b5f611ca33383612915565b90508382827fb4cd18e02d5df7efacb0a9e243523322a5a1198e3e5c8624729139ba232ab1a93442604051611ce2929190918252602082015260400190565b60405180910390a49392505050565b611cf96129ce565b600b805460ff60a01b1916600160a01b831515908102919091179091556040514281527fb9c62307336e3148a6afd10d350797a6544eb07ddfb98cf05f49a4cd55d8636390602001611c35565b600c8181548110611d55575f80fd5b5f918252602090912001546001600160a01b0316905081565b606060018054610eb190614ef4565b5f80611d876125c8565b610f64858585612f6f565b600d8181548110611da1575f80fd5b5f91825260209091200154905081565b5f670de0b6b3a7640000611dc5838561500f565b611dcf919061503a565b9392505050565b6110b6338383613114565b5f80611dec8361129a565b9050805f03611dfd57505f92915050565b80670de0b6b3a7640000611e1085611793565b611dc5919061500f565b611e226129ce565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b611e4e33836123dc565b611e6a5760405162461bcd60e51b8152600401610fe490614f7e565b611e76848484846131d9565b50505050565b60128054611aba90614ef4565b5f818152600260205260409020546060906001600160a01b031615151515600114611ef65760405162461bcd60e51b815260206004820152601a60248201527f7773744554484d616e616765723a2057524f4e475f544f4b454e0000000000006044820152606401610fe4565b5f60118054611f0490614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3090614ef4565b8015611f7b5780601f10611f5257610100808354040283529160200191611f7b565b820191905f5260205f20905b815481529060010190602001808311611f5e57829003601f168201915b5050505050905080515f03611f9f57505060408051602081019091525f8152919050565b80611fa98461320c565b6012604051602001611fbd939291906151ae565b604051602081830303815290604052915050919050565b611fdc6129ce565b6012611fe882826150d1565b507fbb70b3d53fd084ac14260cfeaefe93b681b468fb94a9d4ff19bed6ab9d6b967981426040516114a692919061518d565b5f610e9d82613314565b335f81815260186020526040812054909161203f919061236a565b905090565b600b54600160a81b900460ff1615155f0361207257604051634ca8886760e01b815260040160405180910390fd5b600b805460ff60a81b1916905583515f036120a057604051633494a40d60e21b815260040160405180910390fd5b3373ba12222222228d8ba445958a75a0704d566bf2c8146120d45760405163f4a8e62160e01b815260040160405180910390fd5b5f835f815181106120e7576120e7615060565b602002602001015190505f835f8151811061210457612104615060565b602002602001015182612117919061504d565b90505f805f805f805f898060200190518101906121349190615249565b9650965096509650965096509650855f03612166576121588785878b878787613612565b505050505050505050611e76565b61217a87612174888c61504d565b8a613827565b50505050505050505050505050565b5f6001600160e01b031982166380ac58cd60e01b14806121b957506001600160e01b03198216635b5e139f60e01b145b80610e9d57506301ffc9a760e01b6001600160e01b0319831614610e9d565b5f818152600260205260409020546001600160a01b03166122365760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610fe4565b50565b5f80670de0b6b3a764000084101561225557505f905080610f69565b5f6122608686611db1565b90505f61226d87836152ae565b90505f61227982613314565b90505f670de0b6b3a764000061228f898961500f565b612299919061503a565b90505f670de0b6b3a76400006122af818b6152ae565b6122b9908561500f565b6122c3919061503a565b9050808210155f600182146122e1576122dc84846152ae565b6122eb565b6122eb83856152ae565b9c919b50909950505050505050505050565b5f81815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061233182611a4e565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b5f825f0361238b57604051630eda9c3d60e31b815260040160405180910390fd5b6001600160a01b0382165f908152601860205260408120556123ad8284613b7d565b60138054905f6123bc83615074565b909155505060148054905f6123d0836152c1565b90915550929392505050565b5f806123e783611a4e565b9050806001600160a01b0316846001600160a01b0316148061242d57506001600160a01b038082165f9081526005602090815260408083209388168352929052205460ff165b806124515750836001600160a01b031661244684610f32565b6001600160a01b0316145b949350505050565b826001600160a01b031661246c82611a4e565b6001600160a01b0316146124925760405162461bcd60e51b8152600401610fe4906152d6565b6001600160a01b0382166124f45760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610fe4565b6125018383836001613d12565b826001600160a01b031661251482611a4e565b6001600160a01b03161461253a5760405162461bcd60e51b8152600401610fe4906152d6565b5f81815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038781168086526003855283862080545f1901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b604051638d62102760e01b81525f8051602061554383398151915260048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638d621027906024015f604051808303815f87803b158015612633575f80fd5b505af1158015612645573d5f803e3d5ffd5b5050604051638d62102760e01b81525f8051602061556383398151915260048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169250638d62102791506024015f604051808303815f87803b1580156126b4575f80fd5b505af1158015611e76573d5f803e3d5ffd5b5f6015545f036127f95760405163fcd83dd760e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063fcd83dd7906024016020604051808303815f875af1158015612735573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127599190614fe4565b905061276481613e3e565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906127c690734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb908590600401614fcb565b5f604051808303815f87803b1580156127dd575f80fd5b505af11580156127ef573d5f803e3d5ffd5b5092949350505050565b601580546017915f91908261280d836152c1565b9190505581526020019081526020015f2054905090565b6040516001600160a01b03808516602483015283166044820152606481018290526119769085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613ef0565b6128a2670de0b6b3a7640000600f61500f565b8111156128c257604051630a4f5a0760e01b815260040160405180910390fd5b5f6128cd8383611db1565b90505f6128da84836152ae565b90506128e582613fbb565b15155f036129065760405163617ab12d60e11b815260040160405180910390fd5b6119768582865f805f8061406a565b6001600160a01b0382165f908152601860205260408120541561294b576040516343d9a50360e11b815260040160405180910390fd5b5f612954614242565b6001600160a01b0385165f9081526018602090815260408083208490558383526016909152902084905591505092915050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166365d578775f805160206155438339815191526117da85614258565b600a546001600160a01b031633036129e257565b604051635a7617f960e11b815260040160405180910390fd5b6040516386b47ce160e01b81525f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906386b47ce190612a58905f80516020615563833981519152908690600401614fcb565b602060405180830381865afa158015612a73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a979190614fe4565b9050612ab25f80516020615563833981519152333084612824565b604051633d00726360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633d00726390612b0f9086905f8051602061556383398151915290879060040161531b565b6020604051808303815f875af1158015612b2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e769190614fe4565b600b546001600160a01b03163303612b6357565b6040516379543eaf60e11b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166386b47ce15f805160206155638339815191526117da856142ba565b5f612bcd82611a4e565b9050612bdc815f846001613d12565b612be582611a4e565b5f83815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080545f190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b5f612c6c846142ba565b90505f612c7885614258565b90505f612c8486612b7c565b9050612c9586825f85878a8a61406a565b505050505050565b6040516365d5787760e01b81525f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906365d5787790612cfa905f80516020615543833981519152908690600401614fcb565b602060405180830381865afa158015612d15573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d399190614fe4565b9050612d45838261431c565b15155f03612d6657604051634e46a02760e11b815260040160405180910390fd5b6040516330b9df9160e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c2e77e4490612dc39086905f8051602061554383398151915290879060040161531b565b6020604051808303815f875af1158015612ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e039190614fe4565b90506110855f805160206155438339815191523383614416565b612e365f80516020615563833981519152825f19614435565b612e6a73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb5f19614435565b612e9773ae7ab96520de3a18e5e111b5eaab095312d7fe845f805160206155438339815191525f19614435565b612ed05f805160206155438339815191527f00000000000000000000000000000000000000000000000000000000000000005f19614435565b61223673ae7ab96520de3a18e5e111b5eaab095312d7fe8473dc24316b9ae028f1497c275eb9192a3ea0f670225f19614435565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f5d575f80fd5b505af1158015612c95573d5f803e3d5ffd5b5f80612f7a85614454565b1515600103612f9c5760405163814ad12f60e01b815260040160405180910390fd5b6040516386b47ce160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906386b47ce190612ff7905f80516020615563833981519152908790600401614fcb565b602060405180830381865afa158015613012573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130369190614fe4565b60405163a6a7c85960e01b81526004810187905260248101869052336044820181905260648201525f8051602061556383398151915260848201525f8051602061554383398151915260a482015260c4810182905260e481018590529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a6a7c85990610104016020604051808303815f875af11580156130e6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061310a9190614fe4565b9050935093915050565b816001600160a01b0316836001600160a01b0316036131755760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610fe4565b6001600160a01b038381165f81815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101611a16565b6131e4848484612459565b6131f08484848461446e565b611e765760405162461bcd60e51b8152600401610fe49061533a565b6060815f036132325750506040805180820190915260018152600360fc1b602082015290565b815f5b811561325b578061324581615074565b91506132549050600a8361503a565b9150613235565b5f8167ffffffffffffffff81111561327557613275614b2a565b6040519080825280601f01601f19166020018201604052801561329f576020820181803683370190505b508593509050815b831561330b576132b8600a8561538c565b6132c390603061504d565b60f81b826132d0836152c1565b925082815181106132e3576132e3615060565b60200101906001600160f81b03191690815f1a905350613304600a8561503a565b93506132a7565b50949350505050565b604051630aae234760e21b81525f8051602061556383398151915260048201525f9081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632ab88d1c90602401602060405180830381865afa158015613387573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ab9190614fe4565b60405163cfdc148f60e01b81525f8051602061556383398151915260048201529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cfdc148f90602401602060405180830381865afa15801561341f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134439190614fe4565b90508082111561345657505f9392505050565b5f8161346286856152ae565b61347490670de0b6b3a764000061500f565b61347e919061503a565b61349090670de0b6b3a76400006152ae565b6040516349622c4960e01b81525f8051602061556383398151915260048201529091505f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906349622c499060240160a060405180830381865afa158015613504573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613528919061539f565b516040516349622c4960e01b81525f8051602061556383398151915260048201529091505f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906349622c499060240160a060405180830381865afa15801561359d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135c1919061539f565b6080015190505f6135d284846152ae565b6135dc908461500f565b905080846135f2670de0b6b3a76400008561500f565b6135fc919061500f565b613606919061503a565b98975050505050505050565b604051633d00726360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633d00726390613676908a9073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2908b9060040161531b565b6020604051808303815f875af1158015613692573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136b69190614fe4565b506040516330b9df9160e21b81525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c2e77e4490613716908b905f80516020615543833981519152908b9060040161531b565b6020604051808303815f875af1158015613732573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137569190614fe4565b604051636f074d1f60e11b8152600481018290529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063de0e9a3e906024016020604051808303815f875af11580156137bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e39190614fe4565b90505f6137f0828761456b565b905083151560010361380f5761380781888761460a565b50505061381e565b61381a81888761466e565b5050505b50505050505050565b613830826146be565b600e5460405163a1903eab60e01b81526001600160a01b0391821660048201525f917f0000000000000000000000000000000000000000000000000000000000000000169063a1903eab90859060240160206040518083038185885af115801561389c573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906138c19190614fe4565b604051630f451f7160e31b8152600481018290529091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637a28fb8890602401602060405180830381865afa158015613929573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061394d9190614fe4565b604051630ea598cb60e41b8152600481018290529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ea598cb0906024016020604051808303815f875af11580156139b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139da9190614fe4565b604051636987b14960e11b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d30f629290613a3a9089905f8051602061554383398151915290869060040161531b565b6020604051808303815f875af1158015613a56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a7a9190614fe4565b5060405163c7c5c4a760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c7c5c4a790613adf90899073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290899060040161531b565b6020604051808303815f875af1158015613afb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1f9190614fe4565b50613b2986614454565b15155f03613b4a57604051636c62feb960e11b815260040160405180910390fd5b612c9573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ba12222222228d8ba445958a75a0704d566bf2c886614416565b6001600160a01b038216613bd35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610fe4565b5f818152600260205260409020546001600160a01b031615613c375760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610fe4565b613c445f83836001613d12565b5f818152600260205260409020546001600160a01b031615613ca85760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610fe4565b6001600160a01b0382165f81815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115613d815760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b6064820152608401610fe4565b816001600160a01b038516613ddc57613dd781600880545f838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b613dff565b836001600160a01b0316856001600160a01b031614613dff57613dff858261472f565b6001600160a01b038416613e1b57613e16816147c8565b611976565b846001600160a01b0316846001600160a01b03161461197657611976848261486f565b604051631ace8bcf60e31b815260048101829052600160248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d6745e78906044015f604051808303815f87803b158015613ea4575f80fd5b505af1158015613eb6573d5f803e3d5ffd5b5050604080518481524260208201527f96e42d3257b3918e5d21803481411046445d8f5ae52841ae17000a2f5cd9919093500190506114a6565b5f805f846001600160a01b031684604051613f0b919061540d565b5f604051808303815f865af19150503d805f8114613f44576040519150601f19603f3d011682016040523d82523d5f602084013e613f49565b606091505b50915091505f81515f1480613f6d575081806020019051810190613f6d9190615428565b9050828015613f795750805b8015613f8e57505f866001600160a01b03163b115b93508315155f03613fb257604051633204506f60e01b815260040160405180910390fd5b50505092915050565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ebebdeaf73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2856040518363ffffffff1660e01b815260040161401f929190614fcb565b602060405180830381865afa15801561403a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061405e9190614fe4565b60105411159392505050565b6040805160208101899052908101869052606081018590526080810184905260a081018390523360c082015281151560e08201525f906101000160408051601f1981840301815290829052600c8054600181810183557fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790910180546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166001600160a01b031990921691909117909155600d805492830181555f8190527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb59092018c9055600b805460ff60a81b1916600160a81b179055632e1c224f60e11b85529294507f000000000000000000000000000000000000000000000000000000000000000090921692635c38449e926141b69230929091908790600401615443565b5f604051808303815f87803b1580156141cd575f80fd5b505af11580156141df573d5f803e3d5ffd5b50505050600c8054806141f4576141f46154e1565b5f8281526020902081015f1990810180546001600160a01b0319169055019055600d805480614225576142256154e1565b600190038181905f5260205f20015f905590555050505050505050565b5f61424b6148b1565b60135461203f919061504d565b60405163951e435d60e01b8152600481018290525f8051602061554383398151915260248201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063951e435d906044016117f7565b604051632a145e2560e01b8152600481018290525f8051602061556383398151915260248201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632a145e25906044016117f7565b5f8061432784611793565b9050805f0361433a576001915050610e9d565b5f670de0b6b3a7640000600f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ebebdeaf5f80516020615543833981519152886040518363ffffffff1660e01b81526004016143a2929190614fcb565b602060405180830381865afa1580156143bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143e19190614fe4565b6143eb919061500f565b6143f5919061503a565b905081816144028761129a565b61440c91906152ae565b1195945050505050565b611e768363a9059cbb60e01b8484604051602401612858929190614fcb565b611e768363095ea7b360e01b8484604051602401612858929190614fcb565b5f61445e82611793565b6144678361129a565b1192915050565b5f6001600160a01b0384163b1561456057604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906144b19033908990889088906004016154f5565b6020604051808303815f875af19250505080156144eb575060408051601f3d908101601f191682019092526144e891810190615527565b60015b614546573d808015614518576040519150601f19603f3d011682016040523d82523d5f602084013e61451d565b606091505b5080515f0361453e5760405162461bcd60e51b8152600401610fe49061533a565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612451565b506001949350505050565b604051630f7c084960e21b8152600160048201525f602482018190526044820184905260648201839052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633df02124906084016020604051808303815f875af11580156145e6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dcf9190614fe4565b61461382612f04565b61463273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23384614416565b6001600160a01b0381166108fc61464984866152ae565b6040518115909202915f818181858888f19350505050158015611e76573d5f803e3d5ffd5b61467783612f04565b61469673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23384614416565b61108573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2826146b985876152ae565b614416565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561471d575f80fd5b505af1158015611976573d5f803e3d5ffd5b5f600161473b84611b39565b61474591906152ae565b5f83815260076020526040902054909150808214614796576001600160a01b0384165f9081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b505f9182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b6008545f906147d9906001906152ae565b5f838152600960205260408120546008805493945090928490811061480057614800615060565b905f5260205f2001549050806008838154811061481f5761481f615060565b5f918252602080832090910192909255828152600990915260408082208490558582528120556008805480614856576148566154e1565b600190038181905f5260205f20015f9055905550505050565b5f61487983611b39565b6001600160a01b039093165f908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b5f60145f81546148c090615074565b9182905550919050565b6001600160e01b031981168114612236575f80fd5b5f602082840312156148ef575f80fd5b8135611dcf816148ca565b5f5b838110156149145781810151838201526020016148fc565b50505f910152565b5f81518084526149338160208601602086016148fa565b601f01601f19169290920160200192915050565b602081525f611dcf602083018461491c565b5f60208284031215614969575f80fd5b5035919050565b5f805f60608486031215614982575f80fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114612236575f80fd5b5f80604083850312156149be575f80fd5b82356149c981614999565b946020939093013593505050565b5f805f805f608086880312156149eb575f80fd5b85356149f681614999565b94506020860135614a0681614999565b935060408601359250606086013567ffffffffffffffff80821115614a29575f80fd5b818801915088601f830112614a3c575f80fd5b813581811115614a4a575f80fd5b896020828501011115614a5b575f80fd5b9699959850939650602001949392505050565b5f805f60608486031215614a80575f80fd5b8335614a8b81614999565b92506020840135614a9b81614999565b929592945050506040919091013590565b5f8060408385031215614abd575f80fd5b50508035926020909101359150565b5f60208284031215614adc575f80fd5b8135611dcf81614999565b602080825282518282018190525f9190848201906040850190845b81811015614b1e57835183529284019291840191600101614b02565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6757614b67614b2a565b604052919050565b5f67ffffffffffffffff831115614b8857614b88614b2a565b614b9b601f8401601f1916602001614b3e565b9050828152838383011115614bae575f80fd5b828260208301375f602084830101529392505050565b5f60208284031215614bd4575f80fd5b813567ffffffffffffffff811115614bea575f80fd5b8201601f81018413614bfa575f80fd5b61245184823560208401614b6f565b5f8060408385031215614c1a575f80fd5b823591506020830135614c2c81614999565b809150509250929050565b8015158114612236575f80fd5b5f805f60608486031215614c56575f80fd5b83359250602084013591506040840135614c6f81614c37565b809150509250925092565b5f60208284031215614c8a575f80fd5b8135611dcf81614c37565b5f8060408385031215614ca6575f80fd5b8235614cb181614999565b91506020830135614c2c81614c37565b5f82601f830112614cd0575f80fd5b611dcf83833560208501614b6f565b5f805f8060808587031215614cf2575f80fd5b8435614cfd81614999565b93506020850135614d0d81614999565b925060408501359150606085013567ffffffffffffffff811115614d2f575f80fd5b614d3b87828801614cc1565b91505092959194509250565b5f8060408385031215614d58575f80fd5b8235614d6381614999565b91506020830135614c2c81614999565b5f67ffffffffffffffff821115614d8c57614d8c614b2a565b5060051b60200190565b5f82601f830112614da5575f80fd5b81356020614dba614db583614d73565b614b3e565b82815260059290921b84018101918181019086841115614dd8575f80fd5b8286015b84811015614df35780358352918301918301614ddc565b509695505050505050565b5f805f8060808587031215614e11575f80fd5b843567ffffffffffffffff80821115614e28575f80fd5b818701915087601f830112614e3b575f80fd5b81356020614e4b614db583614d73565b82815260059290921b8401810191818101908b841115614e69575f80fd5b948201945b83861015614e90578535614e8181614999565b82529482019490820190614e6e565b98505088013592505080821115614ea5575f80fd5b614eb188838901614d96565b94506040870135915080821115614ec6575f80fd5b614ed288838901614d96565b93506060870135915080821115614ee7575f80fd5b50614d3b87828801614cc1565b600181811c90821680614f0857607f821691505b602082108103614f2657634e487b7160e01b5f52602260045260245ffd5b50919050565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290525f828460a08401375f60a0848401015260a0601f19601f85011683010190509695505050505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6001600160a01b03929092168252602082015260400190565b5f60208284031215614ff4575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610e9d57610e9d614ffb565b634e487b7160e01b5f52601260045260245ffd5b5f8261504857615048615026565b500490565b80820180821115610e9d57610e9d614ffb565b634e487b7160e01b5f52603260045260245ffd5b5f6001820161508557615085614ffb565b5060010190565b601f821115611085575f81815260208120601f850160051c810160208610156150b25750805b601f850160051c820191505b81811015612c95578281556001016150be565b815167ffffffffffffffff8111156150eb576150eb614b2a565b6150ff816150f98454614ef4565b8461508c565b602080601f831160018114615132575f841561511b5750858301515b5f19600386901b1c1916600185901b178555612c95565b5f85815260208120601f198616915b8281101561516057888601518255948401946001909101908401615141565b508582101561517d57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b604081525f61519f604083018561491c565b90508260208301529392505050565b5f845160206151c08285838a016148fa565b8551918401916151d38184848a016148fa565b85549201915f906151e381614ef4565b600182811680156151fb576001811461521057615239565b60ff1984168752821515830287019450615239565b895f52855f205f5b8481101561523157815489820152908301908701615218565b505082870194505b50929a9950505050505050505050565b5f805f805f805f60e0888a03121561525f575f80fd5b875196506020880151955060408801519450606088015193506080880151925060a088015161528d81614999565b60c089015190925061529e81614c37565b8091505092959891949750929550565b81810381811115610e9d57610e9d614ffb565b5f816152cf576152cf614ffb565b505f190190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b9283526001600160a01b03919091166020830152604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b5f8261539a5761539a615026565b500690565b5f60a082840312156153af575f80fd5b60405160a0810181811067ffffffffffffffff821117156153d2576153d2614b2a565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b5f825161541e8184602087016148fa565b9190910192915050565b5f60208284031215615438575f80fd5b8151611dcf81614c37565b5f6080820160018060a01b038088168452602060808186015282885480855260a0870191505f9450898552828520855b82811015615491578154861684529284019260019182019101615473565b5050508581036040870152875480825288855282852091830193505b808510156154cc578154845260019485019493830193909101906154ad565b5050508381036060850152613606818661491c565b634e487b7160e01b5f52603160045260245ffd5b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906117439083018461491c565b5f60208284031215615537575f80fd5b8151611dcf816148ca56fe0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000004d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8a264697066735822122021fedbbadaeb7714ea96d32a0064cd9092513e9c24571d6c27a65e612f05d6e964736f6c6343000815003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000084524baa1951247b3a2617a843e6ece915bb96740000000000000000000000000000000000000000000000000d2f13f7789f0000000000000000000000000000000000000000000000000000000000000000001457697365506f7765724661726d2d777374455448000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a5750462d77737445544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e68747470733a2f2f6261636b656e642e6c69717569646e6674732e636f6d0000
Deployed Bytecode
0x608060405260043610610419575f3560e01c806370a0823111610220578063b56453e411610129578063da3ef23f116100b3578063e9f7b59a11610078578063e9f7b59a14610df3578063ec8c890414610e12578063ee97f7f314610e26578063f04f270714610e45578063fae8ccf014610e64575f80fd5b8063da3ef23f14610d22578063da9425e214610d41578063df011c4114610d6c578063e985e9c514610d81578063e9b2e0d714610dc8575f80fd5b8063bf86d690116100f9578063bf86d69014610c9b578063c668286214610cbb578063c71b0e1c14610ccf578063c87b56dd14610ce4578063d3573a3314610d03575f80fd5b8063b56453e414610bf7578063b5ed298a14610c2a578063b88d4fde14610c49578063bc16384614610c68575f80fd5b806395d89b41116101aa578063a1c44ae01161017a578063a1c44ae014610b52578063a22cb46514610b71578063a2309ff814610b90578063a96bb61114610ba5578063ad5c464814610bc4575f80fd5b806395d89b4114610ab85780639751a63f14610acc5780639a8a8c5314610aff5780639cba355914610b33575f80fd5b8063730e695d116101f0578063730e695d146109ff57806376c4b7db14610a325780637c854ec714610a475780638221e78114610a7a57806395d0de6014610a99575f80fd5b806370a082311461099a578063715018a6146109b95780637246bea1146109cd57806372d8a06c146109ec575f80fd5b806342842e0e116103225780635664cb48116102ac5780635ba6b9481161027c5780635ba6b948146109015780635d4f774214610920578063620c1ee9146109345780636352211e146109675780636c0360eb14610986575f80fd5b80635664cb481461087157806358fff2bc146108a45780635a5d096c146108c35780635aa79a4e146108e2575f80fd5b80634cacc937116102f25780634cacc937146107e15780634e71e0c8146108005780634f6ccce71461081457806353528bc01461083357806355f804b314610852575f80fd5b806342842e0e14610744578063438b63001461076357806348ccda3c1461078f5780634b2a12da146107c2575f80fd5b806318160ddd116103a35780632f745c59116103735780632f745c591461066d5780632fc0b9f41461068c578063338346d2146106bf5780633a3c3b87146106f25780633a74e87814610725575f80fd5b806318160ddd146105e657806323b872dd1461060457806327a4986b146106235780632d02bea21461064e575f80fd5b8063095ea7b3116103e9578063095ea7b31461051c5780630f9f234d1461053d57806313b39b9c14610570578063150b7a021461058f57806315a88d22146105c7575f80fd5b806301ffc9a71461045c57806306fdde0314610490578063081812fc146104b15780630861f2fd146104e8575f80fd5b3661045857604080513481523360208201527f49109bdae8e3bbdcbeb7fe5b25b1c75a6bc84fd3f27c6ee0633d41fe197f2aba910160405180910390a1005b5f80fd5b348015610467575f80fd5b5061047b6104763660046148df565b610e79565b60405190151581526020015b60405180910390f35b34801561049b575f80fd5b506104a4610ea3565b6040516104879190614947565b3480156104bc575f80fd5b506104d06104cb366004614959565b610f32565b6040516001600160a01b039091168152602001610487565b3480156104f3575f80fd5b50610507610502366004614970565b610f57565b60408051928352901515602083015201610487565b348015610527575f80fd5b5061053b6105363660046149ad565b610f71565b005b348015610548575f80fd5b506104d07f0000000000000000000000005f8b6c17c3a6ef18b5711f9b562940990658400d81565b34801561057b575f80fd5b5061053b61058a3660046149ad565b61108a565b34801561059a575f80fd5b506105ae6105a93660046149d7565b6110ba565b6040516001600160e01b03199091168152602001610487565b3480156105d2575f80fd5b50600e546104d0906001600160a01b031681565b3480156105f1575f80fd5b506008545b604051908152602001610487565b34801561060f575f80fd5b5061053b61061e366004614a6e565b61110c565b34801561062e575f80fd5b506105f661063d366004614959565b60166020525f908152604090205481565b348015610659575f80fd5b506105f6610668366004614aac565b61113d565b348015610678575f80fd5b506105f66106873660046149ad565b611206565b348015610697575f80fd5b506104d07f0000000000000000000000004d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e881565b3480156106ca575f80fd5b506104d07f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b3480156106fd575f80fd5b506104d07f000000000000000000000000dc24316b9ae028f1497c275eb9192a3ea0f6702281565b348015610730575f80fd5b506105f661073f366004614959565b61129a565b34801561074f575f80fd5b5061053b61075e366004614a6e565b61135d565b34801561076e575f80fd5b5061078261077d366004614acc565b611377565b6040516104879190614ae7565b34801561079a575f80fd5b506104d07f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e281565b3480156107cd575f80fd5b5061053b6107dc366004614959565b611468565b3480156107ec575f80fd5b5061053b6107fb366004614aac565b6114b1565b34801561080b575f80fd5b5061053b61152a565b34801561081f575f80fd5b506105f661082e366004614959565b611556565b34801561083e575f80fd5b506105f661084d366004614aac565b6115e6565b34801561085d575f80fd5b5061053b61086c366004614bc4565b61174d565b34801561087c575f80fd5b506104d07f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b3480156108af575f80fd5b506105f66108be366004614959565b611793565b3480156108ce575f80fd5b5061047b6108dd366004614c09565b611836565b3480156108ed575f80fd5b5061053b6108fc366004614c44565b61188e565b34801561090c575f80fd5b5061053b61091b366004614aac565b61197d565b34801561092b575f80fd5b5061053b611a23565b34801561093f575f80fd5b506104d07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b348015610972575f80fd5b506104d0610981366004614959565b611a4e565b348015610991575f80fd5b506104a4611aad565b3480156109a5575f80fd5b506105f66109b4366004614acc565b611b39565b3480156109c4575f80fd5b5061053b611bbd565b3480156109d8575f80fd5b5061053b6109e7366004614acc565b611be3565b6105f66109fa366004614959565b611c40565b348015610a0a575f80fd5b506104d07f0000000000000000000000004307d8207f2c429f0dcbd9051b5b1d638c3b7fbb81565b348015610a3d575f80fd5b506105f660155481565b348015610a52575f80fd5b506104d07f0000000000000000000000009d6d4e2afab382ae9b52807a4b36a8d2afc78b0781565b348015610a85575f80fd5b5061053b610a94366004614c7a565b611cf1565b348015610aa4575f80fd5b506104d0610ab3366004614959565b611d46565b348015610ac3575f80fd5b506104a4611d6e565b348015610ad7575f80fd5b506104d07f000000000000000000000000d2caa748b66768ac9c53a5443225bdf1365dd4b681565b348015610b0a575f80fd5b50610b1e610b19366004614970565b611d7d565b60408051928352602083019190915201610487565b348015610b3e575f80fd5b506105f6610b4d366004614959565b611d92565b348015610b5d575f80fd5b506105f6610b6c366004614aac565b611db1565b348015610b7c575f80fd5b5061053b610b8b366004614c95565b611dd6565b348015610b9b575f80fd5b506105f660135481565b348015610bb0575f80fd5b506105f6610bbf366004614959565b611de1565b348015610bcf575f80fd5b506104d07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b348015610c02575f80fd5b506104d07f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb967481565b348015610c35575f80fd5b5061053b610c44366004614acc565b611e1a565b348015610c54575f80fd5b5061053b610c63366004614cdf565b611e44565b348015610c73575f80fd5b506104d07f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c881565b348015610ca6575f80fd5b50600b5461047b90600160a01b900460ff1681565b348015610cc6575f80fd5b506104a4611e7c565b348015610cda575f80fd5b506105f660145481565b348015610cef575f80fd5b506104a4610cfe366004614959565b611e89565b348015610d0e575f80fd5b50600b546104d0906001600160a01b031681565b348015610d2d575f80fd5b5061053b610d3c366004614bc4565b611fd4565b348015610d4c575f80fd5b506105f6610d5b366004614acc565b60186020525f908152604090205481565b348015610d77575f80fd5b506105f6600f5481565b348015610d8c575f80fd5b5061047b610d9b366004614d47565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205460ff1690565b348015610dd3575f80fd5b506105f6610de2366004614959565b60176020525f908152604090205481565b348015610dfe575f80fd5b506105f6610e0d366004614959565b61201a565b348015610e1d575f80fd5b506105f6612024565b348015610e31575f80fd5b50600a546104d0906001600160a01b031681565b348015610e50575f80fd5b5061053b610e5f366004614dfe565b612044565b348015610e6f575f80fd5b506105f660105481565b5f6001600160e01b0319821663780e9d6360e01b1480610e9d5750610e9d82612189565b92915050565b60605f8054610eb190614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054610edd90614ef4565b8015610f285780601f10610eff57610100808354040283529160200191610f28565b820191905f5260205f20905b815481529060010190602001808311610f0b57829003601f168201915b5050505050905090565b5f610f3c826121d8565b505f908152600460205260409020546001600160a01b031690565b5f80610f64858585612239565b915091505b935093915050565b5f610f7b82611a4e565b9050806001600160a01b0316836001600160a01b031603610fed5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061100957506110098133610d9b565b61107b5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610fe4565b61108583836122fd565b505050565b335f908152601860205260409020548190036110ac576110aa813361236a565b505b6110b68282610f71565b5050565b5f7fa05d90f300156ad1b545bc5d8197024456f21d22a708f5af04dd293e3d60525186868686866040516110f2959493929190614f2c565b60405180910390a150630a85bd0160e11b95945050505050565b61111633826123dc565b6111325760405162461bcd60e51b8152600401610fe490614f7e565b611085838383612459565b600b545f90600160a01b900460ff16151560010361116e57604051630450a9a360e21b815260040160405180910390fd5b6111766125c8565b5f61117f6126c6565b90506111a173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2333087612824565b6111ac81858561288f565b5f6111b73383612915565b90508382827fb4cd18e02d5df7efacb0a9e243523322a5a1198e3e5c8624729139ba232ab1a988426040516111f6929190918252602082015260400190565b60405180910390a4949350505050565b5f61121083611b39565b82106112725760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610fe4565b506001600160a01b03919091165f908152600660209081526040808320938352929052205490565b5f670de0b6b3a7640000600f547f000000000000000000000000d2caa748b66768ac9c53a5443225bdf1365dd4b66001600160a01b031663ebebdeaf5f805160206155438339815191526112ed87612987565b6040518363ffffffff1660e01b815260040161130a929190614fcb565b602060405180830381865afa158015611325573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113499190614fe4565b611353919061500f565b610e9d919061503a565b61108583838360405180602001604052805f815250611e44565b6001600160a01b0381165f9081526018602052604081205460609161139b84611b39565b90505f82156113a8575060015b5f6113b3828461504d565b67ffffffffffffffff8111156113cb576113cb614b2a565b6040519080825280602002602001820160405280156113f4578160200160208202803683370190505b5090505f5b838110156114385761140b8782611206565b82828151811061141d5761141d615060565b602090810291909101015261143181615074565b90506113f9565b841561145e578482828151811061145157611451615060565b6020026020010181815250505b5095945050505050565b6114706129ce565b6010819055604080518281524260208201527f6d41ef415406b2fbd2e8e6c2fa40f471038209962c13e3e9280a9bdf3219983c91015b60405180910390a150565b6114b96125c8565b5f828152601660205260409020546114d190826129fb565b60165f8381526020019081526020015f2054827fa30b3c2ccf1776c70e08f1e8f7d7eb571fe975803f15f61c7526e7947d7504ff834260405161151e929190918252602082015260400190565b60405180910390a35050565b611532612b4f565b600b54600a80546001600160a01b0319166001600160a01b03909216919091179055565b5f61156060085490565b82106115c35760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610fe4565b600882815481106115d6576115d6615060565b905f5260205f2001549050919050565b5f8281526016602052604081205481906115ff90612987565b604051632eca54bf60e21b8152600481018290529091505f906001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0169063bb2952fc90602401602060405180830381865afa158015611667573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061168b9190614fe4565b604051635e0d443f60e01b8152600160048201525f60248201819052604482018390529192506001600160a01b037f000000000000000000000000dc24316b9ae028f1497c275eb9192a3ea0f670221690635e0d443f90606401602060405180830381865afa158015611700573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117249190614fe4565b9050670de0b6b3a7640000611739868361500f565b611743919061503a565b9695505050505050565b6117556129ce565b601161176182826150d1565b507f94bd9a3c5b04dfd2358148322fefc59aee617cb939f7adc02a60d7053a43325481426040516114a692919061518d565b5f7f000000000000000000000000d2caa748b66768ac9c53a5443225bdf1365dd4b66001600160a01b031663ebebdeaf5f805160206155638339815191526117da85612b7c565b6040518363ffffffff1660e01b81526004016117f7929190614fcb565b602060405180830381865afa158015611812573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e9d9190614fe4565b6001600160a01b0381165f9081526018602052604081205483900361185d57506001610e9d565b816001600160a01b031661187084611a4e565b6001600160a01b03160361188657506001610e9d565b505f92915050565b6118966125c8565b826118a18133611836565b15155f036118c2576040516349e27cff60e01b815260040160405180910390fd5b5f8481526016602090815260408083208054908490553384526018909252909120548590036118ff57335f90815260186020526040812055611908565b61190885612bc3565b60408051858152426020820152829187917f79b2e2d00a00811102e4c45a3a4d9866abcbe9f9471572632098aab13aedb52a910160405180910390a38060175f60155f815461195690615074565b9182905550815260208101919091526040015f2055611976818585612c62565b5050505050565b6119856125c8565b816119908133611836565b15155f036119b1576040516349e27cff60e01b815260040160405180910390fd5b5f838152601660205260409020546119c99083612c9d565b60165f8481526020019081526020015f2054837f54f4c57f40abbe4603bbaf72e5e1d421b094a958865111157f36f674a40cd69a8442604051611a16929190918252602082015260400190565b60405180910390a3505050565b611a4c7f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674612e1d565b565b5f818152600260205260408120546001600160a01b031680610e9d5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610fe4565b60118054611aba90614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054611ae690614ef4565b8015611b315780601f10611b0857610100808354040283529160200191611b31565b820191905f5260205f20905b815481529060010190602001808311611b1457829003601f168201915b505050505081565b5f6001600160a01b038216611ba25760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610fe4565b506001600160a01b03165f9081526003602052604090205490565b611bc56129ce565b600a80546001600160a01b0319908116909155600b80549091169055565b611beb6129ce565b600e80546001600160a01b0319166001600160a01b0383169081179091556040514281527fa68fac7ee2725ea373813039d3d466e1dbd7d27dfc4bb8896b39ec530faa78a8906020015b60405180910390a250565b600b545f90600160a01b900460ff161515600103611c7157604051630450a9a360e21b815260040160405180910390fd5b611c796125c8565b5f611c826126c6565b9050611c8d34612f04565b611c9881348561288f565b5f611ca33383612915565b90508382827fb4cd18e02d5df7efacb0a9e243523322a5a1198e3e5c8624729139ba232ab1a93442604051611ce2929190918252602082015260400190565b60405180910390a49392505050565b611cf96129ce565b600b805460ff60a01b1916600160a01b831515908102919091179091556040514281527fb9c62307336e3148a6afd10d350797a6544eb07ddfb98cf05f49a4cd55d8636390602001611c35565b600c8181548110611d55575f80fd5b5f918252602090912001546001600160a01b0316905081565b606060018054610eb190614ef4565b5f80611d876125c8565b610f64858585612f6f565b600d8181548110611da1575f80fd5b5f91825260209091200154905081565b5f670de0b6b3a7640000611dc5838561500f565b611dcf919061503a565b9392505050565b6110b6338383613114565b5f80611dec8361129a565b9050805f03611dfd57505f92915050565b80670de0b6b3a7640000611e1085611793565b611dc5919061500f565b611e226129ce565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b611e4e33836123dc565b611e6a5760405162461bcd60e51b8152600401610fe490614f7e565b611e76848484846131d9565b50505050565b60128054611aba90614ef4565b5f818152600260205260409020546060906001600160a01b031615151515600114611ef65760405162461bcd60e51b815260206004820152601a60248201527f7773744554484d616e616765723a2057524f4e475f544f4b454e0000000000006044820152606401610fe4565b5f60118054611f0490614ef4565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3090614ef4565b8015611f7b5780601f10611f5257610100808354040283529160200191611f7b565b820191905f5260205f20905b815481529060010190602001808311611f5e57829003601f168201915b5050505050905080515f03611f9f57505060408051602081019091525f8152919050565b80611fa98461320c565b6012604051602001611fbd939291906151ae565b604051602081830303815290604052915050919050565b611fdc6129ce565b6012611fe882826150d1565b507fbb70b3d53fd084ac14260cfeaefe93b681b468fb94a9d4ff19bed6ab9d6b967981426040516114a692919061518d565b5f610e9d82613314565b335f81815260186020526040812054909161203f919061236a565b905090565b600b54600160a81b900460ff1615155f0361207257604051634ca8886760e01b815260040160405180910390fd5b600b805460ff60a81b1916905583515f036120a057604051633494a40d60e21b815260040160405180910390fd5b3373ba12222222228d8ba445958a75a0704d566bf2c8146120d45760405163f4a8e62160e01b815260040160405180910390fd5b5f835f815181106120e7576120e7615060565b602002602001015190505f835f8151811061210457612104615060565b602002602001015182612117919061504d565b90505f805f805f805f898060200190518101906121349190615249565b9650965096509650965096509650855f03612166576121588785878b878787613612565b505050505050505050611e76565b61217a87612174888c61504d565b8a613827565b50505050505050505050505050565b5f6001600160e01b031982166380ac58cd60e01b14806121b957506001600160e01b03198216635b5e139f60e01b145b80610e9d57506301ffc9a760e01b6001600160e01b0319831614610e9d565b5f818152600260205260409020546001600160a01b03166122365760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610fe4565b50565b5f80670de0b6b3a764000084101561225557505f905080610f69565b5f6122608686611db1565b90505f61226d87836152ae565b90505f61227982613314565b90505f670de0b6b3a764000061228f898961500f565b612299919061503a565b90505f670de0b6b3a76400006122af818b6152ae565b6122b9908561500f565b6122c3919061503a565b9050808210155f600182146122e1576122dc84846152ae565b6122eb565b6122eb83856152ae565b9c919b50909950505050505050505050565b5f81815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061233182611a4e565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b5f825f0361238b57604051630eda9c3d60e31b815260040160405180910390fd5b6001600160a01b0382165f908152601860205260408120556123ad8284613b7d565b60138054905f6123bc83615074565b909155505060148054905f6123d0836152c1565b90915550929392505050565b5f806123e783611a4e565b9050806001600160a01b0316846001600160a01b0316148061242d57506001600160a01b038082165f9081526005602090815260408083209388168352929052205460ff165b806124515750836001600160a01b031661244684610f32565b6001600160a01b0316145b949350505050565b826001600160a01b031661246c82611a4e565b6001600160a01b0316146124925760405162461bcd60e51b8152600401610fe4906152d6565b6001600160a01b0382166124f45760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610fe4565b6125018383836001613d12565b826001600160a01b031661251482611a4e565b6001600160a01b03161461253a5760405162461bcd60e51b8152600401610fe4906152d6565b5f81815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038781168086526003855283862080545f1901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b604051638d62102760e01b81525f8051602061554383398151915260048201527f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b031690638d621027906024015f604051808303815f87803b158015612633575f80fd5b505af1158015612645573d5f803e3d5ffd5b5050604051638d62102760e01b81525f8051602061556383398151915260048201527f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03169250638d62102791506024015f604051808303815f87803b1580156126b4575f80fd5b505af1158015611e76573d5f803e3d5ffd5b5f6015545f036127f95760405163fcd83dd760e01b81523060048201525f907f0000000000000000000000009d6d4e2afab382ae9b52807a4b36a8d2afc78b076001600160a01b03169063fcd83dd7906024016020604051808303815f875af1158015612735573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127599190614fe4565b905061276481613e3e565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000009d6d4e2afab382ae9b52807a4b36a8d2afc78b07169063095ea7b3906127c690734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb908590600401614fcb565b5f604051808303815f87803b1580156127dd575f80fd5b505af11580156127ef573d5f803e3d5ffd5b5092949350505050565b601580546017915f91908261280d836152c1565b9190505581526020019081526020015f2054905090565b6040516001600160a01b03808516602483015283166044820152606481018290526119769085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613ef0565b6128a2670de0b6b3a7640000600f61500f565b8111156128c257604051630a4f5a0760e01b815260040160405180910390fd5b5f6128cd8383611db1565b90505f6128da84836152ae565b90506128e582613fbb565b15155f036129065760405163617ab12d60e11b815260040160405180910390fd5b6119768582865f805f8061406a565b6001600160a01b0382165f908152601860205260408120541561294b576040516343d9a50360e11b815260040160405180910390fd5b5f612954614242565b6001600160a01b0385165f9081526018602090815260408083208490558383526016909152902084905591505092915050565b5f7f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03166365d578775f805160206155438339815191526117da85614258565b600a546001600160a01b031633036129e257565b604051635a7617f960e11b815260040160405180910390fd5b6040516386b47ce160e01b81525f906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb967416906386b47ce190612a58905f80516020615563833981519152908690600401614fcb565b602060405180830381865afa158015612a73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a979190614fe4565b9050612ab25f80516020615563833981519152333084612824565b604051633d00726360e01b81526001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96741690633d00726390612b0f9086905f8051602061556383398151915290879060040161531b565b6020604051808303815f875af1158015612b2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e769190614fe4565b600b546001600160a01b03163303612b6357565b6040516379543eaf60e11b815260040160405180910390fd5b5f7f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03166386b47ce15f805160206155638339815191526117da856142ba565b5f612bcd82611a4e565b9050612bdc815f846001613d12565b612be582611a4e565b5f83815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080545f190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b5f612c6c846142ba565b90505f612c7885614258565b90505f612c8486612b7c565b9050612c9586825f85878a8a61406a565b505050505050565b6040516365d5787760e01b81525f906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb967416906365d5787790612cfa905f80516020615543833981519152908690600401614fcb565b602060405180830381865afa158015612d15573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d399190614fe4565b9050612d45838261431c565b15155f03612d6657604051634e46a02760e11b815260040160405180910390fd5b6040516330b9df9160e21b81526001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674169063c2e77e4490612dc39086905f8051602061554383398151915290879060040161531b565b6020604051808303815f875af1158015612ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e039190614fe4565b90506110855f805160206155438339815191523383614416565b612e365f80516020615563833981519152825f19614435565b612e6a73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2734307d8207f2c429f0dcbd9051b5b1d638c3b7fbb5f19614435565b612e9773ae7ab96520de3a18e5e111b5eaab095312d7fe845f805160206155438339815191525f19614435565b612ed05f805160206155438339815191527f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96745f19614435565b61223673ae7ab96520de3a18e5e111b5eaab095312d7fe8473dc24316b9ae028f1497c275eb9192a3ea0f670225f19614435565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f5d575f80fd5b505af1158015612c95573d5f803e3d5ffd5b5f80612f7a85614454565b1515600103612f9c5760405163814ad12f60e01b815260040160405180910390fd5b6040516386b47ce160e01b81526001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb967416906386b47ce190612ff7905f80516020615563833981519152908790600401614fcb565b602060405180830381865afa158015613012573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130369190614fe4565b60405163a6a7c85960e01b81526004810187905260248101869052336044820181905260648201525f8051602061556383398151915260848201525f8051602061554383398151915260a482015260c4810182905260e481018590529092507f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03169063a6a7c85990610104016020604051808303815f875af11580156130e6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061310a9190614fe4565b9050935093915050565b816001600160a01b0316836001600160a01b0316036131755760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610fe4565b6001600160a01b038381165f81815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101611a16565b6131e4848484612459565b6131f08484848461446e565b611e765760405162461bcd60e51b8152600401610fe49061533a565b6060815f036132325750506040805180820190915260018152600360fc1b602082015290565b815f5b811561325b578061324581615074565b91506132549050600a8361503a565b9150613235565b5f8167ffffffffffffffff81111561327557613275614b2a565b6040519080825280601f01601f19166020018201604052801561329f576020820181803683370190505b508593509050815b831561330b576132b8600a8561538c565b6132c390603061504d565b60f81b826132d0836152c1565b925082815181106132e3576132e3615060565b60200101906001600160f81b03191690815f1a905350613304600a8561503a565b93506132a7565b50949350505050565b604051630aae234760e21b81525f8051602061556383398151915260048201525f9081906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96741690632ab88d1c90602401602060405180830381865afa158015613387573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ab9190614fe4565b60405163cfdc148f60e01b81525f8051602061556383398151915260048201529091505f906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674169063cfdc148f90602401602060405180830381865afa15801561341f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134439190614fe4565b90508082111561345657505f9392505050565b5f8161346286856152ae565b61347490670de0b6b3a764000061500f565b61347e919061503a565b61349090670de0b6b3a76400006152ae565b6040516349622c4960e01b81525f8051602061556383398151915260048201529091505f906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb967416906349622c499060240160a060405180830381865afa158015613504573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613528919061539f565b516040516349622c4960e01b81525f8051602061556383398151915260048201529091505f907f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b0316906349622c499060240160a060405180830381865afa15801561359d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135c1919061539f565b6080015190505f6135d284846152ae565b6135dc908461500f565b905080846135f2670de0b6b3a76400008561500f565b6135fc919061500f565b613606919061503a565b98975050505050505050565b604051633d00726360e01b81526001600160a01b037f0000000000000000000000004307d8207f2c429f0dcbd9051b5b1d638c3b7fbb1690633d00726390613676908a9073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2908b9060040161531b565b6020604051808303815f875af1158015613692573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136b69190614fe4565b506040516330b9df9160e21b81525f906001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674169063c2e77e4490613716908b905f80516020615543833981519152908b9060040161531b565b6020604051808303815f875af1158015613732573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137569190614fe4565b604051636f074d1f60e11b8152600481018290529091505f906001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0169063de0e9a3e906024016020604051808303815f875af11580156137bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e39190614fe4565b90505f6137f0828761456b565b905083151560010361380f5761380781888761460a565b50505061381e565b61381a81888761466e565b5050505b50505050505050565b613830826146be565b600e5460405163a1903eab60e01b81526001600160a01b0391821660048201525f917f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84169063a1903eab90859060240160206040518083038185885af115801561389c573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906138c19190614fe4565b604051630f451f7160e31b8152600481018290529091505f906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe841690637a28fb8890602401602060405180830381865afa158015613929573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061394d9190614fe4565b604051630ea598cb60e41b8152600481018290529091505f906001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0169063ea598cb0906024016020604051808303815f875af11580156139b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139da9190614fe4565b604051636987b14960e11b81529091506001600160a01b037f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674169063d30f629290613a3a9089905f8051602061554383398151915290869060040161531b565b6020604051808303815f875af1158015613a56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a7a9190614fe4565b5060405163c7c5c4a760e01b81526001600160a01b037f0000000000000000000000004307d8207f2c429f0dcbd9051b5b1d638c3b7fbb169063c7c5c4a790613adf90899073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290899060040161531b565b6020604051808303815f875af1158015613afb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1f9190614fe4565b50613b2986614454565b15155f03613b4a57604051636c62feb960e11b815260040160405180910390fd5b612c9573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ba12222222228d8ba445958a75a0704d566bf2c886614416565b6001600160a01b038216613bd35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610fe4565b5f818152600260205260409020546001600160a01b031615613c375760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610fe4565b613c445f83836001613d12565b5f818152600260205260409020546001600160a01b031615613ca85760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610fe4565b6001600160a01b0382165f81815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115613d815760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b6064820152608401610fe4565b816001600160a01b038516613ddc57613dd781600880545f838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b613dff565b836001600160a01b0316856001600160a01b031614613dff57613dff858261472f565b6001600160a01b038416613e1b57613e16816147c8565b611976565b846001600160a01b0316846001600160a01b03161461197657611976848261486f565b604051631ace8bcf60e31b815260048101829052600160248201527f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03169063d6745e78906044015f604051808303815f87803b158015613ea4575f80fd5b505af1158015613eb6573d5f803e3d5ffd5b5050604080518481524260208201527f96e42d3257b3918e5d21803481411046445d8f5ae52841ae17000a2f5cd9919093500190506114a6565b5f805f846001600160a01b031684604051613f0b919061540d565b5f604051808303815f865af19150503d805f8114613f44576040519150601f19603f3d011682016040523d82523d5f602084013e613f49565b606091505b50915091505f81515f1480613f6d575081806020019051810190613f6d9190615428565b9050828015613f795750805b8015613f8e57505f866001600160a01b03163b115b93508315155f03613fb257604051633204506f60e01b815260040160405180910390fd5b50505092915050565b5f807f000000000000000000000000d2caa748b66768ac9c53a5443225bdf1365dd4b66001600160a01b031663ebebdeaf73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2856040518363ffffffff1660e01b815260040161401f929190614fcb565b602060405180830381865afa15801561403a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061405e9190614fe4565b60105411159392505050565b6040805160208101899052908101869052606081018590526080810184905260a081018390523360c082015281151560e08201525f906101000160408051601f1981840301815290829052600c8054600181810183557fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790910180546001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281166001600160a01b031990921691909117909155600d805492830181555f8190527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb59092018c9055600b805460ff60a81b1916600160a81b179055632e1c224f60e11b85529294507f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c890921692635c38449e926141b69230929091908790600401615443565b5f604051808303815f87803b1580156141cd575f80fd5b505af11580156141df573d5f803e3d5ffd5b50505050600c8054806141f4576141f46154e1565b5f8281526020902081015f1990810180546001600160a01b0319169055019055600d805480614225576142256154e1565b600190038181905f5260205f20015f905590555050505050505050565b5f61424b6148b1565b60135461203f919061504d565b60405163951e435d60e01b8152600481018290525f8051602061554383398151915260248201525f907f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b03169063951e435d906044016117f7565b604051632a145e2560e01b8152600481018290525f8051602061556383398151915260248201525f907f00000000000000000000000084524baa1951247b3a2617a843e6ece915bb96746001600160a01b031690632a145e25906044016117f7565b5f8061432784611793565b9050805f0361433a576001915050610e9d565b5f670de0b6b3a7640000600f547f000000000000000000000000d2caa748b66768ac9c53a5443225bdf1365dd4b66001600160a01b031663ebebdeaf5f80516020615543833981519152886040518363ffffffff1660e01b81526004016143a2929190614fcb565b602060405180830381865afa1580156143bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143e19190614fe4565b6143eb919061500f565b6143f5919061503a565b905081816144028761129a565b61440c91906152ae565b1195945050505050565b611e768363a9059cbb60e01b8484604051602401612858929190614fcb565b611e768363095ea7b360e01b8484604051602401612858929190614fcb565b5f61445e82611793565b6144678361129a565b1192915050565b5f6001600160a01b0384163b1561456057604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906144b19033908990889088906004016154f5565b6020604051808303815f875af19250505080156144eb575060408051601f3d908101601f191682019092526144e891810190615527565b60015b614546573d808015614518576040519150601f19603f3d011682016040523d82523d5f602084013e61451d565b606091505b5080515f0361453e5760405162461bcd60e51b8152600401610fe49061533a565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612451565b506001949350505050565b604051630f7c084960e21b8152600160048201525f602482018190526044820184905260648201839052907f000000000000000000000000dc24316b9ae028f1497c275eb9192a3ea0f670226001600160a01b031690633df02124906084016020604051808303815f875af11580156145e6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dcf9190614fe4565b61461382612f04565b61463273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23384614416565b6001600160a01b0381166108fc61464984866152ae565b6040518115909202915f818181858888f19350505050158015611e76573d5f803e3d5ffd5b61467783612f04565b61469673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23384614416565b61108573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2826146b985876152ae565b614416565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561471d575f80fd5b505af1158015611976573d5f803e3d5ffd5b5f600161473b84611b39565b61474591906152ae565b5f83815260076020526040902054909150808214614796576001600160a01b0384165f9081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b505f9182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b6008545f906147d9906001906152ae565b5f838152600960205260408120546008805493945090928490811061480057614800615060565b905f5260205f2001549050806008838154811061481f5761481f615060565b5f918252602080832090910192909255828152600990915260408082208490558582528120556008805480614856576148566154e1565b600190038181905f5260205f20015f9055905550505050565b5f61487983611b39565b6001600160a01b039093165f908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b5f60145f81546148c090615074565b9182905550919050565b6001600160e01b031981168114612236575f80fd5b5f602082840312156148ef575f80fd5b8135611dcf816148ca565b5f5b838110156149145781810151838201526020016148fc565b50505f910152565b5f81518084526149338160208601602086016148fa565b601f01601f19169290920160200192915050565b602081525f611dcf602083018461491c565b5f60208284031215614969575f80fd5b5035919050565b5f805f60608486031215614982575f80fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114612236575f80fd5b5f80604083850312156149be575f80fd5b82356149c981614999565b946020939093013593505050565b5f805f805f608086880312156149eb575f80fd5b85356149f681614999565b94506020860135614a0681614999565b935060408601359250606086013567ffffffffffffffff80821115614a29575f80fd5b818801915088601f830112614a3c575f80fd5b813581811115614a4a575f80fd5b896020828501011115614a5b575f80fd5b9699959850939650602001949392505050565b5f805f60608486031215614a80575f80fd5b8335614a8b81614999565b92506020840135614a9b81614999565b929592945050506040919091013590565b5f8060408385031215614abd575f80fd5b50508035926020909101359150565b5f60208284031215614adc575f80fd5b8135611dcf81614999565b602080825282518282018190525f9190848201906040850190845b81811015614b1e57835183529284019291840191600101614b02565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6757614b67614b2a565b604052919050565b5f67ffffffffffffffff831115614b8857614b88614b2a565b614b9b601f8401601f1916602001614b3e565b9050828152838383011115614bae575f80fd5b828260208301375f602084830101529392505050565b5f60208284031215614bd4575f80fd5b813567ffffffffffffffff811115614bea575f80fd5b8201601f81018413614bfa575f80fd5b61245184823560208401614b6f565b5f8060408385031215614c1a575f80fd5b823591506020830135614c2c81614999565b809150509250929050565b8015158114612236575f80fd5b5f805f60608486031215614c56575f80fd5b83359250602084013591506040840135614c6f81614c37565b809150509250925092565b5f60208284031215614c8a575f80fd5b8135611dcf81614c37565b5f8060408385031215614ca6575f80fd5b8235614cb181614999565b91506020830135614c2c81614c37565b5f82601f830112614cd0575f80fd5b611dcf83833560208501614b6f565b5f805f8060808587031215614cf2575f80fd5b8435614cfd81614999565b93506020850135614d0d81614999565b925060408501359150606085013567ffffffffffffffff811115614d2f575f80fd5b614d3b87828801614cc1565b91505092959194509250565b5f8060408385031215614d58575f80fd5b8235614d6381614999565b91506020830135614c2c81614999565b5f67ffffffffffffffff821115614d8c57614d8c614b2a565b5060051b60200190565b5f82601f830112614da5575f80fd5b81356020614dba614db583614d73565b614b3e565b82815260059290921b84018101918181019086841115614dd8575f80fd5b8286015b84811015614df35780358352918301918301614ddc565b509695505050505050565b5f805f8060808587031215614e11575f80fd5b843567ffffffffffffffff80821115614e28575f80fd5b818701915087601f830112614e3b575f80fd5b81356020614e4b614db583614d73565b82815260059290921b8401810191818101908b841115614e69575f80fd5b948201945b83861015614e90578535614e8181614999565b82529482019490820190614e6e565b98505088013592505080821115614ea5575f80fd5b614eb188838901614d96565b94506040870135915080821115614ec6575f80fd5b614ed288838901614d96565b93506060870135915080821115614ee7575f80fd5b50614d3b87828801614cc1565b600181811c90821680614f0857607f821691505b602082108103614f2657634e487b7160e01b5f52602260045260245ffd5b50919050565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290525f828460a08401375f60a0848401015260a0601f19601f85011683010190509695505050505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6001600160a01b03929092168252602082015260400190565b5f60208284031215614ff4575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610e9d57610e9d614ffb565b634e487b7160e01b5f52601260045260245ffd5b5f8261504857615048615026565b500490565b80820180821115610e9d57610e9d614ffb565b634e487b7160e01b5f52603260045260245ffd5b5f6001820161508557615085614ffb565b5060010190565b601f821115611085575f81815260208120601f850160051c810160208610156150b25750805b601f850160051c820191505b81811015612c95578281556001016150be565b815167ffffffffffffffff8111156150eb576150eb614b2a565b6150ff816150f98454614ef4565b8461508c565b602080601f831160018114615132575f841561511b5750858301515b5f19600386901b1c1916600185901b178555612c95565b5f85815260208120601f198616915b8281101561516057888601518255948401946001909101908401615141565b508582101561517d57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b604081525f61519f604083018561491c565b90508260208301529392505050565b5f845160206151c08285838a016148fa565b8551918401916151d38184848a016148fa565b85549201915f906151e381614ef4565b600182811680156151fb576001811461521057615239565b60ff1984168752821515830287019450615239565b895f52855f205f5b8481101561523157815489820152908301908701615218565b505082870194505b50929a9950505050505050505050565b5f805f805f805f60e0888a03121561525f575f80fd5b875196506020880151955060408801519450606088015193506080880151925060a088015161528d81614999565b60c089015190925061529e81614c37565b8091505092959891949750929550565b81810381811115610e9d57610e9d614ffb565b5f816152cf576152cf614ffb565b505f190190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b9283526001600160a01b03919091166020830152604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b5f8261539a5761539a615026565b500690565b5f60a082840312156153af575f80fd5b60405160a0810181811067ffffffffffffffff821117156153d2576153d2614b2a565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b5f825161541e8184602087016148fa565b9190910192915050565b5f60208284031215615438575f80fd5b8151611dcf81614c37565b5f6080820160018060a01b038088168452602060808186015282885480855260a0870191505f9450898552828520855b82811015615491578154861684529284019260019182019101615473565b5050508581036040870152875480825288855282852091830193505b808510156154cc578154845260019485019493830193909101906154ad565b5050508381036060850152613606818661491c565b634e487b7160e01b5f52603160045260245ffd5b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906117439083018461491c565b5f60208284031215615537575f80fd5b8151611dcf816148ca56fe0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000004d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8a264697066735822122021fedbbadaeb7714ea96d32a0064cd9092513e9c24571d6c27a65e612f05d6e964736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000084524baa1951247b3a2617a843e6ece915bb96740000000000000000000000000000000000000000000000000d2f13f7789f0000000000000000000000000000000000000000000000000000000000000000001457697365506f7765724661726d2d777374455448000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a5750462d77737445544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e68747470733a2f2f6261636b656e642e6c69717569646e6674732e636f6d0000
-----Decoded View---------------
Arg [0] : _name (string): WisePowerFarm-wstETH
Arg [1] : _symbol (string): WPF-wstETH
Arg [2] : _initBaseURI (string): https://backend.liquidnfts.com
Arg [3] : _wiseLendingAddress (address): 0x84524bAa1951247b3A2617A843e6eCe915Bb9674
Arg [4] : _collateralFactor (uint256): 950000000000000000
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [3] : 00000000000000000000000084524baa1951247b3a2617a843e6ece915bb9674
Arg [4] : 0000000000000000000000000000000000000000000000000d2f13f7789f0000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [6] : 57697365506f7765724661726d2d777374455448000000000000000000000000
Arg [7] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [8] : 5750462d77737445544800000000000000000000000000000000000000000000
Arg [9] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [10] : 68747470733a2f2f6261636b656e642e6c69717569646e6674732e636f6d0000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.