Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
AirPuffVaultEPM
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import "./abstracts/AirPuffVaultEP.sol"; contract AirPuffVaultEPM is AirPuffVaultEP { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address _WETH) external initializer { strategyAddresses.WETH = _WETH; strategyAddresses.borrowAsset = _WETH; MAX_BPS = 100_000; DENOMINATOR = 1_000; DECIMAL = 1e18; __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); __ERC20_init("AirPuff-EigenPiemswETH", "bmswETH"); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../interfaces/ILending.sol"; import "../interfaces/IVaultM.sol"; interface IWETH { function deposit() external payable; function withdraw(uint256) external; function decimals() external view returns (uint8); } interface IAirPuffHandler { function handlerSwap(bool isSimple, uint256 _amount,address _assetFrom,address _assetTo, bool _isClose, bool _isBalancer) external returns (uint256); function getPositionWithInterestRate(address _user, uint256 _positionID, address _AirPuffVault) external view returns (uint256,uint256); function keeper() external view returns (address); function vaultCurrentSnapshotID(address _vault) external view returns (uint256); function getLatestData(address _token) external view returns (uint256); } interface IEigenDepositHelper { //amount, claimed function getUserCycleInfo(uint256 _cycle,address _user,address _asset) external view returns (uint256, uint256); function currentCycle() external view returns (uint256); function userClaim(uint256[] calldata _cycles, address[] calldata _assets) external; } interface IEigenPieDeposit { function depositAsset(address asset,uint256 depositAmount,uint256 minRec,address referral) external; } interface IswETH { function deposit() external payable; function swETHToETHRate() external view returns (uint256); } interface ISWExit { function createWithdrawRequest(uint256 amount) external; function getLastTokenIdCreated() external view returns (uint256); function setApprovalForAll(address operator, bool approved) external; function finalizeWithdrawal(uint256 tokenId) external; function getLastTokenIdProcessed() external view returns (uint256); function getProcessedRateForTokenId(uint256 tokenId) external view returns (bool isProcessed, uint256 processedRate); function claimableCycles(uint256 _cycleID) external view returns (bool); } abstract contract AirPuffVaultEP is IVault, OwnableUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable, ERC20BurnableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; using MathUpgradeable for uint256; FeeConfiguration public feeConfiguration; StrategyAddresses public strategyAddresses; LeverageBounds public leverageBounds; SwapData private swapData; address public LendingVault; uint256 public DTVLimit; bool public isSwapSimple; bool public isBalancer; bool public isUnstakeEnabled; bool public withdrawEnabled; uint256[] public allCycles; address[] private allUsers; uint256 internal MAX_BPS; uint256 internal DENOMINATOR; uint256 internal DECIMAL; mapping(address => UserInfo[]) public userInfo; mapping(address => bool) public isUser; mapping(address => mapping(uint256 => PositionTimestamps)) public positionTimestamps; mapping(address => mapping(uint256 => uint256)) public positionCycle; mapping(address => mapping(uint256 => CloseRequestData)) public closeRequests; mapping(address => uint256[]) public userCloseRequestsCount; mapping(uint256 => bool) public isCycle; uint256[50] private __gaps; mapping(address => mapping(uint256 => bool)) public closePending; mapping(address => mapping(uint256 => uint256)) public closeWETHAmount; mapping(address => bool) public onlyAllowedClosers; modifier InvalidID(uint256 positionId, address user) { require(positionId < userInfo[user].length, "AirPuff: positionID is not valid"); _; } /** --------------------- Event --------------------- */ event Deposit(address indexed user,uint256 amount, uint256 tokenAmount, uint256 time, uint256 positionID, uint256 leverage); event Withdraw(address indexed user, uint256 positionID, uint256 amount, uint256 leverage, uint256 repayAmount, uint256 time, uint256 userTokensBurned); event ProtocolFeeChanged( address newFeeReceiver, uint256 newWithdrawalFee, address newLendingFeeReceiver, uint256 liquidatorFeeChanged ); event Liquidated( address indexed user, uint256 indexed positionId, address liquidator, uint256 time, uint256 lendingRepayAmount, uint256 position ); event SetLendingVault(address vault); event SetStrategyAddresses(address AirPuffHandler, address _mswETH, address _eigenPie, address _swETH, address _EigenPreDepositHelper, address _swExit); event SetDTVLimit(uint256 DTVLimit); event LeverageBoundsSet(uint256 minLeverage, uint256 maxLeverage, uint256 minDeposit); event SetIsSwapSimple(bool isSimple); event SetIsBalancer(bool isBalancer); event UnstakeEnabled(bool isUnstakeEnabled); event SetWithdrawEnabled(bool _withdrawEnabled); event SetAllowedClosers(address _closer, bool _allowed); event PositionCloseFulfilled(address _user, uint256 _closeRequestID, uint256 _lendingRepayAmount, bool isLiquidation); /** ----------- Change onlyOwner functions ------------- */ function setAllowedClosers(address _closer, bool _allowed) external onlyOwner { onlyAllowedClosers[_closer] = _allowed; emit SetAllowedClosers(_closer, _allowed); } function setUnstakeEnabled(bool _isUnstakeEnabled) external onlyOwner { isUnstakeEnabled = _isUnstakeEnabled; emit UnstakeEnabled(_isUnstakeEnabled); } function setIsSwapSimple(bool _isSimple) external onlyOwner { isSwapSimple = _isSimple; emit SetIsSwapSimple(_isSimple); } function setIsBalancer(bool _isBalancer) external onlyOwner { isBalancer = _isBalancer; emit SetIsBalancer(_isBalancer); } function setStrategyAddresses( address _AirPuffHandler, address _mswETH, address _EigenPie, address _swETH, address _EigenPreDepositHelper, address _swExit ) external onlyOwner { strategyAddresses.AirPuffHandler = _AirPuffHandler; strategyAddresses.mswETH = _mswETH; strategyAddresses.EigenPie = _EigenPie; strategyAddresses.swETH = _swETH; strategyAddresses.EigenPreDepositHelper = _EigenPreDepositHelper; strategyAddresses.swExit = _swExit; ISWExit(_swExit).setApprovalForAll(_swExit, true); emit SetStrategyAddresses(_AirPuffHandler, _mswETH, _EigenPie, _swETH, _EigenPreDepositHelper, _swExit); } function setLendingVault(address _vault) public onlyOwner { LendingVault = _vault; emit SetLendingVault(_vault); } function setDTVLimit(uint256 _DTVLimit) public onlyOwner { DTVLimit = _DTVLimit; emit SetDTVLimit(_DTVLimit); } function setMinMaxLeverageBounds(uint256 _minLeverage, uint256 _maxLeverage, uint256 _minDeposit) public onlyOwner { require(_minLeverage >= 1000 && _maxLeverage <= 15000, "AirPuff: incorrect leverage bounds"); require(_minLeverage < _maxLeverage, "AirPuff: minLeverage is greater than maxLeverage"); leverageBounds.minLeverage = _minLeverage; leverageBounds.maxLeverage = _maxLeverage; leverageBounds.minDeposit = _minDeposit; emit LeverageBoundsSet(_minLeverage, _maxLeverage, _minDeposit); } function setProtocolFee( address _feeReceiver, uint256 _withdrawalFee, address _lendingFeeReceiver, uint256 _mFeePercent, address _mFeeReceiver, uint256 _liquidatorFee ) external onlyOwner { require(_withdrawalFee <= MAX_BPS, "Invalid fees"); require(_mFeePercent <= 90000, "Invalid mFeePercent"); feeConfiguration.feeReceiver = _feeReceiver; feeConfiguration.withdrawalFee = _withdrawalFee; feeConfiguration.lendingFeeReceiver = _lendingFeeReceiver; feeConfiguration.mFeeReceiver = _mFeeReceiver; feeConfiguration.mFeePercent = _mFeePercent; feeConfiguration.liquidatorFee = _liquidatorFee; emit ProtocolFeeChanged( _feeReceiver, _withdrawalFee, _lendingFeeReceiver, _liquidatorFee ); } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } /** ----------- View functions ------------- */ function getAllUsers() public view returns (address[] memory) { return allUsers; } function getTotalNumbersOfOpenPositionBy(address _user) public view returns (uint256) { return userInfo[_user].length; } function getUpdatedDebt( uint256 _positionID, address _user ) public view returns (uint256, uint256, uint256, uint256) { UserInfo memory _userInfo = userInfo[_user][_positionID]; if (_userInfo.closed || _userInfo.liquidated) return (0, 0, 0, 0); //in WETH (uint256 leverageWithInterests,uint256 totalInterests) = IAirPuffHandler(strategyAddresses.AirPuffHandler).getPositionWithInterestRate( _user, _positionID, address(this)); //In ETH (that asset returns e18 decimals but the handler already converts it to e10 so we need to re-divide it by 1e10 to get the correct value) uint256 mswETHPrice = IAirPuffHandler(strategyAddresses.AirPuffHandler).getLatestData(strategyAddresses.swETH); //in ETH uint256 currentPositionValue = _userInfo.position.mulDiv(mswETHPrice, DECIMAL); uint256 currentDTV = leverageWithInterests.mulDiv(DECIMAL, currentPositionValue); return ( currentDTV, currentPositionValue, leverageWithInterests, totalInterests); } function getAllEigeinPieCycleDepositAmounts() public view returns (uint256) { uint256 currentCycle = IEigenDepositHelper(strategyAddresses.EigenPreDepositHelper).currentCycle(); uint256 totalDeposited; for (uint256 i = 0; i <= currentCycle; i++) { (uint256 bal,) = IEigenDepositHelper(strategyAddresses.EigenPreDepositHelper).getUserCycleInfo(i, address(this), strategyAddresses.swETH); totalDeposited += bal; } return totalDeposited; } /** ----------- User functions ------------- */ function openPosition(uint256 _leverage) external payable nonReentrant { require(onlyAllowedClosers[msg.sender], "AirPuff: only allowed closers"); require(_leverage >= leverageBounds.minLeverage && _leverage <= leverageBounds.maxLeverage, "AirPuff: leverage is out of bounds"); require(msg.value >= leverageBounds.minDeposit, "AirPuff: deposit is less than minimum"); uint256 amount = msg.value; uint256 leveragedAmount = (amount.mulDiv(_leverage, DENOMINATOR) - amount); require(leveragedAmount > 0, "AirPuff: leveragedAmount is 0"); bool success = ILending(LendingVault).lend(leveragedAmount,address(this)); require(success, "AirPuff: lending failed"); IWETH(strategyAddresses.WETH).withdraw(leveragedAmount); uint256 staked = _depositAndStake(amount + leveragedAmount); require(staked > 0, "AirPuff: staked is 0"); uint256 posID = userInfo[msg.sender].length; UserInfo memory _userInfo = UserInfo({ user: msg.sender, deposit: amount, leverage: _leverage, position: staked, liquidated: false, liquidator: address(0), leverageAmount: leveragedAmount, positionId: posID, closed: false }); PositionTimestamps storage pts = positionTimestamps[msg.sender][posID]; positionCycle[msg.sender][posID] = IEigenDepositHelper(strategyAddresses.EigenPreDepositHelper).currentCycle(); pts.openTimestamp = block.timestamp; pts.vaultSnapshotID = IAirPuffHandler(strategyAddresses.AirPuffHandler).vaultCurrentSnapshotID(LendingVault); if (!isCycle[positionCycle[msg.sender][posID]]) { allCycles.push(positionCycle[msg.sender][posID]); isCycle[positionCycle[msg.sender][posID]] = true; } if (isUser[msg.sender] == false) { isUser[msg.sender] = true; allUsers.push(msg.sender); } userInfo[msg.sender].push(_userInfo); _mint(msg.sender, staked); emit Deposit(msg.sender, amount, staked, block.timestamp, posID, _leverage); } function closePosition(uint256 _positionID) external InvalidID(_positionID, msg.sender) nonReentrant { UserInfo storage _userInfo = userInfo[msg.sender][_positionID]; require(!_userInfo.liquidated && !_userInfo.closed, "AirPuff: position is not active"); require(_userInfo.position > 0, "AirPuff: position is not enough to close"); require(msg.sender == _userInfo.user, "AirPuff: not allowed to close position"); require(!closePending[msg.sender][_positionID], "AirPuff: close position is pending"); uint256 positionID = _positionID; CloseData memory closeData; SwapData memory sData; //Check for liquidation (closeData.currentDTV,,closeData.fulldebtValue,closeData.totalInterests) = getUpdatedDebt(positionID, msg.sender); if (closeData.currentDTV >= (DTVLimit)) { revert("Wait for liquidation"); } uint256 userTokensBurned = _userInfo.position; _burn(msg.sender, _userInfo.position); uint256 debtSW = closeData.fulldebtValue * DECIMAL / IswETH(strategyAddresses.swETH).swETHToETHRate(); closeData.toLeverageUser = _userInfo.position - debtSW; uint256 userRequestCount = userCloseRequestsCount[msg.sender].length; CloseRequestData storage closeRequest = closeRequests[msg.sender][userRequestCount]; closeRequest.positionID = positionID; closeRequest.amount = debtSW; closeRequest.closeRequestID = userRequestCount; closeRequest.user = msg.sender; closeRequest.done = false; userCloseRequestsCount[msg.sender].push(userRequestCount); uint256 withdrawFee; if (feeConfiguration.withdrawalFee > 0) { withdrawFee = closeData.toLeverageUser.mulDiv(feeConfiguration.withdrawalFee, MAX_BPS); IERC20Upgradeable(strategyAddresses.mswETH).safeTransfer(feeConfiguration.feeReceiver, withdrawFee); } sData.toLeverageUserOut = closeData.toLeverageUser - withdrawFee; IERC20Upgradeable(strategyAddresses.mswETH).safeTransfer(_userInfo.user, sData.toLeverageUserOut); IERC20Upgradeable(strategyAddresses.mswETH).safeTransfer(feeConfiguration.lendingFeeReceiver, debtSW); closePending[msg.sender][positionID] = true; PositionTimestamps storage pts = positionTimestamps[_userInfo.user][positionID]; pts.closeTimestamp = block.timestamp; emit Withdraw(msg.sender, positionID, _userInfo.position, _userInfo.leverage, debtSW, block.timestamp, userTokensBurned); } function fulfillClosePosition(address _user, uint256 _closeRequestID, uint256 _lendingRepayAmount) public { require(msg.sender == IAirPuffHandler(strategyAddresses.AirPuffHandler).keeper(), "AirPuff: not allowed to fulfill close position"); CloseRequestData storage closeRequest = closeRequests[_user][_closeRequestID]; require(!closeRequest.done, "AirPuff: close request already fulfilled"); require(closePending[_user][closeRequest.positionID], "AirPuff: close request is not pending"); require(_lendingRepayAmount > 0, "AirPuff: lending repay amount is 0"); require(closeRequest.user != address(0), "AirPuff: request does not exist"); uint256 posID = closeRequest.positionID; UserInfo storage _userInfo = userInfo[_user][posID]; require(!_userInfo.liquidated && !_userInfo.closed, "AirPuff: position is not active"); require(_lendingRepayAmount >= _userInfo.leverageAmount, "AirPuff: incorrect lending repay amount"); IERC20Upgradeable(strategyAddresses.WETH).safeTransferFrom(msg.sender, address(this), _lendingRepayAmount); IERC20Upgradeable(strategyAddresses.WETH).safeIncreaseAllowance(LendingVault, _lendingRepayAmount); ILending(LendingVault).repayDebt(_userInfo.leverageAmount, _lendingRepayAmount); closeWETHAmount[_user][posID] = _lendingRepayAmount; _userInfo.closed = true; _userInfo.position = 0; _userInfo.leverageAmount = 0; closeRequest.done = true; if (_userInfo.liquidator != address(0)) { _userInfo.liquidated = true; } emit PositionCloseFulfilled(_user, _closeRequestID, _lendingRepayAmount, _userInfo.liquidated); } function liquidatePosition(uint256 _positionID, address _user) external InvalidID(_positionID, _user) nonReentrant { require(msg.sender == IAirPuffHandler(strategyAddresses.AirPuffHandler).keeper(), "AirPuff: not allowed to liquidate positions"); UserInfo storage _userInfo = userInfo[_user][_positionID]; require(!_userInfo.liquidated, "AirPuff: Already liquidated"); require(_userInfo.user != address(0), "AirPuff: no active position"); (uint256 currentDTV,,,) = getUpdatedDebt(_positionID, _user); CloseData memory closeData; SwapData memory sData; require(currentDTV >= DTVLimit, "Liquidation not required"); uint256 position = _userInfo.position; _burn(_user, position); IERC20Upgradeable(strategyAddresses.mswETH).safeTransfer(feeConfiguration.lendingFeeReceiver, _userInfo.position); uint256 userRequestCount = userCloseRequestsCount[_user].length; CloseRequestData storage closeRequest = closeRequests[_user][userRequestCount]; closeRequest.positionID = _positionID; closeRequest.amount = position; closeRequest.closeRequestID = userRequestCount; closeRequest.user = _user; closeRequest.done = false; userCloseRequestsCount[_user].push(userRequestCount); _userInfo.liquidator = msg.sender; emit Liquidated(_user, _positionID, msg.sender, block.timestamp, _userInfo.position, position); } // -- Internal functions -- // function claimAll(uint256[] memory _cycles,address[] memory _assets) public onlyOwner { IEigenDepositHelper(strategyAddresses.EigenPreDepositHelper).userClaim(_cycles, _assets); } function _depositAndStake(uint256 totalAmount) internal returns (uint256) { uint256 swETHBalBefore = IERC20Upgradeable(strategyAddresses.swETH).balanceOf(address(this)); IswETH(strategyAddresses.swETH).deposit{value: totalAmount}(); uint256 swETHBalAfter = IERC20Upgradeable(strategyAddresses.swETH).balanceOf(address(this)); uint256 swETHAmountOut = swETHBalAfter - swETHBalBefore; uint256 depositedBal = _eigenPieDeposit(swETHAmountOut); return depositedBal; } function _eigenPieDeposit(uint256 _amount) internal returns (uint256) { IERC20Upgradeable(strategyAddresses.swETH).safeIncreaseAllowance(strategyAddresses.EigenPie, _amount); uint256 balBefore = IERC20Upgradeable(strategyAddresses.mswETH).balanceOf(address(this)); IEigenPieDeposit(strategyAddresses.EigenPie).depositAsset(strategyAddresses.swETH,_amount, _amount, address(0)); uint256 balAfter = IERC20Upgradeable(strategyAddresses.mswETH).balanceOf(address(this)); uint256 depositedBal = balAfter - balBefore; return depositedBal; } /** ----------- Token functions ------------- */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {} function transfer(address to, uint256 amount) public virtual override returns (bool) {} function burn(uint256 amount) public virtual override {} function burnFrom(address from, uint256 amount) public virtual override {} function onERC721Received( address, address _from, uint256 _tokenId, bytes calldata ) external returns (bytes4) { return this.onERC721Received.selector; } receive() external payable {} }
//SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface ILending { function lend(uint256 _borrowed, address _receiver) external returns (bool status); function repayDebt(uint256 leverage, uint256 debtValue) external returns (bool); function getTotalDebt() external view returns (uint256); function updateTotalDebt(uint256 profit) external returns (uint256); function totalAssets() external view returns (uint256); function totalDebt() external view returns (uint256); function balanceOfUSDC() external view returns (uint256); function getUtilizationRate() external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface IVault { struct UserInfo { address user; uint256 deposit; uint256 leverage; uint256 position; bool liquidated; address liquidator; uint256 leverageAmount; uint256 positionId; bool closed; } struct FeeConfiguration { address feeReceiver; uint256 withdrawalFee; address lendingFeeReceiver; uint256 mFeePercent; address mFeeReceiver; uint256 liquidatorFee; } struct LeverageBounds { uint256 minLeverage; uint256 maxLeverage; uint256 minDeposit; } struct StrategyAddresses { address WETH; address AirPuffHandler; address borrowAsset; address mswETH; address EigenPie; address swETH; address EigenPreDepositHelper; address swExit; } struct SwapData { uint256 amountOut; uint256 repayAmount; uint256 toLeverageUserOut; uint256 liquidationLeftovers; } struct CloseData { uint256 currentDTV; uint256 fulldebtValue; uint256 totalInterests; uint256 mFee; uint256 toLeverageUser; uint256 totalLRTAssetPosition; uint256 lendingRepayment; } struct PositionTimestamps { uint256 openTimestamp; uint256 closeTimestamp; uint256 vaultSnapshotID; } struct CloseRequestData { address user; uint256 closeRequestID; uint256 positionID; uint256 amount; uint256 swExitID; bool done; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable { function __ERC20Burnable_init() internal onlyInitializing { } function __ERC20Burnable_init_unchained() internal onlyInitializing { } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 1 }, "evmVersion": "shanghai", "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minLeverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxLeverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minDeposit","type":"uint256"}],"name":"LeverageBoundsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lendingRepayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"position","type":"uint256"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_closeRequestID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_lendingRepayAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLiquidation","type":"bool"}],"name":"PositionCloseFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"newWithdrawalFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"newLendingFeeReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidatorFeeChanged","type":"uint256"}],"name":"ProtocolFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_closer","type":"address"},{"indexed":false,"internalType":"bool","name":"_allowed","type":"bool"}],"name":"SetAllowedClosers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"DTVLimit","type":"uint256"}],"name":"SetDTVLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isBalancer","type":"bool"}],"name":"SetIsBalancer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isSimple","type":"bool"}],"name":"SetIsSwapSimple","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"SetLendingVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"AirPuffHandler","type":"address"},{"indexed":false,"internalType":"address","name":"_mswETH","type":"address"},{"indexed":false,"internalType":"address","name":"_eigenPie","type":"address"},{"indexed":false,"internalType":"address","name":"_swETH","type":"address"},{"indexed":false,"internalType":"address","name":"_EigenPreDepositHelper","type":"address"},{"indexed":false,"internalType":"address","name":"_swExit","type":"address"}],"name":"SetStrategyAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_withdrawEnabled","type":"bool"}],"name":"SetWithdrawEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isUnstakeEnabled","type":"bool"}],"name":"UnstakeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userTokensBurned","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DTVLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LendingVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allCycles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_cycles","type":"uint256[]"},{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"claimAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"closePending","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_positionID","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"closeRequests","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"closeRequestID","type":"uint256"},{"internalType":"uint256","name":"positionID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"swExitID","type":"uint256"},{"internalType":"bool","name":"done","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"closeWETHAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeConfiguration","outputs":[{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"withdrawalFee","type":"uint256"},{"internalType":"address","name":"lendingFeeReceiver","type":"address"},{"internalType":"uint256","name":"mFeePercent","type":"uint256"},{"internalType":"address","name":"mFeeReceiver","type":"address"},{"internalType":"uint256","name":"liquidatorFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_closeRequestID","type":"uint256"},{"internalType":"uint256","name":"_lendingRepayAmount","type":"uint256"}],"name":"fulfillClosePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllEigeinPieCycleDepositAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllUsers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getTotalNumbersOfOpenPositionBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_positionID","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUpdatedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_WETH","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBalancer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isCycle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSwapSimple","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isUnstakeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isUser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leverageBounds","outputs":[{"internalType":"uint256","name":"minLeverage","type":"uint256"},{"internalType":"uint256","name":"maxLeverage","type":"uint256"},{"internalType":"uint256","name":"minDeposit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_positionID","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"liquidatePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"onlyAllowedClosers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_leverage","type":"uint256"}],"name":"openPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"positionCycle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"positionTimestamps","outputs":[{"internalType":"uint256","name":"openTimestamp","type":"uint256"},{"internalType":"uint256","name":"closeTimestamp","type":"uint256"},{"internalType":"uint256","name":"vaultSnapshotID","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_closer","type":"address"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowedClosers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_DTVLimit","type":"uint256"}],"name":"setDTVLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBalancer","type":"bool"}],"name":"setIsBalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isSimple","type":"bool"}],"name":"setIsSwapSimple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"setLendingVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minLeverage","type":"uint256"},{"internalType":"uint256","name":"_maxLeverage","type":"uint256"},{"internalType":"uint256","name":"_minDeposit","type":"uint256"}],"name":"setMinMaxLeverageBounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"uint256","name":"_withdrawalFee","type":"uint256"},{"internalType":"address","name":"_lendingFeeReceiver","type":"address"},{"internalType":"uint256","name":"_mFeePercent","type":"uint256"},{"internalType":"address","name":"_mFeeReceiver","type":"address"},{"internalType":"uint256","name":"_liquidatorFee","type":"uint256"}],"name":"setProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_AirPuffHandler","type":"address"},{"internalType":"address","name":"_mswETH","type":"address"},{"internalType":"address","name":"_EigenPie","type":"address"},{"internalType":"address","name":"_swETH","type":"address"},{"internalType":"address","name":"_EigenPreDepositHelper","type":"address"},{"internalType":"address","name":"_swExit","type":"address"}],"name":"setStrategyAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUnstakeEnabled","type":"bool"}],"name":"setUnstakeEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyAddresses","outputs":[{"internalType":"address","name":"WETH","type":"address"},{"internalType":"address","name":"AirPuffHandler","type":"address"},{"internalType":"address","name":"borrowAsset","type":"address"},{"internalType":"address","name":"mswETH","type":"address"},{"internalType":"address","name":"EigenPie","type":"address"},{"internalType":"address","name":"swETH","type":"address"},{"internalType":"address","name":"EigenPreDepositHelper","type":"address"},{"internalType":"address","name":"swExit","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userCloseRequestsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userInfo","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"uint256","name":"position","type":"uint256"},{"internalType":"bool","name":"liquidated","type":"bool"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"uint256","name":"leverageAmount","type":"uint256"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"bool","name":"closed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801562000010575f80fd5b506200001b62000021565b620000df565b5f54610100900460ff16156200008d5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811614620000dd575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6147dd80620000ed5f395ff3fe60806040526004361061029e575f3560e01c806306fdde03146102a9578063095ea7b3146102d3578063100e196d14610302578063150b7a02146103a657806318160ddd146103ea5780631adeca1e146104085780631e545826146104295780631e678f211461043d57806321ce919d1461045c5780632287e96a146104d457806323b872dd146104f55780632464e83f1461051757806328284b61146105365780632a4d971b14610555578063313ce56714610574578063395093511461058f5780633f4ba83a146105ae578063408a03d8146105c25780634209fff1146105e157806342966c68146106105780634b2dbd6f1461062d57806355c4347b1461064c578063567c03981461068b5780635c975abb146106a55780635f036de1146106bc578063661adea2146106db5780636cd2ccb8146106fa57806370a0823114610731578063715018a6146107655780637250076114610779578063778cf1ec146107b057806378fc8850146107c657806379cc6790146107f35780638456cb59146108115780638836509f146108255780638da5cb5b14610845578063944c979d1461085957806395d89b411461088e5780639627334e146108a257806398c47e8c146108d157806399ff820314610952578063a126d60114610965578063a457c2d714610984578063a9059cbb146109a3578063ab0ba2d7146109c4578063b33210b0146109e3578063ba39695814610a1d578063bcbf688014610a3c578063c4d66de814610a5b578063cf5cedb014610a7a578063d0845b8d14610a99578063d1ec4ea914610ab8578063d41b2aaa14610ae7578063db189fec14610b06578063dd62ed3e14610b36578063e2842d7914610b55578063f11b795414610b76578063f2fde38b14610bbc578063fb38814514610bdb575f80fd5b366102a557005b5f80fd5b3480156102b4575f80fd5b506102bd610c7b565b6040516102ca9190613e77565b60405180910390f35b3480156102de575f80fd5b506102f26102ed366004613ebd565b610d0b565b60405190151581526020016102ca565b34801561030d575f80fd5b506101335461013454610135546101365461013754610138546101395461013a54610354976001600160a01b03908116978116968116958116948116938116928116911688565b604080516001600160a01b03998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a0840152831660c083015290911660e0820152610100016102ca565b3480156103b1575f80fd5b506103d16103c0366004613ee7565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016102ca565b3480156103f5575f80fd5b5060cb545b6040519081526020016102ca565b348015610413575f80fd5b50610427610422366004614054565b610d24565b005b348015610434575f80fd5b506103fa610d90565b348015610448575f80fd5b50610427610457366004614113565b610ec0565b348015610467575f80fd5b5061047b610476366004613ebd565b610f2a565b604080516001600160a01b039a8b16815260208101999099528801969096526060870194909452911515608086015290941660a084015260c083019390935260e0820192909252901515610100820152610120016102ca565b3480156104df575f80fd5b50610144546102f2906301000000900460ff1681565b348015610500575f80fd5b506102f261050f36600461414a565b5f9392505050565b348015610522575f80fd5b50610144546102f290610100900460ff1681565b348015610541575f80fd5b50610427610550366004614188565b610fa3565b348015610560575f80fd5b506103fa61056f3660046141a3565b610ff9565b34801561057f575f80fd5b50604051601281526020016102ca565b34801561059a575f80fd5b506102f26105a9366004613ebd565b611019565b3480156105b9575f80fd5b5061042761103a565b3480156105cd575f80fd5b506104276105dc3660046141ba565b61104c565b3480156105ec575f80fd5b506102f26105fb3660046141ba565b61014b6020525f908152604090205460ff1681565b34801561061b575f80fd5b5061042761062a3660046141a3565b50565b348015610638575f80fd5b506104276106473660046141a3565b6110a0565b348015610657575f80fd5b5061066b6106663660046141d5565b6110de565b6040805194855260208501939093529183015260608201526080016102ca565b348015610696575f80fd5b50610144546102f29060ff1681565b3480156106b0575f80fd5b5060975460ff166102f2565b3480156106c7575f80fd5b506104276106d63660046141d5565b611313565b3480156106e6575f80fd5b506104276106f53660046141f8565b611779565b348015610705575f80fd5b506103fa610714366004613ebd565b61018460209081525f928352604080842090915290825290205481565b34801561073c575f80fd5b506103fa61074b3660046141ba565b6001600160a01b03165f90815260c9602052604090205490565b348015610770575f80fd5b50610427611c88565b348015610784575f80fd5b506103fa610793366004613ebd565b61014d60209081525f928352604080842090915290825290205481565b3480156107bb575f80fd5b506103fa6101435481565b3480156107d1575f80fd5b50610142546107e6906001600160a01b031681565b6040516102ca919061422a565b3480156107fe575f80fd5b5061042761080d366004613ebd565b5050565b34801561081c575f80fd5b50610427611c99565b348015610830575f80fd5b50610144546102f29062010000900460ff1681565b348015610850575f80fd5b506107e6611ca9565b348015610864575f80fd5b506103fa6108733660046141ba565b6001600160a01b03165f90815261014a602052604090205490565b348015610899575f80fd5b506102bd611cb8565b3480156108ad575f80fd5b506102f26108bc3660046141ba565b6101856020525f908152604090205460ff1681565b3480156108dc575f80fd5b5061012d5461012e5461012f5461013054610131546101325461090f956001600160a01b03908116959481169392169086565b604080516001600160a01b0397881681526020810196909652938616938501939093526060840191909152909216608082015260a081019190915260c0016102ca565b6104276109603660046141a3565b611cc7565b348015610970575f80fd5b5061042761097f3660046141a3565b612393565b34801561098f575f80fd5b506102f261099e366004613ebd565b612864565b3480156109ae575f80fd5b506102f26109bd366004613ebd565b5f92915050565b3480156109cf575f80fd5b506104276109de36600461423e565b6128e9565b3480156109ee575f80fd5b506102f26109fd366004613ebd565b61018360209081525f928352604080842090915290825290205460ff1681565b348015610a28575f80fd5b50610427610a37366004614188565b612a14565b348015610a47575f80fd5b50610427610a563660046142a1565b612a66565b348015610a66575f80fd5b50610427610a753660046141ba565b612b94565b348015610a85575f80fd5b50610427610a94366004614188565b612d4f565b348015610aa4575f80fd5b50610427610ab33660046142ca565b612d9f565b348015610ac3575f80fd5b506102f2610ad23660046141a3565b6101506020525f908152604090205460ff1681565b348015610af2575f80fd5b506103fa610b01366004613ebd565b612ec5565b348015610b11575f80fd5b5061013b5461013c5461013d54610b2792919083565b6040516102ca93929190614348565b348015610b41575f80fd5b506103fa610b5036600461435e565b612ef1565b348015610b60575f80fd5b50610b69612f1b565b6040516102ca91906143cc565b348015610b81575f80fd5b50610b27610b90366004613ebd565b61014c60209081525f928352604080842090915290825290208054600182015460029092015490919083565b348015610bc7575f80fd5b50610427610bd63660046141ba565b612f7b565b348015610be6575f80fd5b50610c42610bf5366004613ebd565b61014e60209081525f92835260408084209091529082529020805460018201546002830154600384015460048501546005909501546001600160a01b039094169492939192909160ff1686565b604080516001600160a01b03909716875260208701959095529385019290925260608401526080830152151560a082015260c0016102ca565b606060cc8054610c8a906143de565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb6906143de565b8015610d015780601f10610cd857610100808354040283529160200191610d01565b820191905f5260205f20905b815481529060010190602001808311610ce457829003601f168201915b5050505050905090565b5f33610d18818585612ff1565b60019150505b92915050565b610d2c613114565b61013954604051636d830c6160e11b81526001600160a01b039091169063db0618c290610d5f9085908590600401614416565b5f604051808303815f87803b158015610d76575f80fd5b505af1158015610d88573d5f803e3d5ffd5b505050505050565b5f806101336006015f9054906101000a90046001600160a01b03166001600160a01b031663bab2f5526040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0a9190614462565b90505f805b828111610eb957610139546101385460405163ba37b42960e01b8152600481018490523060248201526001600160a01b0391821660448201525f92919091169063ba37b429906064016040805180830381865afa158015610e72573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e969190614479565b509050610ea381846144af565b9250508080610eb1906144c2565b915050610e0f565b5092915050565b610ec8613114565b6001600160a01b0382165f908152610185602052604090819020805460ff1916831515179055517f2626e1501ac007a99ed3bca0402984dce31d222879c878c4a5fb3952b6733a0290610f1e90849084906144da565b60405180910390a15050565b61014a602052815f5260405f208181548110610f44575f80fd5b5f918252602090912060089091020180546001820154600283015460038401546004850154600586015460068701546007909701546001600160a01b0396871699509497509295919460ff808316956101009093049091169392911689565b610fab613114565b610144805460ff19168215151790556040517f0c941692f2150cd601667ca332b43d1248223903490578e29170f6286390c59090610fee90831515815260200190565b60405180910390a150565b6101458181548110611009575f80fd5b5f91825260209091200154905081565b5f33610d1881858561102b8383612ef1565b61103591906144af565b612ff1565b611042613114565b61104a613173565b565b611054613114565b61014280546001600160a01b0319166001600160a01b0383161790556040517f63cfbd3f699aee5839a268c3b8711c3401093dbe492882085f9659cca8be0b6f90610fee90839061422a565b6110a8613114565b6101438190556040518181527fdd22b11e8687e6bbbc986e7ee0c5076064ac56c77b65a633a0996595f327d5dd90602001610fee565b6001600160a01b0381165f90815261014a602052604081208054829182918291829188908110611110576111106144f5565b5f9182526020918290206040805161012081018252600890930290910180546001600160a01b03908116845260018201549484019490945260028101549183019190915260038101546060830152600481015460ff808216151560808501526101009182900490941660a0840152600582015460c0840152600682015460e084015260079091015490921615159181018290529150806111b1575080608001515b156111c8575f805f8094509450945094505061130a565b61013454604051631b49306160e01b81526001600160a01b038881166004830152602482018a90523060448301525f928392911690631b493061906064016040805180830381865afa158015611220573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112449190614479565b6101345461013854604051633cbc807760e21b81529395509193505f926001600160a01b039182169263f2f201dc926112829291169060040161422a565b602060405180830381865afa15801561129d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c19190614462565b90505f6112e0826101495487606001516131bf9092919063ffffffff16565b90505f6112fb6101495483876131bf9092919063ffffffff16565b99509097509295509093505050505b92959194509250565b6001600160a01b0381165f90815261014a60205260409020548290829082106113575760405162461bcd60e51b815260040161134e90614509565b60405180910390fd5b61135f6132aa565b610134546040805163aced166160e01b815290516001600160a01b039092169163aced1661916004808201926020929091908290030181865afa1580156113a8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113cc919061453e565b6001600160a01b0316336001600160a01b0316146114405760405162461bcd60e51b815260206004820152602b60248201527f416972507566663a206e6f7420616c6c6f77656420746f206c6971756964617460448201526a6520706f736974696f6e7360a81b606482015260840161134e565b6001600160a01b0383165f90815261014a6020526040812080548690811061146a5761146a6144f5565b5f9182526020909120600890910201600481015490915060ff16156114cf5760405162461bcd60e51b815260206004820152601b60248201527a105a5c941d59998e88105b1c9958591e481b1a5c5d5a59185d1959602a1b604482015260640161134e565b80546001600160a01b03166115245760405162461bcd60e51b815260206004820152601b60248201527a20b4b9283ab3331d1037379030b1ba34bb32903837b9b4ba34b7b760291b604482015260640161134e565b5f61152f86866110de565b505050905061153c613dfb565b611544613e31565b610143548310156115925760405162461bcd60e51b8152602060048201526018602482015277131a5c5d5a59185d1a5bdb881b9bdd081c995c5d5a5c995960421b604482015260640161134e565b60038401546115a18882613303565b61012f546003860154610136546115c6926001600160a01b0391821692911690613422565b5f61014f5f8a6001600160a01b03166001600160a01b031681526020019081526020015f208054905090505f61014e5f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f8381526020019081526020015f2090508a816002018190555082816003018190555081816001018190555089815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f816005015f6101000a81548160ff02191690831515021790555061014f5f8b6001600160a01b03166001600160a01b031681526020019081526020015f2082908060018154018082558091505060019003905f5260205f20015f9091909190915055338760040160016101000a8154816001600160a01b0302191690836001600160a01b031602179055508a8a6001600160a01b03167fd6da7d9908c68b91a918abe9a7b86a0342a4d1c9511463900fa6d653994ec4cf33428b600301548860405161175a94939291906001600160a01b0394909416845260208401929092526040830152606082015260800190565b60405180910390a3505050505050506117736001606555565b50505050565b610134546040805163aced166160e01b815290516001600160a01b039092169163aced1661916004808201926020929091908290030181865afa1580156117c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117e6919061453e565b6001600160a01b0316336001600160a01b03161461185d5760405162461bcd60e51b815260206004820152602e60248201527f416972507566663a206e6f7420616c6c6f77656420746f2066756c66696c6c2060448201526d31b637b9b2903837b9b4ba34b7b760911b606482015260840161134e565b6001600160a01b0383165f90815261014e602090815260408083208584529091529020600581015460ff16156118e65760405162461bcd60e51b815260206004820152602860248201527f416972507566663a20636c6f7365207265717565737420616c726561647920666044820152671d5b199a5b1b195960c21b606482015260840161134e565b6001600160a01b0384165f908152610183602090815260408083206002850154845290915290205460ff1661196b5760405162461bcd60e51b815260206004820152602560248201527f416972507566663a20636c6f73652072657175657374206973206e6f742070656044820152646e64696e6760d81b606482015260840161134e565b5f82116119c55760405162461bcd60e51b815260206004820152602260248201527f416972507566663a206c656e64696e6720726570617920616d6f756e74206973604482015261020360f41b606482015260840161134e565b80546001600160a01b0316611a1c5760405162461bcd60e51b815260206004820152601f60248201527f416972507566663a207265717565737420646f6573206e6f7420657869737400604482015260640161134e565b60028101546001600160a01b0385165f90815261014a60205260408120805483908110611a4b57611a4b6144f5565b5f9182526020909120600890910201600481015490915060ff16158015611a775750600781015460ff16155b611a935760405162461bcd60e51b815260040161134e90614559565b8060050154841015611af75760405162461bcd60e51b815260206004820152602760248201527f416972507566663a20696e636f7272656374206c656e64696e6720726570617960448201526608185b5bdd5b9d60ca1b606482015260840161134e565b61013354611b10906001600160a01b031633308761347f565b6101425461013354611b2f916001600160a01b039182169116866134b7565b61014254600582015460405163015cb0a560e01b81526001600160a01b039092169163015cb0a591611b6e918890600401918252602082015260400190565b6020604051808303815f875af1158015611b8a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bae9190614590565b506001600160a01b038681165f908152610184602090815260408083208684529091528120869055600783018054600160ff199182168117909255600385018390556005808601939093559186018054909216179055600482015461010090041615611c245760048101805460ff191660011790555b6004810154604080516001600160a01b03891681526020810188905290810186905260ff909116151560608201527f9ac90136167f31456475a696ff0118b2758335e9545cabf670484f25b0049c47906080015b60405180910390a1505050505050565b611c90613114565b61104a5f613552565b611ca1613114565b61104a6135a3565b6033546001600160a01b031690565b606060cd8054610c8a906143de565b611ccf6132aa565b335f908152610185602052604090205460ff16611d2e5760405162461bcd60e51b815260206004820152601d60248201527f416972507566663a206f6e6c7920616c6c6f77656420636c6f73657273000000604482015260640161134e565b61013b548110801590611d44575061013c548111155b611d9b5760405162461bcd60e51b815260206004820152602260248201527f416972507566663a206c65766572616765206973206f7574206f6620626f756e604482015261647360f01b606482015260840161134e565b61013d54341015611dfc5760405162461bcd60e51b815260206004820152602560248201527f416972507566663a206465706f736974206973206c657373207468616e206d696044820152646e696d756d60d81b606482015260840161134e565b6101485434905f908290611e1390829086906131bf565b611e1d91906145ab565b90505f8111611e6e5760405162461bcd60e51b815260206004820152601d60248201527f416972507566663a206c6576657261676564416d6f756e742069732030000000604482015260640161134e565b61014254604051632c6211d160e21b8152600481018390523060248201525f916001600160a01b03169063b1884744906044016020604051808303815f875af1158015611ebd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee19190614590565b905080611f2a5760405162461bcd60e51b8152602060048201526017602482015276105a5c941d59998e881b195b991a5b99c819985a5b1959604a1b604482015260640161134e565b61013354604051632e1a7d4d60e01b8152600481018490526001600160a01b0390911690632e1a7d4d906024015f604051808303815f87803b158015611f6e575f80fd5b505af1158015611f80573d5f803e3d5ffd5b505050505f611f998385611f9491906144af565b6135e0565b90505f8111611fe15760405162461bcd60e51b81526020600482015260146024820152730416972507566663a207374616b656420697320360641b604482015260640161134e565b335f81815261014a60209081526040808320548151610120810183528581528084018a90528083018b9052606081018790526080810185905260a0810185905260c0810189905260e08101829052610100810185905294845261014c8352818420818552835292819020610139548251635d597aa960e11b8152925194959491936001600160a01b039091169263bab2f55292600480830193928290030181865afa158015612092573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120b69190614462565b335f90815261014d60209081526040808320878452909152908190209190915542825561013454610142549151635d8de25560e11b81526001600160a01b039182169263bb1bc4aa9261210e9291169060040161422a565b602060405180830381865afa158015612129573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061214d9190614462565b6002820155335f90815261014d60209081526040808320868452825280832054835261015090915290205460ff166121e757335f90815261014d6020908152604080832086845282528083208054610145805460018181019092557fed95984add84c4014c7f9d66a1b73e788e2db64f5763fa861ad52da204f71b2b019190915590548452610150909252909120805460ff191690911790555b335f90815261014b602052604081205460ff161515900361226057335f81815261014b60205260408120805460ff19166001908117909155610146805491820181559091527ff865fb3f06685bbcb5a1c6d69424d51a154206a5b27ad97bd5fbd9c0b2a0878a0180546001600160a01b03191690911790555b335f81815261014a6020908152604080832080546001808201835591855293839020875160089095020180546001600160a01b0319166001600160a01b039586161781559287015190830155850151600282015560608501516003820155608085015160048201805460a08801516001600160a81b0319909116921515610100600160a81b031916929092176101009290941682029390931790925560c0850151600582015560e08501516006820155908401516007909101805460ff19169115159190911790556123329085613749565b6040805188815260208101869052428183015260608101859052608081018a9052905133917ff943cf10ef4d1e3239f4716ddecdf546e8ba8ab0e41deafd9a71a99936827e45919081900360a00190a25050505050505061062a6001606555565b335f81815261014a602052604090205482919082106123c45760405162461bcd60e51b815260040161134e90614509565b6123cc6132aa565b335f90815261014a602052604081208054859081106123ed576123ed6144f5565b5f9182526020909120600890910201600481015490915060ff161580156124195750600781015460ff16155b6124355760405162461bcd60e51b815260040161134e90614559565b5f8160030154116124995760405162461bcd60e51b815260206004820152602860248201527f416972507566663a20706f736974696f6e206973206e6f7420656e6f75676820604482015267746f20636c6f736560c01b606482015260840161134e565b80546001600160a01b031633146125015760405162461bcd60e51b815260206004820152602660248201527f416972507566663a206e6f7420616c6c6f77656420746f20636c6f736520706f60448201526539b4ba34b7b760d11b606482015260840161134e565b335f9081526101836020908152604080832087845290915290205460ff16156125775760405162461bcd60e51b815260206004820152602260248201527f416972507566663a20636c6f736520706f736974696f6e2069732070656e64696044820152616e6760f01b606482015260840161134e565b83612580613dfb565b612588613e31565b61259283336110de565b604086015260208501525080835261014354116125e85760405162461bcd60e51b81526020600482015260146024820152732bb0b4ba103337b9103634b8bab4b230ba34b7b760611b604482015260640161134e565b60038401546125f73382613303565b6101385460408051636b45965b60e11b815290515f926001600160a01b03169163d68b2cb69160048083019260209291908290030181865afa15801561263f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126639190614462565b61014954856020015161267691906145be565b61268091906145e9565b905080866003015461269291906145ab565b6080850152335f81815261014f60208181526040808420805461014e84528286208187528452918520600281018c905560038101889055600180820184905581546001600160a01b031916909717815560058101805460ff1916905593835280549586018155845290832090930183905561012e54909190156127495761012e546101475460808901516127279290916131bf565b61012d5461013654919250612749916001600160a01b03908116911683613422565b80876080015161275991906145ab565b60408701819052895461013654612780926001600160a01b03918216929190911690613422565b61012f546101365461279f916001600160a01b03918216911686613422565b335f818152610183602090815260408083208c845282528083208054600160ff1990911681179091558d546001600160a01b0316845261014c83528184208d85528352928190204293810184905560038e015460028f015483518f8152948501919091528383015260608301899052608083019390935260a08201899052519192917f194c8d0132d20112211dfa71bb87a92766fde4f4318e08efd2cc4a6e188e509d9181900360c00190a25050505050505050505061285f6001606555565b505050565b5f33816128718286612ef1565b9050838110156128d15760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161134e565b6128de8286868403612ff1565b506001949350505050565b6128f1613114565b610147548511156129335760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964206665657360a01b604482015260640161134e565b62015f9083111561297c5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081b51995954195c98d95b9d606a1b604482015260640161134e565b61012d80546001600160a01b038881166001600160a01b0319928316811790935561012e88905561012f80548883169084168117909155610131805492871692909316919091179091556101308590556101328390556040805192835260208301889052820152606081018290527fea2c2d9ff6a85c05d1354c4c00a91e3b9d080a0e04210dee967e63469a34ecdd90608001611c78565b612a1c613114565b610144805462ff0000191662010000831515021790556040517f412fd56d2370889482e86e6b548521900ac7d783389c28e1430bcdcf6b9f328990610fee90831515815260200190565b612a6e613114565b6103e88310158015612a825750613a988211155b612ad95760405162461bcd60e51b815260206004820152602260248201527f416972507566663a20696e636f7272656374206c6576657261676520626f756e604482015261647360f01b606482015260840161134e565b818310612b415760405162461bcd60e51b815260206004820152603060248201527f416972507566663a206d696e4c6576657261676520697320677265617465722060448201526f7468616e206d61784c6576657261676560801b606482015260840161134e565b61013b83905561013c82905561013d8190556040517f4f82863f56b6abfad6bb6faec52dcd9ab3f799d81d87438a7e3d75f71bbe653890612b8790859085908590614348565b60405180910390a1505050565b5f54610100900460ff1615808015612bb257505f54600160ff909116105b80612bd25750612bc1306137f5565b158015612bd257505f5460ff166001145b612c355760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161134e565b5f805460ff191660011790558015612c56575f805461ff0019166101001790555b61013380546001600160a01b0384166001600160a01b0319918216811790925561013580549091169091179055620186a0610147556103e861014855670de0b6b3a764000061014955612ca7613804565b612caf613832565b612cb7613860565b612d0e60405180604001604052806016815260200175082d2e4a0eacccc5a8ad2cecadca0d2cadae6ee8aa8960531b815250604051806040016040528060078152602001660c4dae6ee8aa8960cb1b81525061388e565b801561080d575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610f1e565b612d57613114565b610144805461ff001916610100831515021790556040517f584f3e4b3d70055b45e1922c8712e5a5b3eaa02883013fa0f74ea0dfcfb1221090610fee90831515815260200190565b612da7613114565b61013480546001600160a01b03199081166001600160a01b03898116919091179092556101368054821688841617905561013780548216878416179055610138805482168684161790556101398054821685841617905561013a8054909116918316918217905560405163a22cb46560e01b815263a22cb46590612e329084906001906004016144da565b5f604051808303815f87803b158015612e49575f80fd5b505af1158015612e5b573d5f803e3d5ffd5b5050604080516001600160a01b03808b168252808a166020830152808916928201929092528187166060820152818616608082015290841660a08201527ff38e8910932afd378baa3865f321215fda176698b19175dd2d62d242b53acfc8925060c0019050611c78565b61014f602052815f5260405f208181548110612edf575f80fd5b905f5260205f20015f91509150505481565b6001600160a01b039182165f90815260ca6020908152604080832093909416825291909152205490565b6060610146805480602002602001604051908101604052809291908181526020018280548015610d0157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311612f54575050505050905090565b612f83613114565b6001600160a01b038116612fe85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161134e565b61062a81613552565b6001600160a01b0383166130535760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161134e565b6001600160a01b0382166130b45760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161134e565b6001600160a01b038381165f81815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b3361311d611ca9565b6001600160a01b03161461104a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161134e565b61317b6138be565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516131b5919061422a565b60405180910390a1565b5f80805f19858709858702925082811083820303915050805f036131f6578382816131ec576131ec6145d5565b04925050506132a3565b80841161323d5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161134e565b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6002606554036132fc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161134e565b6002606555565b6001600160a01b0382166133635760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161134e565b6001600160a01b0382165f90815260c96020526040902054818110156133d65760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161134e565b6001600160a01b0383165f81815260c960209081526040808320868603905560cb80548790039055518581529192915f80516020614788833981519152910160405180910390a3505050565b61285f8363a9059cbb60e01b8484604051602401613441929190614608565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613907565b6001606555565b6040516001600160a01b03808516602483015283166044820152606481018290526117739085906323b872dd60e01b90608401613441565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015613504573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135289190614462565b90506117738463095ea7b360e01b8561354186866144af565b604051602401613441929190614608565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6135ab6139da565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586131a83390565b610138546040516370a0823160e01b81525f9182916001600160a01b03909116906370a082319061361590309060040161422a565b602060405180830381865afa158015613630573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136549190614462565b6101385460408051630d0e30db60e41b815290519293506001600160a01b039091169163d0e30db09186916004808301925f92919082900301818588803b15801561369d575f80fd5b505af11580156136af573d5f803e3d5ffd5b5050610138546040516370a0823160e01b81525f94506001600160a01b0390911692506370a0823191506136e790309060040161422a565b602060405180830381865afa158015613702573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137269190614462565b90505f61373383836145ab565b90505f61373f82613a20565b9695505050505050565b6001600160a01b03821661379f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161134e565b8060cb5f8282546137b091906144af565b90915550506001600160a01b0382165f81815260c960209081526040808320805486019055518481525f80516020614788833981519152910160405180910390a35050565b6001600160a01b03163b151590565b5f54610100900460ff1661382a5760405162461bcd60e51b815260040161134e90614621565b61104a613bad565b5f54610100900460ff166138585760405162461bcd60e51b815260040161134e90614621565b61104a613bdc565b5f54610100900460ff166138865760405162461bcd60e51b815260040161134e90614621565b61104a613c0e565b5f54610100900460ff166138b45760405162461bcd60e51b815260040161134e90614621565b61080d8282613c34565b60975460ff1661104a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161134e565b5f61395b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613c739092919063ffffffff16565b905080515f148061397b57508080602001905181019061397b9190614590565b61285f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161134e565b60975460ff161561104a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161134e565b61013754610138545f91613a41916001600160a01b039081169116846134b7565b610136546040516370a0823160e01b81525f916001600160a01b0316906370a0823190613a7290309060040161422a565b602060405180830381865afa158015613a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ab19190614462565b61013754610138546040516305d7c0f960e31b81526001600160a01b03918216600482015260248101879052604481018790525f60648201529293501690632ebe07c8906084015f604051808303815f87803b158015613b0f575f80fd5b505af1158015613b21573d5f803e3d5ffd5b5050610136546040516370a0823160e01b81525f93506001600160a01b0390911691506370a0823190613b5890309060040161422a565b602060405180830381865afa158015613b73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b979190614462565b90505f613ba483836145ab565b95945050505050565b5f54610100900460ff16613bd35760405162461bcd60e51b815260040161134e90614621565b61104a33613552565b5f54610100900460ff16613c025760405162461bcd60e51b815260040161134e90614621565b6097805460ff19169055565b5f54610100900460ff166134785760405162461bcd60e51b815260040161134e90614621565b5f54610100900460ff16613c5a5760405162461bcd60e51b815260040161134e90614621565b60cc613c6683826146b1565b5060cd61285f82826146b1565b6060613c8184845f85613c89565b949350505050565b606082471015613cea5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161134e565b5f80866001600160a01b03168587604051613d05919061476c565b5f6040518083038185875af1925050503d805f8114613d3f576040519150601f19603f3d011682016040523d82523d5f602084013e613d44565b606091505b5091509150613d5587838387613d60565b979650505050505050565b60608315613dcc5782515f03613dc557613d79856137f5565b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161134e565b5081613c81565b613c818383815115613de15781518083602001fd5b8060405162461bcd60e51b815260040161134e9190613e77565b6040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b60405180608001604052805f81526020015f81526020015f81526020015f81525090565b5f5b83811015613e6f578181015183820152602001613e57565b50505f910152565b602081525f8251806020840152613e95816040850160208701613e55565b601f01601f19169190910160400192915050565b6001600160a01b038116811461062a575f80fd5b5f8060408385031215613ece575f80fd5b8235613ed981613ea9565b946020939093013593505050565b5f805f805f60808688031215613efb575f80fd5b8535613f0681613ea9565b94506020860135613f1681613ea9565b93506040860135925060608601356001600160401b0380821115613f38575f80fd5b818801915088601f830112613f4b575f80fd5b813581811115613f59575f80fd5b896020828501011115613f6a575f80fd5b9699959850939650602001949392505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613fb957613fb9613f7d565b604052919050565b5f6001600160401b03821115613fd957613fd9613f7d565b5060051b60200190565b5f82601f830112613ff2575f80fd5b8135602061400761400283613fc1565b613f91565b82815260059290921b84018101918181019086841115614025575f80fd5b8286015b8481101561404957803561403c81613ea9565b8352918301918301614029565b509695505050505050565b5f8060408385031215614065575f80fd5b82356001600160401b038082111561407b575f80fd5b818501915085601f83011261408e575f80fd5b8135602061409e61400283613fc1565b82815260059290921b840181019181810190898411156140bc575f80fd5b948201945b838610156140da578535825294820194908201906140c1565b965050860135925050808211156140ef575f80fd5b506140fc85828601613fe3565b9150509250929050565b801515811461062a575f80fd5b5f8060408385031215614124575f80fd5b823561412f81613ea9565b9150602083013561413f81614106565b809150509250929050565b5f805f6060848603121561415c575f80fd5b833561416781613ea9565b9250602084013561417781613ea9565b929592945050506040919091013590565b5f60208284031215614198575f80fd5b81356132a381614106565b5f602082840312156141b3575f80fd5b5035919050565b5f602082840312156141ca575f80fd5b81356132a381613ea9565b5f80604083850312156141e6575f80fd5b82359150602083013561413f81613ea9565b5f805f6060848603121561420a575f80fd5b833561421581613ea9565b95602085013595506040909401359392505050565b6001600160a01b0391909116815260200190565b5f805f805f8060c08789031215614253575f80fd5b863561425e81613ea9565b955060208701359450604087013561427581613ea9565b935060608701359250608087013561428c81613ea9565b8092505060a087013590509295509295509295565b5f805f606084860312156142b3575f80fd5b505081359360208301359350604090920135919050565b5f805f805f8060c087890312156142df575f80fd5b86356142ea81613ea9565b955060208701356142fa81613ea9565b9450604087013561430a81613ea9565b9350606087013561431a81613ea9565b9250608087013561432a81613ea9565b915060a087013561433a81613ea9565b809150509295509295509295565b9283526020830191909152604082015260600190565b5f806040838503121561436f575f80fd5b823561437a81613ea9565b9150602083013561413f81613ea9565b5f8151808452602080850194508084015f5b838110156143c15781516001600160a01b03168752958201959082019060010161439c565b509495945050505050565b602081525f6132a3602083018461438a565b600181811c908216806143f257607f821691505b60208210810361441057634e487b7160e01b5f52602260045260245ffd5b50919050565b604080825283519082018190525f906020906060840190828701845b8281101561444e57815184529284019290840190600101614432565b5050508381038285015261373f818661438a565b5f60208284031215614472575f80fd5b5051919050565b5f806040838503121561448a575f80fd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610d1e57610d1e61449b565b5f600182016144d3576144d361449b565b5060010190565b6001600160a01b039290921682521515602082015260400190565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f416972507566663a20706f736974696f6e4944206973206e6f742076616c6964604082015260600190565b5f6020828403121561454e575f80fd5b81516132a381613ea9565b6020808252601f908201527f416972507566663a20706f736974696f6e206973206e6f742061637469766500604082015260600190565b5f602082840312156145a0575f80fd5b81516132a381614106565b81810381811115610d1e57610d1e61449b565b8082028115828204841417610d1e57610d1e61449b565b634e487b7160e01b5f52601260045260245ffd5b5f8261460357634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160a01b03929092168252602082015260400190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561285f575f81815260208120601f850160051c810160208610156146925750805b601f850160051c820191505b81811015610d885782815560010161469e565b81516001600160401b038111156146ca576146ca613f7d565b6146de816146d884546143de565b8461466c565b602080601f831160018114614711575f84156146fa5750858301515b5f19600386901b1c1916600185901b178555610d88565b5f85815260208120601f198616915b8281101561473f57888601518255948401946001909101908401614720565b508582101561475c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f825161477d818460208701613e55565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122033d840f970503ae08224bc8a38cbb034b2b256b59c8b5926365dc0ebbe59cd2664736f6c63430008150033
Deployed Bytecode
0x60806040526004361061029e575f3560e01c806306fdde03146102a9578063095ea7b3146102d3578063100e196d14610302578063150b7a02146103a657806318160ddd146103ea5780631adeca1e146104085780631e545826146104295780631e678f211461043d57806321ce919d1461045c5780632287e96a146104d457806323b872dd146104f55780632464e83f1461051757806328284b61146105365780632a4d971b14610555578063313ce56714610574578063395093511461058f5780633f4ba83a146105ae578063408a03d8146105c25780634209fff1146105e157806342966c68146106105780634b2dbd6f1461062d57806355c4347b1461064c578063567c03981461068b5780635c975abb146106a55780635f036de1146106bc578063661adea2146106db5780636cd2ccb8146106fa57806370a0823114610731578063715018a6146107655780637250076114610779578063778cf1ec146107b057806378fc8850146107c657806379cc6790146107f35780638456cb59146108115780638836509f146108255780638da5cb5b14610845578063944c979d1461085957806395d89b411461088e5780639627334e146108a257806398c47e8c146108d157806399ff820314610952578063a126d60114610965578063a457c2d714610984578063a9059cbb146109a3578063ab0ba2d7146109c4578063b33210b0146109e3578063ba39695814610a1d578063bcbf688014610a3c578063c4d66de814610a5b578063cf5cedb014610a7a578063d0845b8d14610a99578063d1ec4ea914610ab8578063d41b2aaa14610ae7578063db189fec14610b06578063dd62ed3e14610b36578063e2842d7914610b55578063f11b795414610b76578063f2fde38b14610bbc578063fb38814514610bdb575f80fd5b366102a557005b5f80fd5b3480156102b4575f80fd5b506102bd610c7b565b6040516102ca9190613e77565b60405180910390f35b3480156102de575f80fd5b506102f26102ed366004613ebd565b610d0b565b60405190151581526020016102ca565b34801561030d575f80fd5b506101335461013454610135546101365461013754610138546101395461013a54610354976001600160a01b03908116978116968116958116948116938116928116911688565b604080516001600160a01b03998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a0840152831660c083015290911660e0820152610100016102ca565b3480156103b1575f80fd5b506103d16103c0366004613ee7565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016102ca565b3480156103f5575f80fd5b5060cb545b6040519081526020016102ca565b348015610413575f80fd5b50610427610422366004614054565b610d24565b005b348015610434575f80fd5b506103fa610d90565b348015610448575f80fd5b50610427610457366004614113565b610ec0565b348015610467575f80fd5b5061047b610476366004613ebd565b610f2a565b604080516001600160a01b039a8b16815260208101999099528801969096526060870194909452911515608086015290941660a084015260c083019390935260e0820192909252901515610100820152610120016102ca565b3480156104df575f80fd5b50610144546102f2906301000000900460ff1681565b348015610500575f80fd5b506102f261050f36600461414a565b5f9392505050565b348015610522575f80fd5b50610144546102f290610100900460ff1681565b348015610541575f80fd5b50610427610550366004614188565b610fa3565b348015610560575f80fd5b506103fa61056f3660046141a3565b610ff9565b34801561057f575f80fd5b50604051601281526020016102ca565b34801561059a575f80fd5b506102f26105a9366004613ebd565b611019565b3480156105b9575f80fd5b5061042761103a565b3480156105cd575f80fd5b506104276105dc3660046141ba565b61104c565b3480156105ec575f80fd5b506102f26105fb3660046141ba565b61014b6020525f908152604090205460ff1681565b34801561061b575f80fd5b5061042761062a3660046141a3565b50565b348015610638575f80fd5b506104276106473660046141a3565b6110a0565b348015610657575f80fd5b5061066b6106663660046141d5565b6110de565b6040805194855260208501939093529183015260608201526080016102ca565b348015610696575f80fd5b50610144546102f29060ff1681565b3480156106b0575f80fd5b5060975460ff166102f2565b3480156106c7575f80fd5b506104276106d63660046141d5565b611313565b3480156106e6575f80fd5b506104276106f53660046141f8565b611779565b348015610705575f80fd5b506103fa610714366004613ebd565b61018460209081525f928352604080842090915290825290205481565b34801561073c575f80fd5b506103fa61074b3660046141ba565b6001600160a01b03165f90815260c9602052604090205490565b348015610770575f80fd5b50610427611c88565b348015610784575f80fd5b506103fa610793366004613ebd565b61014d60209081525f928352604080842090915290825290205481565b3480156107bb575f80fd5b506103fa6101435481565b3480156107d1575f80fd5b50610142546107e6906001600160a01b031681565b6040516102ca919061422a565b3480156107fe575f80fd5b5061042761080d366004613ebd565b5050565b34801561081c575f80fd5b50610427611c99565b348015610830575f80fd5b50610144546102f29062010000900460ff1681565b348015610850575f80fd5b506107e6611ca9565b348015610864575f80fd5b506103fa6108733660046141ba565b6001600160a01b03165f90815261014a602052604090205490565b348015610899575f80fd5b506102bd611cb8565b3480156108ad575f80fd5b506102f26108bc3660046141ba565b6101856020525f908152604090205460ff1681565b3480156108dc575f80fd5b5061012d5461012e5461012f5461013054610131546101325461090f956001600160a01b03908116959481169392169086565b604080516001600160a01b0397881681526020810196909652938616938501939093526060840191909152909216608082015260a081019190915260c0016102ca565b6104276109603660046141a3565b611cc7565b348015610970575f80fd5b5061042761097f3660046141a3565b612393565b34801561098f575f80fd5b506102f261099e366004613ebd565b612864565b3480156109ae575f80fd5b506102f26109bd366004613ebd565b5f92915050565b3480156109cf575f80fd5b506104276109de36600461423e565b6128e9565b3480156109ee575f80fd5b506102f26109fd366004613ebd565b61018360209081525f928352604080842090915290825290205460ff1681565b348015610a28575f80fd5b50610427610a37366004614188565b612a14565b348015610a47575f80fd5b50610427610a563660046142a1565b612a66565b348015610a66575f80fd5b50610427610a753660046141ba565b612b94565b348015610a85575f80fd5b50610427610a94366004614188565b612d4f565b348015610aa4575f80fd5b50610427610ab33660046142ca565b612d9f565b348015610ac3575f80fd5b506102f2610ad23660046141a3565b6101506020525f908152604090205460ff1681565b348015610af2575f80fd5b506103fa610b01366004613ebd565b612ec5565b348015610b11575f80fd5b5061013b5461013c5461013d54610b2792919083565b6040516102ca93929190614348565b348015610b41575f80fd5b506103fa610b5036600461435e565b612ef1565b348015610b60575f80fd5b50610b69612f1b565b6040516102ca91906143cc565b348015610b81575f80fd5b50610b27610b90366004613ebd565b61014c60209081525f928352604080842090915290825290208054600182015460029092015490919083565b348015610bc7575f80fd5b50610427610bd63660046141ba565b612f7b565b348015610be6575f80fd5b50610c42610bf5366004613ebd565b61014e60209081525f92835260408084209091529082529020805460018201546002830154600384015460048501546005909501546001600160a01b039094169492939192909160ff1686565b604080516001600160a01b03909716875260208701959095529385019290925260608401526080830152151560a082015260c0016102ca565b606060cc8054610c8a906143de565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb6906143de565b8015610d015780601f10610cd857610100808354040283529160200191610d01565b820191905f5260205f20905b815481529060010190602001808311610ce457829003601f168201915b5050505050905090565b5f33610d18818585612ff1565b60019150505b92915050565b610d2c613114565b61013954604051636d830c6160e11b81526001600160a01b039091169063db0618c290610d5f9085908590600401614416565b5f604051808303815f87803b158015610d76575f80fd5b505af1158015610d88573d5f803e3d5ffd5b505050505050565b5f806101336006015f9054906101000a90046001600160a01b03166001600160a01b031663bab2f5526040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0a9190614462565b90505f805b828111610eb957610139546101385460405163ba37b42960e01b8152600481018490523060248201526001600160a01b0391821660448201525f92919091169063ba37b429906064016040805180830381865afa158015610e72573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e969190614479565b509050610ea381846144af565b9250508080610eb1906144c2565b915050610e0f565b5092915050565b610ec8613114565b6001600160a01b0382165f908152610185602052604090819020805460ff1916831515179055517f2626e1501ac007a99ed3bca0402984dce31d222879c878c4a5fb3952b6733a0290610f1e90849084906144da565b60405180910390a15050565b61014a602052815f5260405f208181548110610f44575f80fd5b5f918252602090912060089091020180546001820154600283015460038401546004850154600586015460068701546007909701546001600160a01b0396871699509497509295919460ff808316956101009093049091169392911689565b610fab613114565b610144805460ff19168215151790556040517f0c941692f2150cd601667ca332b43d1248223903490578e29170f6286390c59090610fee90831515815260200190565b60405180910390a150565b6101458181548110611009575f80fd5b5f91825260209091200154905081565b5f33610d1881858561102b8383612ef1565b61103591906144af565b612ff1565b611042613114565b61104a613173565b565b611054613114565b61014280546001600160a01b0319166001600160a01b0383161790556040517f63cfbd3f699aee5839a268c3b8711c3401093dbe492882085f9659cca8be0b6f90610fee90839061422a565b6110a8613114565b6101438190556040518181527fdd22b11e8687e6bbbc986e7ee0c5076064ac56c77b65a633a0996595f327d5dd90602001610fee565b6001600160a01b0381165f90815261014a602052604081208054829182918291829188908110611110576111106144f5565b5f9182526020918290206040805161012081018252600890930290910180546001600160a01b03908116845260018201549484019490945260028101549183019190915260038101546060830152600481015460ff808216151560808501526101009182900490941660a0840152600582015460c0840152600682015460e084015260079091015490921615159181018290529150806111b1575080608001515b156111c8575f805f8094509450945094505061130a565b61013454604051631b49306160e01b81526001600160a01b038881166004830152602482018a90523060448301525f928392911690631b493061906064016040805180830381865afa158015611220573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112449190614479565b6101345461013854604051633cbc807760e21b81529395509193505f926001600160a01b039182169263f2f201dc926112829291169060040161422a565b602060405180830381865afa15801561129d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c19190614462565b90505f6112e0826101495487606001516131bf9092919063ffffffff16565b90505f6112fb6101495483876131bf9092919063ffffffff16565b99509097509295509093505050505b92959194509250565b6001600160a01b0381165f90815261014a60205260409020548290829082106113575760405162461bcd60e51b815260040161134e90614509565b60405180910390fd5b61135f6132aa565b610134546040805163aced166160e01b815290516001600160a01b039092169163aced1661916004808201926020929091908290030181865afa1580156113a8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113cc919061453e565b6001600160a01b0316336001600160a01b0316146114405760405162461bcd60e51b815260206004820152602b60248201527f416972507566663a206e6f7420616c6c6f77656420746f206c6971756964617460448201526a6520706f736974696f6e7360a81b606482015260840161134e565b6001600160a01b0383165f90815261014a6020526040812080548690811061146a5761146a6144f5565b5f9182526020909120600890910201600481015490915060ff16156114cf5760405162461bcd60e51b815260206004820152601b60248201527a105a5c941d59998e88105b1c9958591e481b1a5c5d5a59185d1959602a1b604482015260640161134e565b80546001600160a01b03166115245760405162461bcd60e51b815260206004820152601b60248201527a20b4b9283ab3331d1037379030b1ba34bb32903837b9b4ba34b7b760291b604482015260640161134e565b5f61152f86866110de565b505050905061153c613dfb565b611544613e31565b610143548310156115925760405162461bcd60e51b8152602060048201526018602482015277131a5c5d5a59185d1a5bdb881b9bdd081c995c5d5a5c995960421b604482015260640161134e565b60038401546115a18882613303565b61012f546003860154610136546115c6926001600160a01b0391821692911690613422565b5f61014f5f8a6001600160a01b03166001600160a01b031681526020019081526020015f208054905090505f61014e5f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f8381526020019081526020015f2090508a816002018190555082816003018190555081816001018190555089815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f816005015f6101000a81548160ff02191690831515021790555061014f5f8b6001600160a01b03166001600160a01b031681526020019081526020015f2082908060018154018082558091505060019003905f5260205f20015f9091909190915055338760040160016101000a8154816001600160a01b0302191690836001600160a01b031602179055508a8a6001600160a01b03167fd6da7d9908c68b91a918abe9a7b86a0342a4d1c9511463900fa6d653994ec4cf33428b600301548860405161175a94939291906001600160a01b0394909416845260208401929092526040830152606082015260800190565b60405180910390a3505050505050506117736001606555565b50505050565b610134546040805163aced166160e01b815290516001600160a01b039092169163aced1661916004808201926020929091908290030181865afa1580156117c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117e6919061453e565b6001600160a01b0316336001600160a01b03161461185d5760405162461bcd60e51b815260206004820152602e60248201527f416972507566663a206e6f7420616c6c6f77656420746f2066756c66696c6c2060448201526d31b637b9b2903837b9b4ba34b7b760911b606482015260840161134e565b6001600160a01b0383165f90815261014e602090815260408083208584529091529020600581015460ff16156118e65760405162461bcd60e51b815260206004820152602860248201527f416972507566663a20636c6f7365207265717565737420616c726561647920666044820152671d5b199a5b1b195960c21b606482015260840161134e565b6001600160a01b0384165f908152610183602090815260408083206002850154845290915290205460ff1661196b5760405162461bcd60e51b815260206004820152602560248201527f416972507566663a20636c6f73652072657175657374206973206e6f742070656044820152646e64696e6760d81b606482015260840161134e565b5f82116119c55760405162461bcd60e51b815260206004820152602260248201527f416972507566663a206c656e64696e6720726570617920616d6f756e74206973604482015261020360f41b606482015260840161134e565b80546001600160a01b0316611a1c5760405162461bcd60e51b815260206004820152601f60248201527f416972507566663a207265717565737420646f6573206e6f7420657869737400604482015260640161134e565b60028101546001600160a01b0385165f90815261014a60205260408120805483908110611a4b57611a4b6144f5565b5f9182526020909120600890910201600481015490915060ff16158015611a775750600781015460ff16155b611a935760405162461bcd60e51b815260040161134e90614559565b8060050154841015611af75760405162461bcd60e51b815260206004820152602760248201527f416972507566663a20696e636f7272656374206c656e64696e6720726570617960448201526608185b5bdd5b9d60ca1b606482015260840161134e565b61013354611b10906001600160a01b031633308761347f565b6101425461013354611b2f916001600160a01b039182169116866134b7565b61014254600582015460405163015cb0a560e01b81526001600160a01b039092169163015cb0a591611b6e918890600401918252602082015260400190565b6020604051808303815f875af1158015611b8a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bae9190614590565b506001600160a01b038681165f908152610184602090815260408083208684529091528120869055600783018054600160ff199182168117909255600385018390556005808601939093559186018054909216179055600482015461010090041615611c245760048101805460ff191660011790555b6004810154604080516001600160a01b03891681526020810188905290810186905260ff909116151560608201527f9ac90136167f31456475a696ff0118b2758335e9545cabf670484f25b0049c47906080015b60405180910390a1505050505050565b611c90613114565b61104a5f613552565b611ca1613114565b61104a6135a3565b6033546001600160a01b031690565b606060cd8054610c8a906143de565b611ccf6132aa565b335f908152610185602052604090205460ff16611d2e5760405162461bcd60e51b815260206004820152601d60248201527f416972507566663a206f6e6c7920616c6c6f77656420636c6f73657273000000604482015260640161134e565b61013b548110801590611d44575061013c548111155b611d9b5760405162461bcd60e51b815260206004820152602260248201527f416972507566663a206c65766572616765206973206f7574206f6620626f756e604482015261647360f01b606482015260840161134e565b61013d54341015611dfc5760405162461bcd60e51b815260206004820152602560248201527f416972507566663a206465706f736974206973206c657373207468616e206d696044820152646e696d756d60d81b606482015260840161134e565b6101485434905f908290611e1390829086906131bf565b611e1d91906145ab565b90505f8111611e6e5760405162461bcd60e51b815260206004820152601d60248201527f416972507566663a206c6576657261676564416d6f756e742069732030000000604482015260640161134e565b61014254604051632c6211d160e21b8152600481018390523060248201525f916001600160a01b03169063b1884744906044016020604051808303815f875af1158015611ebd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee19190614590565b905080611f2a5760405162461bcd60e51b8152602060048201526017602482015276105a5c941d59998e881b195b991a5b99c819985a5b1959604a1b604482015260640161134e565b61013354604051632e1a7d4d60e01b8152600481018490526001600160a01b0390911690632e1a7d4d906024015f604051808303815f87803b158015611f6e575f80fd5b505af1158015611f80573d5f803e3d5ffd5b505050505f611f998385611f9491906144af565b6135e0565b90505f8111611fe15760405162461bcd60e51b81526020600482015260146024820152730416972507566663a207374616b656420697320360641b604482015260640161134e565b335f81815261014a60209081526040808320548151610120810183528581528084018a90528083018b9052606081018790526080810185905260a0810185905260c0810189905260e08101829052610100810185905294845261014c8352818420818552835292819020610139548251635d597aa960e11b8152925194959491936001600160a01b039091169263bab2f55292600480830193928290030181865afa158015612092573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120b69190614462565b335f90815261014d60209081526040808320878452909152908190209190915542825561013454610142549151635d8de25560e11b81526001600160a01b039182169263bb1bc4aa9261210e9291169060040161422a565b602060405180830381865afa158015612129573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061214d9190614462565b6002820155335f90815261014d60209081526040808320868452825280832054835261015090915290205460ff166121e757335f90815261014d6020908152604080832086845282528083208054610145805460018181019092557fed95984add84c4014c7f9d66a1b73e788e2db64f5763fa861ad52da204f71b2b019190915590548452610150909252909120805460ff191690911790555b335f90815261014b602052604081205460ff161515900361226057335f81815261014b60205260408120805460ff19166001908117909155610146805491820181559091527ff865fb3f06685bbcb5a1c6d69424d51a154206a5b27ad97bd5fbd9c0b2a0878a0180546001600160a01b03191690911790555b335f81815261014a6020908152604080832080546001808201835591855293839020875160089095020180546001600160a01b0319166001600160a01b039586161781559287015190830155850151600282015560608501516003820155608085015160048201805460a08801516001600160a81b0319909116921515610100600160a81b031916929092176101009290941682029390931790925560c0850151600582015560e08501516006820155908401516007909101805460ff19169115159190911790556123329085613749565b6040805188815260208101869052428183015260608101859052608081018a9052905133917ff943cf10ef4d1e3239f4716ddecdf546e8ba8ab0e41deafd9a71a99936827e45919081900360a00190a25050505050505061062a6001606555565b335f81815261014a602052604090205482919082106123c45760405162461bcd60e51b815260040161134e90614509565b6123cc6132aa565b335f90815261014a602052604081208054859081106123ed576123ed6144f5565b5f9182526020909120600890910201600481015490915060ff161580156124195750600781015460ff16155b6124355760405162461bcd60e51b815260040161134e90614559565b5f8160030154116124995760405162461bcd60e51b815260206004820152602860248201527f416972507566663a20706f736974696f6e206973206e6f7420656e6f75676820604482015267746f20636c6f736560c01b606482015260840161134e565b80546001600160a01b031633146125015760405162461bcd60e51b815260206004820152602660248201527f416972507566663a206e6f7420616c6c6f77656420746f20636c6f736520706f60448201526539b4ba34b7b760d11b606482015260840161134e565b335f9081526101836020908152604080832087845290915290205460ff16156125775760405162461bcd60e51b815260206004820152602260248201527f416972507566663a20636c6f736520706f736974696f6e2069732070656e64696044820152616e6760f01b606482015260840161134e565b83612580613dfb565b612588613e31565b61259283336110de565b604086015260208501525080835261014354116125e85760405162461bcd60e51b81526020600482015260146024820152732bb0b4ba103337b9103634b8bab4b230ba34b7b760611b604482015260640161134e565b60038401546125f73382613303565b6101385460408051636b45965b60e11b815290515f926001600160a01b03169163d68b2cb69160048083019260209291908290030181865afa15801561263f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126639190614462565b61014954856020015161267691906145be565b61268091906145e9565b905080866003015461269291906145ab565b6080850152335f81815261014f60208181526040808420805461014e84528286208187528452918520600281018c905560038101889055600180820184905581546001600160a01b031916909717815560058101805460ff1916905593835280549586018155845290832090930183905561012e54909190156127495761012e546101475460808901516127279290916131bf565b61012d5461013654919250612749916001600160a01b03908116911683613422565b80876080015161275991906145ab565b60408701819052895461013654612780926001600160a01b03918216929190911690613422565b61012f546101365461279f916001600160a01b03918216911686613422565b335f818152610183602090815260408083208c845282528083208054600160ff1990911681179091558d546001600160a01b0316845261014c83528184208d85528352928190204293810184905560038e015460028f015483518f8152948501919091528383015260608301899052608083019390935260a08201899052519192917f194c8d0132d20112211dfa71bb87a92766fde4f4318e08efd2cc4a6e188e509d9181900360c00190a25050505050505050505061285f6001606555565b505050565b5f33816128718286612ef1565b9050838110156128d15760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161134e565b6128de8286868403612ff1565b506001949350505050565b6128f1613114565b610147548511156129335760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964206665657360a01b604482015260640161134e565b62015f9083111561297c5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081b51995954195c98d95b9d606a1b604482015260640161134e565b61012d80546001600160a01b038881166001600160a01b0319928316811790935561012e88905561012f80548883169084168117909155610131805492871692909316919091179091556101308590556101328390556040805192835260208301889052820152606081018290527fea2c2d9ff6a85c05d1354c4c00a91e3b9d080a0e04210dee967e63469a34ecdd90608001611c78565b612a1c613114565b610144805462ff0000191662010000831515021790556040517f412fd56d2370889482e86e6b548521900ac7d783389c28e1430bcdcf6b9f328990610fee90831515815260200190565b612a6e613114565b6103e88310158015612a825750613a988211155b612ad95760405162461bcd60e51b815260206004820152602260248201527f416972507566663a20696e636f7272656374206c6576657261676520626f756e604482015261647360f01b606482015260840161134e565b818310612b415760405162461bcd60e51b815260206004820152603060248201527f416972507566663a206d696e4c6576657261676520697320677265617465722060448201526f7468616e206d61784c6576657261676560801b606482015260840161134e565b61013b83905561013c82905561013d8190556040517f4f82863f56b6abfad6bb6faec52dcd9ab3f799d81d87438a7e3d75f71bbe653890612b8790859085908590614348565b60405180910390a1505050565b5f54610100900460ff1615808015612bb257505f54600160ff909116105b80612bd25750612bc1306137f5565b158015612bd257505f5460ff166001145b612c355760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161134e565b5f805460ff191660011790558015612c56575f805461ff0019166101001790555b61013380546001600160a01b0384166001600160a01b0319918216811790925561013580549091169091179055620186a0610147556103e861014855670de0b6b3a764000061014955612ca7613804565b612caf613832565b612cb7613860565b612d0e60405180604001604052806016815260200175082d2e4a0eacccc5a8ad2cecadca0d2cadae6ee8aa8960531b815250604051806040016040528060078152602001660c4dae6ee8aa8960cb1b81525061388e565b801561080d575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610f1e565b612d57613114565b610144805461ff001916610100831515021790556040517f584f3e4b3d70055b45e1922c8712e5a5b3eaa02883013fa0f74ea0dfcfb1221090610fee90831515815260200190565b612da7613114565b61013480546001600160a01b03199081166001600160a01b03898116919091179092556101368054821688841617905561013780548216878416179055610138805482168684161790556101398054821685841617905561013a8054909116918316918217905560405163a22cb46560e01b815263a22cb46590612e329084906001906004016144da565b5f604051808303815f87803b158015612e49575f80fd5b505af1158015612e5b573d5f803e3d5ffd5b5050604080516001600160a01b03808b168252808a166020830152808916928201929092528187166060820152818616608082015290841660a08201527ff38e8910932afd378baa3865f321215fda176698b19175dd2d62d242b53acfc8925060c0019050611c78565b61014f602052815f5260405f208181548110612edf575f80fd5b905f5260205f20015f91509150505481565b6001600160a01b039182165f90815260ca6020908152604080832093909416825291909152205490565b6060610146805480602002602001604051908101604052809291908181526020018280548015610d0157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311612f54575050505050905090565b612f83613114565b6001600160a01b038116612fe85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161134e565b61062a81613552565b6001600160a01b0383166130535760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161134e565b6001600160a01b0382166130b45760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161134e565b6001600160a01b038381165f81815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b3361311d611ca9565b6001600160a01b03161461104a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161134e565b61317b6138be565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516131b5919061422a565b60405180910390a1565b5f80805f19858709858702925082811083820303915050805f036131f6578382816131ec576131ec6145d5565b04925050506132a3565b80841161323d5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161134e565b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6002606554036132fc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161134e565b6002606555565b6001600160a01b0382166133635760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161134e565b6001600160a01b0382165f90815260c96020526040902054818110156133d65760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161134e565b6001600160a01b0383165f81815260c960209081526040808320868603905560cb80548790039055518581529192915f80516020614788833981519152910160405180910390a3505050565b61285f8363a9059cbb60e01b8484604051602401613441929190614608565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613907565b6001606555565b6040516001600160a01b03808516602483015283166044820152606481018290526117739085906323b872dd60e01b90608401613441565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015613504573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135289190614462565b90506117738463095ea7b360e01b8561354186866144af565b604051602401613441929190614608565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6135ab6139da565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586131a83390565b610138546040516370a0823160e01b81525f9182916001600160a01b03909116906370a082319061361590309060040161422a565b602060405180830381865afa158015613630573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136549190614462565b6101385460408051630d0e30db60e41b815290519293506001600160a01b039091169163d0e30db09186916004808301925f92919082900301818588803b15801561369d575f80fd5b505af11580156136af573d5f803e3d5ffd5b5050610138546040516370a0823160e01b81525f94506001600160a01b0390911692506370a0823191506136e790309060040161422a565b602060405180830381865afa158015613702573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137269190614462565b90505f61373383836145ab565b90505f61373f82613a20565b9695505050505050565b6001600160a01b03821661379f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161134e565b8060cb5f8282546137b091906144af565b90915550506001600160a01b0382165f81815260c960209081526040808320805486019055518481525f80516020614788833981519152910160405180910390a35050565b6001600160a01b03163b151590565b5f54610100900460ff1661382a5760405162461bcd60e51b815260040161134e90614621565b61104a613bad565b5f54610100900460ff166138585760405162461bcd60e51b815260040161134e90614621565b61104a613bdc565b5f54610100900460ff166138865760405162461bcd60e51b815260040161134e90614621565b61104a613c0e565b5f54610100900460ff166138b45760405162461bcd60e51b815260040161134e90614621565b61080d8282613c34565b60975460ff1661104a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161134e565b5f61395b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613c739092919063ffffffff16565b905080515f148061397b57508080602001905181019061397b9190614590565b61285f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161134e565b60975460ff161561104a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161134e565b61013754610138545f91613a41916001600160a01b039081169116846134b7565b610136546040516370a0823160e01b81525f916001600160a01b0316906370a0823190613a7290309060040161422a565b602060405180830381865afa158015613a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ab19190614462565b61013754610138546040516305d7c0f960e31b81526001600160a01b03918216600482015260248101879052604481018790525f60648201529293501690632ebe07c8906084015f604051808303815f87803b158015613b0f575f80fd5b505af1158015613b21573d5f803e3d5ffd5b5050610136546040516370a0823160e01b81525f93506001600160a01b0390911691506370a0823190613b5890309060040161422a565b602060405180830381865afa158015613b73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b979190614462565b90505f613ba483836145ab565b95945050505050565b5f54610100900460ff16613bd35760405162461bcd60e51b815260040161134e90614621565b61104a33613552565b5f54610100900460ff16613c025760405162461bcd60e51b815260040161134e90614621565b6097805460ff19169055565b5f54610100900460ff166134785760405162461bcd60e51b815260040161134e90614621565b5f54610100900460ff16613c5a5760405162461bcd60e51b815260040161134e90614621565b60cc613c6683826146b1565b5060cd61285f82826146b1565b6060613c8184845f85613c89565b949350505050565b606082471015613cea5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161134e565b5f80866001600160a01b03168587604051613d05919061476c565b5f6040518083038185875af1925050503d805f8114613d3f576040519150601f19603f3d011682016040523d82523d5f602084013e613d44565b606091505b5091509150613d5587838387613d60565b979650505050505050565b60608315613dcc5782515f03613dc557613d79856137f5565b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161134e565b5081613c81565b613c818383815115613de15781518083602001fd5b8060405162461bcd60e51b815260040161134e9190613e77565b6040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b60405180608001604052805f81526020015f81526020015f81526020015f81525090565b5f5b83811015613e6f578181015183820152602001613e57565b50505f910152565b602081525f8251806020840152613e95816040850160208701613e55565b601f01601f19169190910160400192915050565b6001600160a01b038116811461062a575f80fd5b5f8060408385031215613ece575f80fd5b8235613ed981613ea9565b946020939093013593505050565b5f805f805f60808688031215613efb575f80fd5b8535613f0681613ea9565b94506020860135613f1681613ea9565b93506040860135925060608601356001600160401b0380821115613f38575f80fd5b818801915088601f830112613f4b575f80fd5b813581811115613f59575f80fd5b896020828501011115613f6a575f80fd5b9699959850939650602001949392505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613fb957613fb9613f7d565b604052919050565b5f6001600160401b03821115613fd957613fd9613f7d565b5060051b60200190565b5f82601f830112613ff2575f80fd5b8135602061400761400283613fc1565b613f91565b82815260059290921b84018101918181019086841115614025575f80fd5b8286015b8481101561404957803561403c81613ea9565b8352918301918301614029565b509695505050505050565b5f8060408385031215614065575f80fd5b82356001600160401b038082111561407b575f80fd5b818501915085601f83011261408e575f80fd5b8135602061409e61400283613fc1565b82815260059290921b840181019181810190898411156140bc575f80fd5b948201945b838610156140da578535825294820194908201906140c1565b965050860135925050808211156140ef575f80fd5b506140fc85828601613fe3565b9150509250929050565b801515811461062a575f80fd5b5f8060408385031215614124575f80fd5b823561412f81613ea9565b9150602083013561413f81614106565b809150509250929050565b5f805f6060848603121561415c575f80fd5b833561416781613ea9565b9250602084013561417781613ea9565b929592945050506040919091013590565b5f60208284031215614198575f80fd5b81356132a381614106565b5f602082840312156141b3575f80fd5b5035919050565b5f602082840312156141ca575f80fd5b81356132a381613ea9565b5f80604083850312156141e6575f80fd5b82359150602083013561413f81613ea9565b5f805f6060848603121561420a575f80fd5b833561421581613ea9565b95602085013595506040909401359392505050565b6001600160a01b0391909116815260200190565b5f805f805f8060c08789031215614253575f80fd5b863561425e81613ea9565b955060208701359450604087013561427581613ea9565b935060608701359250608087013561428c81613ea9565b8092505060a087013590509295509295509295565b5f805f606084860312156142b3575f80fd5b505081359360208301359350604090920135919050565b5f805f805f8060c087890312156142df575f80fd5b86356142ea81613ea9565b955060208701356142fa81613ea9565b9450604087013561430a81613ea9565b9350606087013561431a81613ea9565b9250608087013561432a81613ea9565b915060a087013561433a81613ea9565b809150509295509295509295565b9283526020830191909152604082015260600190565b5f806040838503121561436f575f80fd5b823561437a81613ea9565b9150602083013561413f81613ea9565b5f8151808452602080850194508084015f5b838110156143c15781516001600160a01b03168752958201959082019060010161439c565b509495945050505050565b602081525f6132a3602083018461438a565b600181811c908216806143f257607f821691505b60208210810361441057634e487b7160e01b5f52602260045260245ffd5b50919050565b604080825283519082018190525f906020906060840190828701845b8281101561444e57815184529284019290840190600101614432565b5050508381038285015261373f818661438a565b5f60208284031215614472575f80fd5b5051919050565b5f806040838503121561448a575f80fd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610d1e57610d1e61449b565b5f600182016144d3576144d361449b565b5060010190565b6001600160a01b039290921682521515602082015260400190565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f416972507566663a20706f736974696f6e4944206973206e6f742076616c6964604082015260600190565b5f6020828403121561454e575f80fd5b81516132a381613ea9565b6020808252601f908201527f416972507566663a20706f736974696f6e206973206e6f742061637469766500604082015260600190565b5f602082840312156145a0575f80fd5b81516132a381614106565b81810381811115610d1e57610d1e61449b565b8082028115828204841417610d1e57610d1e61449b565b634e487b7160e01b5f52601260045260245ffd5b5f8261460357634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160a01b03929092168252602082015260400190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561285f575f81815260208120601f850160051c810160208610156146925750805b601f850160051c820191505b81811015610d885782815560010161469e565b81516001600160401b038111156146ca576146ca613f7d565b6146de816146d884546143de565b8461466c565b602080601f831160018114614711575f84156146fa5750858301515b5f19600386901b1c1916600185901b178555610d88565b5f85815260208120601f198616915b8281101561473f57888601518255948401946001909101908401614720565b508582101561475c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f825161477d818460208701613e55565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122033d840f970503ae08224bc8a38cbb034b2b256b59c8b5926365dc0ebbe59cd2664736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.