Overview
MNT Balance
MNT Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
VotingEscrow
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 800 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {IERC721, IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC20} from "contracts/interfaces/IERC20.sol"; import {IVeArtProxy} from "contracts/interfaces/IVeArtProxy.sol"; import {IVotingEscrow} from "contracts/interfaces/IVotingEscrow.sol"; import {IVoter} from "contracts/interfaces/IVoter.sol"; /// @title Voting Escrow /// @notice veNFT implementation that escrows ERC-20 tokens in the form of an ERC-721 NFT /// @notice Votes have a weight depending on time, so that users are committed to the future of (whatever they are voting for) /// @author Modified from Solidly (https://github.com/solidlyexchange/solidly/blob/master/contracts/ve.sol) /// @author Modified from Curve (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy) /// @author Modified from Nouns DAO (https://github.com/withtally/my-nft-dao-project/blob/main/contracts/ERC721Checkpointable.sol) /// @dev Vote weight decays linearly over time. Lock time cannot be more than `MAXTIME` (4 years). contract VotingEscrow is IERC721, IERC721Metadata, Initializable { enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME, MERGE_TYPE, SPLIT_TYPE } struct LockedBalance { int128 amount; uint256 end; } struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } /* We cannot really do block numbers per se b/c slope is per time, not per block * and per block could be fairly bad b/c Ethereum changes blocktimes. * What we can do is to extrapolate ***At functions */ /// @notice A checkpoint for marking delegated tokenIds from a given timestamp struct Checkpoint { uint256 timestamp; uint256[] tokenIds; } /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit( address indexed provider, uint256 tokenId, uint256 value, uint256 indexed locktime, DepositType deposit_type, uint256 ts ); event Withdraw( address indexed provider, uint256 tokenId, uint256 value, uint256 ts ); event Supply(uint256 prevSupply, uint256 supply); event Delegate( address indexed owner, address indexed delegate, uint256 indexed tokenId ); event DelegateForAll( address indexed owner, address indexed delegate, bool approved ); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ address public emissionsToken; address public voter; address public team; address public artProxy; mapping(uint256 => Point) public pointHistory; // epoch -> unsigned point /// @dev Mapping of interface id to bool about whether or not it's supported mapping(bytes4 => bool) internal supportedInterfaces; /// @dev ERC165 interface ID of ERC165 bytes4 internal constant ERC165_INTERFACE_ID = 0x01ffc9a7; /// @dev ERC165 interface ID of ERC721 bytes4 internal constant ERC721_INTERFACE_ID = 0x80ac58cd; /// @dev ERC165 interface ID of ERC721Metadata bytes4 internal constant ERC721_METADATA_INTERFACE_ID = 0x5b5e139f; /// @dev Current count of token uint256 public latestTokenId; uint256 public epoch; uint256 internal constant WEEK = 1 weeks; /// @dev Max locking time for veNFTs uint256 public constant MAXTIME = 4 * 365 * 86400; uint256 internal constant MULTIPLIER = 1 ether; int128 internal constant iMAXTIME = 4 * 365 * 86400; uint8 internal constant _notEntered = 1; uint8 internal constant _entered = 2; uint8 internal _enteredState; uint8 public constant decimals = 18; string public constant name = "veCLEO"; string public constant symbol = "veCLEO"; string public constant version = "1.0.0"; /// @dev Mapping from NFT ID to the address that owns it. mapping(uint256 => address) internal idToOwner; /// @dev Mapping from owner address to count of his tokens. mapping(address => uint256) internal ownerToNFTokenCount; /// @dev Mapping from NFT ID to approved address. mapping(uint256 => address) internal idToApprovals; /// @dev Mapping from owner address to mapping of operator addresses. mapping(address => mapping(address => bool)) internal ownerToOperators; mapping(uint256 => uint256) public ownershipChange; /// @dev Mapping from owner address to mapping of index to tokenIds mapping(address => mapping(uint256 => uint256)) internal ownerToNFTokenIdList; /// @dev Mapping from NFT ID to index of owner mapping(uint256 => uint256) internal tokenToOwnerIndex; mapping(uint256 => uint256) public userPointEpoch; mapping(uint256 => Point[1000000000]) public userPointHistory; // user -> Point[user_epoch] mapping(uint256 => LockedBalance) public locked; mapping(uint256 => int128) public slopeChanges; // time -> signed slope change mapping(uint256 => uint256) public attachments; mapping(uint256 => bool) public voted; /// @notice tokenId -> delegate mapping(uint256 => address) public idToDelegate; /// @notice owner -> delegate, delegate all of owner's tokenIds mapping(address => mapping(address => bool)) delegateForAll; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256( "EIP712Domain(string name,uint256 chainId,address verifyingContract)" ); constructor() { _disableInitializers(); } function initialize( address _emissionsToken, address _artProxy, address _voter, address msig ) external initializer { emissionsToken = _emissionsToken; voter = _voter; team = msig; artProxy = _artProxy; pointHistory[0].blk = block.number; pointHistory[0].ts = block.timestamp; supportedInterfaces[ERC165_INTERFACE_ID] = true; supportedInterfaces[ERC721_INTERFACE_ID] = true; supportedInterfaces[ERC721_METADATA_INTERFACE_ID] = true; // mint-ish emit Transfer(address(0), address(this), latestTokenId); // burn-ish emit Transfer(address(this), address(0), latestTokenId); _enteredState = 1; } /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /// @dev reentrancy guard modifier nonreentrant() { require(_enteredState == _notEntered); _enteredState = _entered; _; _enteredState = _notEntered; } function setTeam(address _team) external { require(msg.sender == team); team = _team; } /// @dev Returns current token URI metadata /// @param _tokenId Token ID to fetch URI for. function tokenURI(uint256 _tokenId) external view returns (string memory) { require( idToOwner[_tokenId] != address(0), "Query for nonexistent token" ); LockedBalance memory _locked = locked[_tokenId]; return IVeArtProxy(artProxy)._tokenURI( _tokenId, _balanceOfNFT(_tokenId, block.timestamp), _locked.end, uint256(int256(_locked.amount)) ); } /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Returns the address of the owner of the NFT. /// @param _tokenId The identifier for an NFT. function ownerOf(uint256 _tokenId) public view returns (address) { return idToOwner[_tokenId]; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function _balance(address _owner) internal view returns (uint256) { return ownerToNFTokenCount[_owner]; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function balanceOf(address _owner) external view returns (uint256) { return _balance(_owner); } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Get the approved address for a single NFT. /// @param _tokenId ID of the NFT to query the approval of. function getApproved(uint256 _tokenId) external view returns (address) { return idToApprovals[_tokenId]; } /// @dev Checks if `_operator` is an approved operator for `_owner`. /// @param _owner The address that owns the NFTs. /// @param _operator The address that acts on behalf of the owner. function isApprovedForAll( address _owner, address _operator ) external view returns (bool) { return (ownerToOperators[_owner])[_operator]; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ /// @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address. /// Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. /// Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP) /// Throws if `_approved` is the current owner. (NOTE: This is not written the EIP) /// @param _approved Address to be approved for the given NFT ID. /// @param _tokenId ID of the token to be approved. function approve(address _approved, uint256 _tokenId) public { address owner = idToOwner[_tokenId]; // Throws if `_tokenId` is not a valid NFT require(owner != address(0)); // Throws if `_approved` is the current owner require(_approved != owner); // Check requirements bool senderIsOwner = (idToOwner[_tokenId] == msg.sender); bool senderIsApprovedForAll = (ownerToOperators[owner])[msg.sender]; require(senderIsOwner || senderIsApprovedForAll); // Set the approval idToApprovals[_tokenId] = _approved; emit Approval(owner, _approved, _tokenId); } /// @dev Enables or disables approval for a third party ("operator") to manage all of /// `msg.sender`'s assets. It also emits the ApprovalForAll event. /// Throws if `_operator` is the `msg.sender`. (NOTE: This is not written the EIP) /// @notice This works even if sender doesn't own any tokens at the time. /// @param _operator Address to add to the set of authorized operators. /// @param _approved True if the operators is approved, false to revoke approval. function setApprovalForAll(address _operator, bool _approved) external { // Throws if `_operator` is the `msg.sender` assert(_operator != msg.sender); ownerToOperators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /* TRANSFER FUNCTIONS */ /// @dev Clear an approval of a given address /// Throws if `_owner` is not the current owner. function _clearApproval(address _owner, uint256 _tokenId) internal { // Throws if `_owner` is not the current owner assert(idToOwner[_tokenId] == _owner); if (idToApprovals[_tokenId] != address(0)) { // Reset approvals idToApprovals[_tokenId] = address(0); } } /// @dev Returns whether the given spender can transfer a given token ID /// @param _spender address of the spender to query /// @param _tokenId uint ID of the token to be transferred /// @return bool whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token function _isApprovedOrOwner( address _spender, uint256 _tokenId ) internal view returns (bool) { address owner = idToOwner[_tokenId]; bool spenderIsOwner = owner == _spender; bool spenderIsApproved = _spender == idToApprovals[_tokenId]; bool spenderIsApprovedForAll = (ownerToOperators[owner])[_spender]; return spenderIsOwner || spenderIsApproved || spenderIsApprovedForAll; } function isApprovedOrOwner( address _spender, uint256 _tokenId ) external view returns (bool) { return _isApprovedOrOwner(_spender, _tokenId); } /// @dev Exeute transfer of a NFT. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the approved /// address for this NFT. (NOTE: `msg.sender` not allowed in internal function so pass `_sender`.) /// Throws if `_to` is the zero address. /// Throws if `_from` is not the current owner. /// Throws if `_tokenId` is not a valid NFT. function _transferFrom( address _from, address _to, uint256 _tokenId, address _sender ) internal { // Check for stale status require(!IVoter(voter).stale(_tokenId), "STALE"); require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached"); // Check requirements require(_isApprovedOrOwner(_sender, _tokenId)); // Clear approval. Throws if `_from` is not the current owner _clearApproval(_from, _tokenId); // clear delegate _resetDelegate(_tokenId); // Remove NFT. Throws if `_tokenId` is not a valid NFT _removeTokenFrom(_from, _tokenId); // Add NFT _addTokenTo(_to, _tokenId); // Set the block of ownership transfer (for Flash NFT protection) ownershipChange[_tokenId] = block.number; // Log the transfer emit Transfer(_from, _to, _tokenId); } /// @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else /// they maybe be permanently lost. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. function transferFrom( address _from, address _to, uint256 _tokenId ) external { _transferFrom(_from, _to, _tokenId, msg.sender); } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. function safeTransferFrom( address _from, address _to, uint256 _tokenId ) external { safeTransferFrom(_from, _to, _tokenId, ""); } function _isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// Throws if `_tokenID` is stale. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. /// @param _data Additional data with no specified format, sent in call to `_to`. function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes memory _data ) public { require(!IVoter(voter).stale(_tokenId), "STALE"); _transferFrom(_from, _to, _tokenId, msg.sender); if (_isContract(_to)) { // Throws if transfer destination is a contract which does not implement 'onERC721Received' try IERC721Receiver(_to).onERC721Received( msg.sender, _from, _tokenId, _data ) returns (bytes4 response) { if ( response != IERC721Receiver(_to).onERC721Received.selector ) { revert("ERC721: ERC721Receiver rejected tokens"); } } catch (bytes memory reason) { if (reason.length == 0) { revert( "ERC721: transfer to non ERC721Receiver implementer" ); } else { assembly { revert(add(32, reason), mload(reason)) } } } } } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ /// @dev Interface identification is specified in ERC-165. /// @param _interfaceID Id of the interface function supportsInterface( bytes4 _interfaceID ) external view returns (bool) { return supportedInterfaces[_interfaceID]; } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ /// @dev Get token by index function tokenOfOwnerByIndex( address _owner, uint256 _tokenIndex ) external view returns (uint256) { return ownerToNFTokenIdList[_owner][_tokenIndex]; } /// @dev Add a NFT to an index mapping to a given address /// @param _to address of the receiver /// @param _tokenId uint ID Of the token to be added function _addTokenToOwnerList(address _to, uint256 _tokenId) internal { uint256 current_count = _balance(_to); ownerToNFTokenIdList[_to][current_count] = _tokenId; tokenToOwnerIndex[_tokenId] = current_count; } /// @dev Add a NFT to a given address /// Throws if `_tokenId` is owned by someone. function _addTokenTo(address _to, uint256 _tokenId) internal { // Throws if `_tokenId` is owned by someone assert(idToOwner[_tokenId] == address(0)); // Change the owner idToOwner[_tokenId] = _to; // Update owner token index tracking _addTokenToOwnerList(_to, _tokenId); // Change count tracking ownerToNFTokenCount[_to] += 1; } /// @dev Function to mint tokens /// Throws if `_to` is zero address. /// Throws if `_tokenId` is owned by someone. /// @param _to The address that will receive the minted tokens. /// @param _tokenId The token id to mint. /// @return A boolean that indicates if the operation was successful. function _mint(address _to, uint256 _tokenId) internal returns (bool) { // Throws if `_to` is zero address assert(_to != address(0)); // Add NFT. Throws if `_tokenId` is owned by someone _addTokenTo(_to, _tokenId); emit Transfer(address(0), _to, _tokenId); return true; } /// @dev Remove a NFT from an index mapping to a given address /// @param _from address of the sender /// @param _tokenId uint ID Of the token to be removed function _removeTokenFromOwnerList( address _from, uint256 _tokenId ) internal { // Delete uint256 currentCount = _balance(_from) - 1; uint256 currentIndex = tokenToOwnerIndex[_tokenId]; if (currentCount == currentIndex) { // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentCount] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } else { uint256 lastTokenId = ownerToNFTokenIdList[_from][currentCount]; // Add // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentIndex] = lastTokenId; // update tokenToOwnerIndex tokenToOwnerIndex[lastTokenId] = currentIndex; // Delete // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentCount] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } } /// @dev Remove a NFT from a given address /// Throws if `_from` is not the current owner. function _removeTokenFrom(address _from, uint256 _tokenId) internal { // Throws if `_from` is not the current owner assert(idToOwner[_tokenId] == _from); // Change the owner idToOwner[_tokenId] = address(0); // Update owner token index tracking _removeTokenFromOwnerList(_from, _tokenId); // Change count tracking ownerToNFTokenCount[_from] -= 1; } function _burn(uint256 _tokenId) internal { require( _isApprovedOrOwner(msg.sender, _tokenId), "The caller is not the owner, nor given approval" ); address owner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // Remove token _removeTokenFrom(msg.sender, _tokenId); emit Transfer(owner, address(0), _tokenId); } /*////////////////////////////////////////////////////////////// ESCROW STORAGE //////////////////////////////////////////////////////////////*/ /*////////////////////////////////////////////////////////////// ESCROW LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Get the most recently recorded rate of voting power decrease for `_tokenId` /// @param _tokenId token of the NFT /// @return Value of the slope function getLastUserSlope(uint256 _tokenId) external view returns (int128) { uint256 uepoch = userPointEpoch[_tokenId]; return userPointHistory[_tokenId][uepoch].slope; } /// @notice Get the timestamp for checkpoint `_idx` for `_tokenId` /// @param _tokenId token of the NFT /// @param _idx User epoch number /// @return Epoch time of the checkpoint function userPointHistoryTs( uint256 _tokenId, uint256 _idx ) external view returns (uint256) { return userPointHistory[_tokenId][_idx].ts; } /// @notice Get timestamp when `_tokenId`'s lock finishes /// @param _tokenId User NFT /// @return Epoch time of the lock end function locked__end(uint256 _tokenId) external view returns (uint256) { return locked[_tokenId].end; } /// @notice Record global and per-user data to checkpoint /// @param _tokenId NFT token ID. No user checkpoint if 0 /// @param oldLocked Pevious locked amount / end lock time for the user /// @param newLocked New locked amount / end lock time for the user function _checkpoint( uint256 _tokenId, LockedBalance memory oldLocked, LockedBalance memory newLocked ) internal { Point memory uOld; Point memory uNew; int128 oldDSlope = 0; int128 newDSlope = 0; uint256 _epoch = epoch; if (_tokenId != 0) { // Calculate slopes and biases // Kept at zero when they have to if (oldLocked.end > block.timestamp && oldLocked.amount > 0) { uOld.slope = oldLocked.amount / iMAXTIME; uOld.bias = uOld.slope * int128(int256(oldLocked.end - block.timestamp)); } if (newLocked.end > block.timestamp && newLocked.amount > 0) { uNew.slope = newLocked.amount / iMAXTIME; uNew.bias = uNew.slope * int128(int256(newLocked.end - block.timestamp)); } // Read values of scheduled changes in the slope // old_locked.end can be in the past and in the future // new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros oldDSlope = slopeChanges[oldLocked.end]; if (newLocked.end != 0) { if (newLocked.end == oldLocked.end) { newDSlope = oldDSlope; } else { newDSlope = slopeChanges[newLocked.end]; } } } Point memory lastPoint = Point({ bias: 0, slope: 0, ts: block.timestamp, blk: block.number }); if (_epoch > 0) { lastPoint = pointHistory[_epoch]; } uint256 lastCheckpoint = lastPoint.ts; // initial_last_point is used for extrapolation to calculate block number // (approximately, for *At methods) and save them // as we cannot figure that out exactly from inside the contract Point memory initialLastPoint = lastPoint; uint256 blockSlope = 0; // dblock/dt if (block.timestamp > lastPoint.ts) { blockSlope = (MULTIPLIER * (block.number - lastPoint.blk)) / (block.timestamp - lastPoint.ts); } // If last point is already recorded in this block, slope=0 // But that's ok b/c we know the block in such case // Go over weeks to fill history and calculate what the current point is { uint256 tI = (lastCheckpoint / WEEK) * WEEK; for (uint256 i = 0; i < 255; i++) { // Hopefully it won't happen that this won't get used in 5 years! // If it does, users will be able to withdraw but vote weight will be broken tI += WEEK; int128 dSlope = 0; if (tI > block.timestamp) { tI = block.timestamp; } else { dSlope = slopeChanges[tI]; } lastPoint.bias -= lastPoint.slope * int128(int256(tI - lastCheckpoint)); lastPoint.slope += dSlope; if (lastPoint.bias < 0) { // This can happen lastPoint.bias = 0; } if (lastPoint.slope < 0) { // This cannot happen - just in case lastPoint.slope = 0; } lastCheckpoint = tI; lastPoint.ts = tI; lastPoint.blk = initialLastPoint.blk + (blockSlope * (tI - initialLastPoint.ts)) / MULTIPLIER; _epoch += 1; if (tI == block.timestamp) { lastPoint.blk = block.number; break; } else { pointHistory[_epoch] = lastPoint; } } } epoch = _epoch; // Now point_history is filled until t=now if (_tokenId != 0) { // If last point was in this block, the slope change has been applied already // But in such case we have 0 slope(s) lastPoint.slope += (uNew.slope - uOld.slope); lastPoint.bias += (uNew.bias - uOld.bias); if (lastPoint.slope < 0) { lastPoint.slope = 0; } if (lastPoint.bias < 0) { lastPoint.bias = 0; } } // Record the changed point into history pointHistory[_epoch] = lastPoint; if (_tokenId != 0) { // Schedule the slope changes (slope is going down) // We subtract new_user_slope from [new_locked.end] // and add old_user_slope to [old_locked.end] if (oldLocked.end > block.timestamp) { // old_dslope was <something> - u_old.slope, so we cancel that oldDSlope += uOld.slope; if (newLocked.end == oldLocked.end) { oldDSlope -= uNew.slope; // It was a new deposit, not extension } slopeChanges[oldLocked.end] = oldDSlope; } if (newLocked.end > block.timestamp) { if (newLocked.end > oldLocked.end) { newDSlope -= uNew.slope; // old slope disappeared at this point slopeChanges[newLocked.end] = newDSlope; } // else: we recorded it already in old_dslope } // Now handle user history uint256 userEpoch = userPointEpoch[_tokenId] + 1; userPointEpoch[_tokenId] = userEpoch; uNew.ts = block.timestamp; uNew.blk = block.number; userPointHistory[_tokenId][userEpoch] = uNew; } } /// @notice Deposit and lock tokens for a user /// @param _tokenId NFT that holds lock /// @param _value Amount to deposit /// @param unlockTime New time when to unlock the tokens, or 0 if unchanged /// @param lockedBalance Previous locked amount / timestamp /// @param depositType The type of deposit function _depositFor( uint256 _tokenId, uint256 _value, uint256 unlockTime, LockedBalance memory lockedBalance, DepositType depositType ) internal { LockedBalance memory _locked = lockedBalance; uint256 supplyBefore = supply(); LockedBalance memory oldLocked; (oldLocked.amount, oldLocked.end) = (_locked.amount, _locked.end); // Adding to existing lock, or if a lock is expired - creating a new one _locked.amount += int128(int256(_value)); if (unlockTime != 0) { _locked.end = unlockTime; } locked[_tokenId] = _locked; // Possibilities: // Both old_locked.end could be current or expired (>/< block.timestamp) // value == 0 (extend lock) or value > 0 (add to lock or extend lock) // _locked.end > block.timestamp (always) _checkpoint(_tokenId, oldLocked, _locked); address from = msg.sender; if ( _value != 0 && (depositType != DepositType.MERGE_TYPE && depositType != DepositType.SPLIT_TYPE) ) { assert( IERC20(emissionsToken).transferFrom(from, address(this), _value) ); } emit Deposit( from, _tokenId, _value, _locked.end, depositType, block.timestamp ); emit Supply(supplyBefore, supply()); } function blockNumber() external view returns (uint256) { return block.number; } /// @notice Record global data to checkpoint function checkpoint() external { _checkpoint(0, LockedBalance(0, 0), LockedBalance(0, 0)); } /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock /// @dev Anyone (even a smart contract) can deposit for someone else, but /// cannot extend their locktime and deposit for a brand new user /// @param _tokenId lock NFT /// @param _value Amount to add to user's lock function depositFor( uint256 _tokenId, uint256 _value ) external nonreentrant { LockedBalance memory _locked = locked[_tokenId]; require(_value > 0); // dev: need non-zero value require(_locked.amount > 0, "No existing lock found"); require( _locked.end > block.timestamp, "Cannot add to an expired lock. Withdraw" ); _depositFor(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE); } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function _createLock( uint256 _value, uint256 _lockDuration, address _to ) internal returns (uint256) { uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks require(_value > 0); // dev: need non-zero value require( unlockTime > block.timestamp, "Can only lock until time in the future" ); require( unlockTime <= block.timestamp + MAXTIME, "Voting lock can be 4 years max" ); ++latestTokenId; uint256 _tokenId = latestTokenId; _mint(_to, _tokenId); _depositFor( _tokenId, _value, unlockTime, locked[_tokenId], DepositType.CREATE_LOCK_TYPE ); return _tokenId; } /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) function createLock( uint256 _value, uint256 _lockDuration ) external nonreentrant returns (uint256) { return _createLock(_value, _lockDuration, msg.sender); } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function createLockFor( uint256 _value, uint256 _lockDuration, address _to ) external nonreentrant returns (uint256) { return _createLock(_value, _lockDuration, _to); } /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time /// @param _value Amount of tokens to deposit and add to the lock function increaseAmount( uint256 _tokenId, uint256 _value ) external nonreentrant { assert(_isApprovedOrOwner(msg.sender, _tokenId)); LockedBalance memory _locked = locked[_tokenId]; assert(_value > 0); // dev: need non-zero value require(_locked.amount > 0, "No existing lock found"); require( _locked.end > block.timestamp, "Cannot add to an expired lock. Withdraw" ); _depositFor( _tokenId, _value, 0, _locked, DepositType.INCREASE_LOCK_AMOUNT ); } /// @notice Extend the unlock time for `_tokenId` /// @param _lockDuration New number of seconds until tokens unlock function increaseUnlockTime( uint256 _tokenId, uint256 _lockDuration ) external nonreentrant { assert(_isApprovedOrOwner(msg.sender, _tokenId)); LockedBalance memory _locked = locked[_tokenId]; uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks require(_locked.end > block.timestamp, "Lock expired"); require(_locked.amount > 0, "Nothing is locked"); require(unlockTime > _locked.end, "Can only increase lock duration"); require( unlockTime <= block.timestamp + MAXTIME, "Voting lock can be 4 years max" ); _depositFor( _tokenId, 0, unlockTime, _locked, DepositType.INCREASE_UNLOCK_TIME ); } /// @notice Withdraw all tokens for `_tokenId` /// @dev Only possible if the lock has expired function withdraw(uint256 _tokenId) external nonreentrant { assert(_isApprovedOrOwner(msg.sender, _tokenId)); require( attachments[_tokenId] == 0 && !voted[_tokenId], "ATTACHED, reset votes and unboost liquidity" ); LockedBalance memory _locked = locked[_tokenId]; require(block.timestamp >= _locked.end, "!EXPIRED"); uint256 value = uint256(int256(_locked.amount)); locked[_tokenId] = LockedBalance(0, 0); uint256 supply_before = supply(); // old_locked can have either expired <= timestamp or zero end // _locked has only 0 end // Both can have >= 0 amount _checkpoint(_tokenId, _locked, LockedBalance(0, 0)); assert(IERC20(emissionsToken).transfer(msg.sender, value)); // Burn the NFT _burn(_tokenId); emit Withdraw(msg.sender, _tokenId, value, block.timestamp); emit Supply(supply_before, supply()); } /*/////////////////////////////////////////////////////////////// GAUGE VOTING STORAGE //////////////////////////////////////////////////////////////*/ // The following ERC20/minime-compatible methods are not real balanceOf and supply! // They measure the weights for the purpose of voting, so they don't represent // real coins. /// @notice Binary search to estimate timestamp for block number /// @param _block Block to find /// @param maxEpoch Don't go beyond this epoch /// @return Approximate timestamp for block function _findBlockEpoch( uint256 _block, uint256 maxEpoch ) internal view returns (uint256) { // Binary search uint256 _min = 0; uint256 _max = maxEpoch; for (uint256 i = 0; i < 128; i++) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint256 _mid = (_min + _max + 1) / 2; if (pointHistory[_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } return _min; } /// @notice Binary search to estimate epoch for timestamp /// @param _time timestamp to find /// @param maxEpoch Don't go beyond this epoch /// @return Approximate timestamp for block function _findTimeUserEpoch( uint256 _tokenId, uint256 _time, uint256 maxEpoch ) internal view returns (uint256) { // Binary search uint256 _min = 0; uint256 _max = maxEpoch; for (uint256 i = 0; i < 128; i++) { // Will be always enough for 256-bit numbers if (_min >= _max) { break; } uint256 _mid = (_min + _max + 1) / 2; if (userPointHistory[_tokenId][_mid].ts <= _time) { _min = _mid; } else { _max = _mid - 1; } } return _min; } /// @notice Get the current voting power for `_tokenId` /// @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility /// @param _tokenId NFT for lock /// @param _t Epoch time to return voting power at /// @return User voting power function _balanceOfNFT( uint256 _tokenId, uint256 _t ) internal view returns (uint256) { uint256 _epoch = userPointEpoch[_tokenId]; if (_epoch == 0) { return 0; } else { _epoch = _findTimeUserEpoch(_tokenId, _t, _epoch); Point memory lastPoint = userPointHistory[_tokenId][_epoch]; lastPoint.bias -= lastPoint.slope * int128(int256(_t) - int256(lastPoint.ts)); if (lastPoint.bias < 0) { lastPoint.bias = 0; } return uint256(int256(lastPoint.bias)); } } function balanceOfNFT(uint256 _tokenId) external view returns (uint256) { if (ownershipChange[_tokenId] == block.number) return 0; return _balanceOfNFT(_tokenId, block.timestamp); } function balanceOfNFTAt( uint256 _tokenId, uint256 _t ) external view returns (uint256) { return _balanceOfNFT(_tokenId, _t); } /// @notice Measure voting power of `_tokenId` at block height `_block` /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime /// @param _tokenId User's wallet NFT /// @param _block Block to calculate the voting power at /// @return Voting power function _balanceOfAtNFT( uint256 _tokenId, uint256 _block ) internal view returns (uint256) { // Copying and pasting totalSupply code because Vyper cannot pass by // reference yet assert(_block <= block.number); // Binary search uint256 _min = 0; uint256 _max = userPointEpoch[_tokenId]; for (uint256 i = 0; i < 128; i++) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint256 _mid = (_min + _max + 1) / 2; if (userPointHistory[_tokenId][_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } Point memory uPoint = userPointHistory[_tokenId][_min]; uint256 maxEpoch = epoch; uint256 _epoch = _findBlockEpoch(_block, maxEpoch); Point memory pointZero = pointHistory[_epoch]; uint256 dBlock = 0; uint256 dT = 0; if (_epoch < maxEpoch) { Point memory pointOne = pointHistory[_epoch + 1]; dBlock = pointOne.blk - pointZero.blk; dT = pointOne.ts - pointZero.ts; } else { dBlock = block.number - pointZero.blk; dT = block.timestamp - pointZero.ts; } uint256 blockTime = pointZero.ts; if (dBlock != 0) { blockTime += (dT * (_block - pointZero.blk)) / dBlock; } uPoint.bias -= uPoint.slope * int128(int256(blockTime - uPoint.ts)); if (uPoint.bias >= 0) { return uint256(uint128(uPoint.bias)); } else { return 0; } } function balanceOfAtNFT( uint256 _tokenId, uint256 _block ) external view returns (uint256) { return _balanceOfAtNFT(_tokenId, _block); } /// @notice Calculate total voting power at some point in the past /// @param _block Block to calculate the total voting power at /// @return Total voting power at `_block` function totalSupplyAt(uint256 _block) external view returns (uint256) { assert(_block <= block.number); uint256 _epoch = epoch; uint256 targetEpoch = _findBlockEpoch(_block, _epoch); Point memory point = pointHistory[targetEpoch]; uint256 dt = 0; if (targetEpoch < _epoch) { Point memory pointNext = pointHistory[targetEpoch + 1]; if (point.blk != pointNext.blk) { dt = ((_block - point.blk) * (pointNext.ts - point.ts)) / (pointNext.blk - point.blk); } } else { if (point.blk != block.number) { dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk); } } // Now dt contains info on how far are we beyond point return _supplyAt(point, point.ts + dt); } /// @notice Calculate total voting power at some point in the past /// @param point The point (bias/slope) to start search from /// @param t Time to calculate the total voting power at /// @return Total voting power at that time function _supplyAt( Point memory point, uint256 t ) internal view returns (uint256) { Point memory lastPoint = point; uint256 tI = (lastPoint.ts / WEEK) * WEEK; for (uint256 i = 0; i < 255; i++) { tI += WEEK; int128 dSlope = 0; if (tI > t) { tI = t; } else { dSlope = slopeChanges[tI]; } lastPoint.bias -= lastPoint.slope * int128(int256(tI - lastPoint.ts)); if (tI == t) { break; } lastPoint.slope += dSlope; lastPoint.ts = tI; } if (lastPoint.bias < 0) { lastPoint.bias = 0; } return uint256(uint128(lastPoint.bias)); } function totalSupply() external view returns (uint256) { return totalSupplyAtT(block.timestamp); } /// @notice Calculate total voting power /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility /// @return Total voting power function totalSupplyAtT(uint256 t) public view returns (uint256) { uint256 _epoch = epoch; Point memory lastPoint = pointHistory[_epoch]; return _supplyAt(lastPoint, t); } /// @notice Returns the total base tokens this Voting Escrow holds /// @return The balance of base tokens this contract holds function supply() public view returns (uint256) { return IERC20(emissionsToken).balanceOf(address(this)); } /*/////////////////////////////////////////////////////////////// GAUGE VOTING LOGIC //////////////////////////////////////////////////////////////*/ function voting(uint256 _tokenId) external { require(msg.sender == voter); voted[_tokenId] = true; } function abstain(uint256 _tokenId) external { require(msg.sender == voter); voted[_tokenId] = false; } function attach(uint256 _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] + 1; } function detach(uint256 _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] - 1; } function merge(uint256 _from, uint256 _to) external { require( !IVoter(voter).stale(_from) && !IVoter(voter).stale(_to), "!ACTIVE" ); require( attachments[_from] == 0 && !voted[_from], "ATTACHED, reset votes and unboost liquidity" ); require(_from != _to); require(_isApprovedOrOwner(msg.sender, _from)); require(_isApprovedOrOwner(msg.sender, _to)); LockedBalance memory _locked0 = locked[_from]; LockedBalance memory _locked1 = locked[_to]; uint256 value0 = uint256(int256(_locked0.amount)); uint256 end = _locked0.end >= _locked1.end ? _locked0.end : _locked1.end; locked[_from] = LockedBalance(0, 0); _checkpoint(_from, _locked0, LockedBalance(0, 0)); _burn(_from); _depositFor(_to, value0, end, _locked1, DepositType.MERGE_TYPE); } function split( uint256 _from, uint256 _amount ) external returns (uint256 newTokenId) { require(_amount > 0); require(!voted[_from], "VOTED, reset votes and try again"); require(_isApprovedOrOwner(msg.sender, _from)); LockedBalance memory initialLocked = locked[_from]; uint256 oldAmount = uint256(int256(initialLocked.amount)); require( initialLocked.end > block.timestamp, "Cannot add to an expired lock. Withdraw" ); require(_amount < oldAmount); LockedBalance memory newLocked; newLocked.amount = 0; newLocked.end = initialLocked.end; ++latestTokenId; _mint(msg.sender, latestTokenId); LockedBalance memory updatedLocked; updatedLocked.amount = int128(uint128(oldAmount - _amount)); updatedLocked.end = initialLocked.end; locked[_from] = updatedLocked; _checkpoint(_from, initialLocked, updatedLocked); _depositFor( latestTokenId, _amount, initialLocked.end, newLocked, DepositType.SPLIT_TYPE ); newTokenId = latestTokenId; } /// @notice delegate voting power of _tokenId to _operator /// @notice can only be called by owner function delegate(address _operator, uint256 _tokenId) external { address owner = idToOwner[_tokenId]; require(msg.sender == owner, "!owner"); idToDelegate[_tokenId] = _operator; emit Delegate(owner, _operator, _tokenId); } /// @notice delegate voting power of all tokenIds of msg.sender to _operator function setDelegateForAll(address _operator, bool _approved) external { require(_operator != msg.sender); delegateForAll[msg.sender][_operator] = _approved; emit DelegateForAll(msg.sender, _operator, _approved); } function _resetDelegate(uint256 _tokenId) internal { delete idToDelegate[_tokenId]; } /// @notice reset delegate for _tokenId /// @dev only for idToDelegate, to reset delegateFor all call setDelegateForAll(false) function resetDelegate(uint256 _tokenId) public { require(msg.sender == idToOwner[_tokenId], "!owner"); delete idToDelegate[_tokenId]; } function isDelegate( address _operator, uint256 _tokenId ) external view returns (bool) { address owner = idToOwner[_tokenId]; bool operatorIsDelegated = _operator == idToDelegate[_tokenId]; bool operatorIsDelegatedForAll = (delegateForAll[owner])[_operator]; return operatorIsDelegated || operatorIsDelegatedForAll; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/Address.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) || (!Address.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 v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IERC20 { function totalSupply() external view returns (uint256); function transfer( address recipient, uint256 amount ) external returns (bool); function decimals() external view returns (uint8); function symbol() external view returns (string memory); function balanceOf(address) external view returns (uint256); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); function allowance( address owner, address spender ) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); function name() external view returns (string memory); function burn(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IVeArtProxy { function _tokenURI( uint256 _tokenId, uint256 _balanceOf, uint256 _locked_end, uint256 _value ) external pure returns (string memory output); }
// SPDX-License-Identifier: MIT pragma solidity =0.7.6 || ^0.8.13; pragma abicoder v2; interface IVoter { function _ve() external view returns (address); function governor() external view returns (address); function emergencyCouncil() external view returns (address); function attachTokenToGauge(uint256 _tokenId, address account) external; function detachTokenFromGauge(uint256 _tokenId, address account) external; function emitDeposit( uint256 _tokenId, address account, uint256 amount ) external; function emitWithdraw( uint256 _tokenId, address account, uint256 amount ) external; function isWhitelisted(address token) external view returns (bool); function notifyRewardAmount(uint256 amount) external; function distribute(address _gauge) external; function gauges(address pool) external view returns (address); function feeDistributors(address gauge) external view returns (address); function gaugefactory() external view returns (address); function feeDistributorFactory() external view returns (address); function minter() external view returns (address); function factory() external view returns (address); function length() external view returns (uint256); function pools(uint256) external view returns (address); function isAlive(address) external view returns (bool); function setXRatio(uint256 _xRatio) external; function setGaugeXRatio( address[] calldata _gauges, uint256[] calldata _xRaRatios ) external; function resetGaugeXRatio(address[] calldata _gauges) external; function whitelist(address _token) external; function forbid(address _token, bool _status) external; function whitelistOperator() external view returns (address); function gaugeXRatio(address gauge) external view returns (uint256); function isGauge(address gauge) external view returns (bool); function killGauge(address _gauge) external; function reviveGauge(address _gauge) external; function stale(uint256 _tokenID) external view returns (bool); function partnerNFT(uint256 _tokenID) external view returns (bool); function addInitialRewardPerGauge(address _gauge, address token) external; function base() external view returns (address); function xToken() external view returns (address); function addClGaugeReward(address gauge, address reward) external; function removeClGaugeReward(address gauge, address reward) external; function clawBackUnusedEmissions(address[] calldata _gauges) external; }
// SPDX-License-Identifier: MIT pragma solidity =0.7.6 || ^0.8.13; pragma abicoder v2; interface IVotingEscrow { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } struct LockedBalance { int128 amount; uint256 end; } function emissionsToken() external view returns (address); function team() external returns (address); function epoch() external view returns (uint256); function pointHistory(uint256 loc) external view returns (Point memory); function userPointHistory( uint256 tokenId, uint256 loc ) external view returns (Point memory); function userPointEpoch(uint256 tokenId) external view returns (uint256); function ownerOf(uint256) external view returns (address); function isApprovedOrOwner(address, uint256) external view returns (bool); function transferFrom(address, address, uint256) external; function voting(uint256 tokenId) external; function abstain(uint256 tokenId) external; function attach(uint256 tokenId) external; function detach(uint256 tokenId) external; function checkpoint() external; function depositFor(uint256 tokenId, uint256 value) external; function createLockFor( uint256, uint256, address ) external returns (uint256); function balanceOfNFT(uint256) external view returns (uint256); function balanceOfNFTAt(uint256, uint256) external view returns (uint256); function totalSupply() external view returns (uint256); function locked__end(uint256) external view returns (uint256); function balanceOf(address) external view returns (uint256); function tokenOfOwnerByIndex( address, uint256 ) external view returns (uint256); function increaseUnlockTime(uint256 tokenID, uint256 duration) external; function locked( uint256 tokenID ) external view returns (uint256 amount, uint256 unlockTime); function increaseAmount(uint256 _tokenId, uint256 _value) external; function isDelegate( address _operator, uint256 _tokenId ) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 800 }, "evmVersion": "paris", "viaIR": true, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Delegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"DelegateForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"locktime","type":"uint256"},{"indexed":false,"internalType":"enum VotingEscrow.DepositType","name":"deposit_type","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"ts","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":"prevSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"Supply","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXTIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"abstain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"artProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"attach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"attachments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"balanceOfAtNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"balanceOfNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_t","type":"uint256"}],"name":"balanceOfNFTAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"}],"name":"createLock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"createLockFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"detach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emissionsToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getLastUserSlope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"idToDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"increaseAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"}],"name":"increaseUnlockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_emissionsToken","type":"address"},{"internalType":"address","name":"_artProxy","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"msig","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"isDelegate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"locked","outputs":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint256","name":"end","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"locked__end","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownershipChange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pointHistory","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"resetDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setDelegateForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_team","type":"address"}],"name":"setTeam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"slopeChanges","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"split","outputs":[{"internalType":"uint256","name":"newTokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"team","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_tokenIndex","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"t","type":"uint256"}],"name":"totalSupplyAtT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPointEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPointHistory","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"userPointHistoryTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"voted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"voting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60808060405234620000c6576000549060ff8260081c1662000074575060ff8082160362000038575b6040516147219081620000cc8239f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a13862000028565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610412578063026e402b1461040d578063047fc9aa1461040857806305ae4f8c1461040357806306fdde031461035e578063081812fc146103fe578063095cf5c6146103f9578063095ea7b3146103f45780630d6a2033146103ef5780630ec84dda146103ea57806318160ddd146103e55780631e077945146103e057806320606b70146103db578063210ca05d146103d657806323857d51146103d157806323b872dd146103cc5780632e1a7d4d146103c75780632f745c59146103c2578063313ce567146103bd57806342842e0e146103b8578063430c2081146103b357806344acb42a146103ae57806346c96aac146103a95780634b19becc146103a457806354fd4d501461039f5780635594a0451461039a5780635633e0a61461039557806357e871e7146103905780636352211e1461038b57806370a08231146103865780637116c60c1461038157806385f2aef21461037c5780638ad4c447146103775780638c0e8349146103725780638c2c9baf1461036d5780638fbb38ff14610368578063900cf0cf1461036357806395d89b411461035e578063981b24d014610359578063986b7d8a146103545780639d507b8b1461034f578063a22cb4651461034a578063b2383e5514610345578063b45a3c0e14610340578063b52c05fe1461033b578063b88d4fde14610336578063c1f0fb9f14610331578063c2c4c5c11461032c578063c87b56dd14610327578063ccc41a1114610322578063d1c2babb1461031d578063e0514aba14610318578063e58f594714610313578063e7e242d41461030e578063e985e9c514610309578063ec32e6df14610304578063ee00ef3a146102ff578063f487f26c146102fa578063f52a36f7146102f5578063f8a05763146102f0578063f8c8765e146102eb578063f8e3bf3c146102e6578063fbd3a29d146102e15763fd4a77f1146102dc57600080fd5b6121b8565b612167565b6120d2565b611fd0565b611fa1565b611f72565b611ee5565b611ec6565b611e80565b611e1e565b611e00565b611dd4565b611db3565b611bad565b611b78565b611a61565b6117bb565b61177d565b6116f4565b6116a4565b61166c565b6115da565b611530565b61143d565b6113e6565b611298565b6106d8565b61127a565b611249565b611228565b61120a565b6111a9565b611182565b611164565b61112a565b6110f5565b6110da565b611095565b61106e565b611010565b610ec4565b610e9d565b610e2f565b610dd1565b610d97565b610d7b565b610d33565b610ae5565b610aca565b610a69565b610a3f565b610a04565b6109b1565b610995565b6108f6565b6108ca565b6107b3565b61076f565b61073a565b610594565b610571565b6104e1565b610446565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361044157565b600080fd5b346104415760203660031901126104415760043561046381610417565b63ffffffff60e01b166000526005602052602060ff604060002054166040519015158152f35b600435906001600160a01b038216820361044157565b602435906001600160a01b038216820361044157565b604435906001600160a01b038216820361044157565b606435906001600160a01b038216820361044157565b34610441576040366003190112610441576104fa610489565b60243560009181835260096020526001600160a01b0380604085205416916105238333146121f9565b83855260166020526040852080546001600160a01b0319166001600160a01b03831617905516907f510b11bb3f3c799b11307c01ab7db0d335683ef5b2da98f7697de744f465eacc8480a480f35b3461044157600036600319011261044157602061058c612251565b604051908152f35b34610441576040366003190112610441576004356000526011602052602060016105c46024356040600020610e02565b500154604051908152f35b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761060157604052565b6105cf565b6080810190811067ffffffffffffffff82111761060157604052565b90601f8019910116810190811067ffffffffffffffff82111761060157604052565b60405190610651826105e5565b565b6040519061065182610606565b67ffffffffffffffff811161060157601f01601f191660200190565b60005b83811061068f5750506000910152565b818101518382015260200161067f565b906020916106b88151809281855285808601910161067c565b601f01601f1916010190565b9060206106d592818152019061069f565b90565b34610441576000366003190112610441576107366040516106f8816105e5565b600681527f7665434c454f0000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061069f565b0390f35b3461044157602036600319011261044157600435600052600b60205260206001600160a01b0360406000205416604051908152f35b3461044157602036600319011261044157610788610489565b600254906001600160a01b038083163303610441576001600160a01b03199116911617600255600080f35b34610441576040366003190112610441576107cc610489565b60243560009181835260096020526001600160a01b03806040852054169081156108c657808316928284146108c25761086461089392610816876000526009602052604060002090565b5416331460ff6108553361083d886001600160a01b0316600052600c602052604060002090565b906001600160a01b0316600052602052604060002090565b541681156108ba575b506122be565b61087885600052600b602052604060002090565b906001600160a01b03166001600160a01b0319825416179055565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b90503861085e565b8580fd5b8480fd5b346104415760203660031901126104415760043560005260146020526020604060002054604051908152f35b3461044157604036600319011261044157600435602435600854600160ff8216036104415760029060ff1916176008556000918083526012602052604083209160405191610943836105e5565b8460018554600f0b9586865201546020850190815283156109915761096f6109779261097c97136122e6565b514210612332565b612dea565b61098e600160ff196008541617600855565b80f35b5080fd5b3461044157600036600319011261044157602061058c426125a2565b346104415760203660031901126104415760043560009080825260096020526109e86001600160a01b0360408420541633146121f9565b81526016602052604081206001600160a01b0319815416905580f35b346104415760003660031901126104415760206040517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a8668152f35b346104415760003660031901126104415760206001600160a01b0360005460101c16604051908152f35b3461044157602036600319011261044157600435600052600d6020526020604060002054604051908152f35b6060906003190112610441576001600160a01b0390600435828116810361044157916024359081168103610441579060443590565b3461044157610ae3610adb36610a95565b90339261350e565b005b34610441576020806003193601126104415760043590600854600160ff8216036104415760ff1916600217600855610b25610b20833361365b565b6123a4565b610b39826000526014602052604060002090565b541580610d03575b610b4a906123c1565b610b66610b61836000526012602052604060002090565b6122c5565b610b7582820151421015612433565b610b89610b838251600f0b90565b600f0b90565b610b91610644565b93610bb96000958681528686820152610bb4836000526012602052604060002090565b61247f565b610bdc610bc4612251565b93610bcd610644565b908782528787830152836137d7565b610c03610bf7610bf787546001600160a01b039060101c1690565b6001600160a01b031690565b60405163a9059cbb60e01b815233600482015260248101849052908590829060449082908a905af1918215610cfe57610c797f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9493610ca3936000805160206146f5833981519152988a92610cd1575b50506123a4565b610c8281613d54565b60405191829133954291846040919493926060820195825260208201520152565b0390a2610cae612251565b60408051928352602083019190915290a161098e600160ff196008541617600855565b610cf09250803d10610cf7575b610ce88183610622565b8101906124b1565b3880610c72565b503d610cde565b612245565b50610b4a610d2c610d28610d21856000526015602052604060002090565b5460ff1690565b1590565b9050610b41565b34610441576040366003190112610441576001600160a01b03610d54610489565b16600052600e60205260406000206024356000526020526020604060002054604051908152f35b3461044157600036600319011261044157602060405160128152f35b3461044157610da536610a95565b60405191602083019383851067ffffffffffffffff86111761060157610ae39460405260008452612852565b34610441576040366003190112610441576020610df8610def610489565b6024359061365b565b6040519015158152f35b90633b9aca00811015610e19576003020190600090565b634e487b7160e01b600052603260045260246000fd5b34610441576040366003190112610441576024356004356000526011602052604060002090633b9aca0081101561044157610e6991610e02565b508054600182015460029092015460408051600f84810b8252608094851d900b602082015290810193909352606083015290f35b346104415760003660031901126104415760206001600160a01b0360015416604051908152f35b3461044157604036600319011261044157611002600435602435610ee98115156122be565b610f0b610f06610d28610d21856000526015602052604060002090565b6124c6565b610f1d610f18833361365b565b6122be565b610f34610b61836000526012602052604060002090565b90610ff7610f46610b838451600f0b90565b6020840193610f5785514210612332565b610f628285106122be565b610f6a612511565b956000875285516020880152610f89610f84600654612540565b600655565b610f9560065433613edf565b50610fd3610fcc610fbd610fb188610fab612511565b9761255e565b6001600160801b031690565b6001600160801b0316600f0b90565b600f0b8452565b85516020840152610ff283610bb4836000526012602052604060002090565b6137d7565b600654915191612f8c565b600654604051908152602090f35b3461044157600036600319011261044157610736604051611030816105e5565b600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061069f565b346104415760003660031901126104415760206001600160a01b0360035416604051908152f35b3461044157602036600319011261044157600435600052601060205260206110ca604060002054601183526040600020610e02565b505460801d60405190600f0b8152f35b34610441576000366003190112610441576020604051438152f35b3461044157602036600319011261044157600435600052600960205260206001600160a01b0360406000205416604051908152f35b34610441576020366003190112610441576001600160a01b0361114b610489565b16600052600a6020526020604060002054604051908152f35b3461044157602036600319011261044157602061058c6004356125a2565b346104415760003660031901126104415760206001600160a01b0360025416604051908152f35b3461044157602036600319011261044157600435600052600460205260406000208054610736600260018401549301546040519383859460801d90600f0b85909493926060926080830196600f0b8352600f0b602083015260408201520152565b34610441576000366003190112610441576020600654604051908152f35b3461044157604036600319011261044157602061058c602435600435614024565b34610441576020366003190112610441576004356000526015602052602060ff604060002054166040519015158152f35b34610441576000366003190112610441576020600754604051908152f35b34610441576020366003190112610441576107366113406004356112be438211156123a4565b61133a6007546112ce81846141fa565b926112eb6112e6856000526004602052604060002090565b61256b565b9360009281101561139a576112e661130561131592612626565b6000526004602052604060002090565b60608501908151606082019384518203611350575b50505050505b6040830151612655565b90613f29565b6040519081529081906020820190565b61139095509161137a604061136c6113809461138a979661255e565b92015160408a01519061255e565b906125f3565b925190519061255e565b90612606565b388080808061132a565b5060608401908151904382036113b3575b505050611330565b6113de93506113c861138a926113d69261255e565b61137a60408801514261255e565b91514361255e565b3880806113ab565b34610441576020366003190112610441576004356001600160a01b0360015416330361044157600081815260146020526040812054909160001982019182116114385782526014602052604082205580f35b61252a565b346104415760403660031901126104415760085460043560001960ff8316016104415760026115149260ff19161760085561147b610b20823361365b565b806000526012602052604060002090600160405192611499846105e5565b8054600f0b8452015490602083019182526114fb6114cd6114c86114bf60243542612655565b62093a80900490565b6125c3565b926114da42825111612662565b6114f360006114ea8751600f0b90565b600f0b136126ae565b5183116126fa565b61150f61150742612634565b831115612746565b6130ef565b610ae3600160ff196008541617600855565b8015150361044157565b3461044157604036600319011261044157611549610489565b60243561155581611526565b6115aa816115996001600160a01b03851694611573338714156123a4565b33600052600c6020526040600020906001600160a01b0316600052602052604060002090565b9060ff801983541691151516179055565b60405190151581527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b346104415760403660031901126104415760085460043560243560001960ff8416016104415760026115149360ff19161760085561161b610b20833361365b565b81600052601260205260406000209161166760016040519461163c866105e5565b8054600f0b86520154602085019081526116578415156123a4565b61096f60008651600f0b136122e6565b6131bd565b3461044157602036600319011261044157600435600052601260205260408060002060018154600f0b91015482519182526020820152f35b3461044157604036600319011261044157600854600160ff8216036104415760ff1990811660021760085560209060016116e333602435600435614278565b916008541617600855604051908152f35b346104415760803660031901126104415761170d610489565b61171561049f565b6064359167ffffffffffffffff831161044157366023840112156104415782600401359161174283610660565b926117506040519485610622565b8084523660248287010111610441576020816000926024610ae39801838801378501015260443591612852565b34610441576020366003190112610441576001600160a01b03600154163303610441576004356000908152601560205260409020805460ff19169055005b3461044157600080600319360112611a5e57604051906117da826105e5565b808252806020809301528060206040516117f3816105e5565b82815201526118006136d7565b506118096136d7565b5060075491611816610653565b908282528260208301524260408301526060914360608201529184611a3f575b60408301918251928592844211611a13575b96939061185c62093a8083959495046125c3565b9787985b60ff8a10611880575b8861098e8961187b8a61130581600755565b61374a565b61188a8991612645565b93888783964281116000146119d25750610b83966118e86118e16118fe946118dc6118d46118f7966118ce429e8f925b86019b6118c88d51600f0b90565b9361255e565b906136fc565b9151600f0b90565b613713565b600f0b8d52565b8351600f0b612db2565b612db2565b600f0b8252565b8161190d610b838b51600f0b90565b126119ca575b81611922610b838351600f0b90565b126119c2575b5050829483835261196c82890197611965895161195f61195161194b8a8061255e565b8b6125f3565b670de0b6b3a7640000900490565b90612655565b8952612626565b99428503611993575050505050505061098e929361187b9143905290849338808080611869565b600191929394959697506119b58961187b8d6000526004602052604060002090565b0198959291909493611860565b528738611928565b818952611913565b96506118f7906118e86118e16118fe946118dc6118d48c6118ce610b83611a0d611a06846000526013602052604060002090565b54600f0b90565b986118ba565b9250611a39611a2e611a2960608801514361255e565b6125db565b61138a83514261255e565b92611848565b9150611a586112e6856000526004602052604060002090565b91611836565b80fd5b3461044157602036600319011261044157600435611aac6001600160a01b03611aa4611a97846000526009602052604060002090565b546001600160a01b031690565b161515612a74565b6000611ac5610b61836000526012602052604060002090565b611add610bf7610bf76003546001600160a01b031690565b611ae7428561437e565b611afa610b8360208501519451600f0b90565b94611b326040519687958694859463dd9ec14960e01b8652600486019094939260609260808301968352602083015260408201520152565b03915afa8015610cfe5761073691600091611b55575b50604051918291826106c4565b611b7291503d806000833e611b6a8183610622565b810190612ac0565b38611b48565b3461044157602036600319011261044157600435600052601660205260206001600160a01b0360406000205416604051908152f35b346104415760403660031901126104415760043560243590611bdd610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b8082526004820184905293916020918281602481855afa908115610cfe57600091611d96575b50159485611d40575b5050611c25610ae394612b1f565b611c39836000526014602052604060002090565b541580611d1b575b611c4a906123c1565b611c56828414156122be565b611c63610f18843361365b565b611c70610f18833361365b565b611c87610b61846000526012602052604060002090565b91611d0e611ca2610b61836000526012602052604060002090565b94611d09611cb4610b838751600f0b90565b8686015188870151919691808210611d135750965b611cf2611cd4610644565b60008152600084820152610bb4866000526012602052604060002090565b6000611cfc610644565b92818452830152836137d7565b613d54565b6132c2565b905096611cc9565b50611c4a611d39610d28610d21866000526015602052604060002090565b9050611c41565b6040519081526004810184905294508190859060249082905afa938415610cfe57610ae394611c2591600091611d79575b501594611c17565b611d909150833d8511610cf757610ce88183610622565b38611d71565b611dad9150833d8511610cf757610ce88183610622565b38611c0e565b3461044157604036600319011261044157602061058c60243560043561437e565b346104415760203660031901126104415760043560005260106020526020604060002054604051908152f35b3461044157602036600319011261044157602061058c600435612b6b565b3461044157604036600319011261044157602060ff611e74611e3e610489565b6001600160a01b03611e4e61049f565b9116600052600c84526040600020906001600160a01b0316600052602052604060002090565b54166040519015158152f35b3461044157606036600319011261044157611e996104b5565b600854600160ff8216036104415760016116e3602093600260ff1980951617600855602435600435614278565b34610441576000366003190112610441576020604051630784ce008152f35b34610441576040366003190112610441576020611f00610489565b6024356000526009825260ff611f566001600160a01b03928360406000205416936016865280604060002054169082161493600052601785526040600020906001600160a01b0316600052602052604060002090565b54168115611f6a575b506040519015158152f35b905038611f5f565b346104415760203660031901126104415760043560005260136020526020604060002054600f0b604051908152f35b346104415760203660031901126104415760043560005260126020526020600160406000200154604051908152f35b3461044157608036600319011261044157611fe9610489565b612046611ff461049f565b611ffc6104b5565b6120046104cb565b916000549461202a60ff8760081c1615809781986120c4575b81156120a4575b50612b91565b8561203d600160ff196000541617600055565b61208b57612c03565b61204c57005b61205c61ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b61209f61010061ff00196000541617600055565b612c03565b303b159150816120b6575b5038612024565b6001915060ff1614386120af565b600160ff821610915061201d565b34610441576040366003190112610441576120eb610489565b6024356120f781611526565b6001600160a01b038216913383146104415781611599612137923360005260176020526040600020906001600160a01b0316600052602052604060002090565b60405190151581527f58781eab4a0743ab1c285a238be846a235f06cdb5b968030573a635e5f8c92fa60203392a3005b34610441576020366003190112610441576004356001600160a01b03600154163303610441576000908082526014602052604082205490600182018092116114385782526014602052604082205580f35b34610441576020366003190112610441576001600160a01b03600154163303610441576004356000908152601560205260409020805460ff19166001179055005b1561220057565b60405162461bcd60e51b815260206004820152600660248201527f216f776e657200000000000000000000000000000000000000000000000000006044820152606490fd5b6040513d6000823e3d90fd5b602460206001600160a01b0360005460101c16604051928380926370a0823160e01b82523060048301525afa908115610cfe5760009161228f575090565b90506020813d6020116122b6575b816122aa60209383610622565b81010312610441575190565b3d915061229d565b1561044157565b906040516122d2816105e5565b6020600182948054600f0b84520154910152565b156122ed57565b60405162461bcd60e51b815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006044820152606490fd5b1561233957565b60405162461bcd60e51b815260206004820152602760248201527f43616e6e6f742061646420746f20616e2065787069726564206c6f636b2e205760448201527f69746864726177000000000000000000000000000000000000000000000000006064820152608490fd5b156123ab57565b634e487b7160e01b600052600160045260246000fd5b156123c857565b60405162461bcd60e51b815260206004820152602b60248201527f41545441434845442c20726573657420766f74657320616e6420756e626f6f7360448201527f74206c69717569646974790000000000000000000000000000000000000000006064820152608490fd5b1561243a57565b60405162461bcd60e51b815260206004820152600860248201527f21455850495245440000000000000000000000000000000000000000000000006044820152606490fd5b9060206001916124aa8151600f0b85906001600160801b0319825416906001600160801b0316179055565b0151910155565b9081602091031261044157516106d581611526565b156124cd57565b606460405162461bcd60e51b815260206004820152602060248201527f564f5445442c20726573657420766f74657320616e642074727920616761696e6044820152fd5b6040519061251e826105e5565b60006020838281520152565b634e487b7160e01b600052601160045260246000fd5b60001981146114385760010190565b60001981019190821161143857565b9190820391821161143857565b9060405161257881610606565b606060028294805480600f0b855260801d600f0b6020850152600181015460408501520154910152565b6106d59060075460005260046020526125be604060002061256b565b613f29565b9062093a809182810292818404149015171561143857565b90670de0b6b3a7640000918083029283040361143857565b8181029291811591840414171561143857565b8115612610570490565b634e487b7160e01b600052601260045260246000fd5b906001820180921161143857565b90630784ce00820180921161143857565b9062093a80820180921161143857565b9190820180921161143857565b1561266957565b60405162461bcd60e51b815260206004820152600c60248201527f4c6f636b206578706972656400000000000000000000000000000000000000006044820152606490fd5b156126b557565b60405162461bcd60e51b815260206004820152601160248201527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006044820152606490fd5b1561270157565b60405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606490fd5b1561274d57565b60405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606490fd5b1561279957565b60405162461bcd60e51b815260206004820152600560248201527f5354414c450000000000000000000000000000000000000000000000000000006044820152606490fd5b9081602091031261044157516106d581610417565b90926106d594936080936001600160a01b0380921684521660208301526040820152816060820152019061069f565b3d1561284d573d9061283382610660565b916128416040519384610622565b82523d6000602084013e565b606090565b9193929061286e610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b815260048101879052602096918790829060249082905afa8015610cfe576128aa91600091612a57575b5015612792565b6128b63382848761350e565b813b6128c5575b505050509050565b9185916128f59360006001600160a01b03604051809781968295630a85bd0160e11b9b8c855233600486016127f3565b0393165af160009181612a28575b506129875783612911612822565b805191826129845760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b01fd5b9192507fffffffff00000000000000000000000000000000000000000000000000000000909116036129bd5780388080806128bd565b60405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a65637465642060448201527f746f6b656e7300000000000000000000000000000000000000000000000000006064820152608490fd5b612a49919250853d8711612a50575b612a418183610622565b8101906127de565b9038612903565b503d612a37565b612a6e9150883d8a11610cf757610ce88183610622565b386128a3565b15612a7b57565b60405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606490fd5b6020818303126104415780519067ffffffffffffffff8211610441570181601f82011215610441578051612af381610660565b92612b016040519485610622565b81845260208284010111610441576106d5916020808501910161067c565b15612b2657565b60405162461bcd60e51b815260206004820152600760248201527f21414354495645000000000000000000000000000000000000000000000000006044820152606490fd5b80600052600d6020526040600020544314612b8b576106d590429061437e565b50600090565b15612b9857565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608490fd5b92906000937fffffffffffffffffffff0000000000000000000000000000000000000000ffff75ffffffffffffffffffffffffffffffffffffffff000086549260101b1691161784556001600160a01b038092816001600160a01b031995168560015416176001551683600254161760025516906003541617600355436002612c96600080526004602052604060002090565b0155427f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed556301ffc9a760e01b6000526005602052612cfd7fc01909ce2b517f8cd3a46ae0cfde9179f9b675cf633d3d84c8226585cc73c1565b805460ff19166001179055565b6380ac58cd60e01b6000526005602052612d367f072ad3113145b5af48d301e3b9fc3bd1c97c3f26a14f5d44904b71469875631e612cf0565b635b5e139f60e01b6000526005602052612d6f7f3b767bd59d7164fff7ec5b80ca1165d9d6e12ee8656896fac4159b0760bfd9f7612cf0565b600654907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef823083838180a430908280a4610651600160ff196008541617600855565b90600f0b90600f0b01906f7fffffffffffffffffffffffffffffff1982126f7fffffffffffffffffffffffffffffff83131761143857565b612df2612251565b91612e5d612dfe612511565b94612e0a8151600f0b90565b95612e236020830197885160208401528290600f0b9052565b612e3f612e3885600f0b6118f28551600f0b90565b600f0b8352565b612e5782610bb4876000526012602052604060002090565b846137d7565b80151580612f84575b612ed5575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600060408201520152565b0390a3612ec2612251565b60408051928352602083019190915290a1565b612ef1610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f583398151915295612f5c612eb7926000805160206146d583398151915294600091612f65575b506123a4565b95505050612e6b565b612f7e915060203d602011610cf757610ce88183610622565b38612f56565b506001612e66565b90929192612ff6612f9b612251565b93612fa4612511565b8151600f0b96612fc26020840198895160208501528390600f0b9052565b612fd7610fcc86600f0b6118f28651600f0b90565b806130e7575b50612e5782610bb4876000526012602052604060002090565b801515806130df575b613050575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600560408201520152565b61306c610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956130d6612eb7926000805160206146d583398151915294600091612f6557506123a4565b95505050613004565b506000612fff565b875238612fdd565b9190916130fa612251565b91613103612511565b815191602081019283516020840152600f0b82528051600f0b916f7fffffffffffffffffffffffffffffff1983126f7fffffffffffffffffffffffffffffff841317611438576000805160206146f58339815191529661317d938352806131b55750612e5782610bb4876000526012602052604060002090565b519060405190815260006020820152600360408201524260608201526000805160206146d583398151915260803392a3612ec2612251565b845238612fdd565b6131c5612251565b916131d1612dfe612511565b801515806132ba575b61322b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600260408201520152565b613247610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956132b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506131df565b5060016131da565b909291926132d1612f9b612251565b801515806133ba575b61332b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600460408201520152565b613347610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956133b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506132df565b5060006132da565b909291926133d1612f9b612251565b801515806134ba575b61342b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600160408201520152565b613447610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956134b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506133df565b5060016133da565b156134c957565b60405162461bcd60e51b815260206004820152600860248201527f61747461636865640000000000000000000000000000000000000000000000006044820152606490fd5b9192613528610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b81526004810186905290602090829060249082905afa8015610cfe576135949261356a8792610f1894600091613642575015612792565b61357e826000526014602052604060002090565b54158061361d575b61358f906134c2565b61365b565b61359e8383614495565b6135bf83600052601660205260406000206001600160a01b03198154169055565b6135c983836144e5565b6135d3838261463e565b436135e884600052600d602052604060002090565b556001600160a01b0380911691167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4565b5061358f61363b610d28610d21856000526015602052604060002090565b9050613586565b612a6e915060203d602011610cf757610ce88183610622565b9060005260096020526001600160a01b039060ff6136b583604060002054169284811680851495600b602052604060002054161493600052600c6020526040600020906001600160a01b0316600052602052604060002090565b54169082156136cf575b5081156136ca575090565b905090565b9150386136bf565b604051906136e482610606565b60006060838281528260208201528260408201520152565b90600f0b90600f0b029081600f0b91820361143857565b600f91820b910b03906f7fffffffffffffffffffffffffffffff1982126f7fffffffffffffffffffffffffffffff83131761143857565b9060606002916137758151600f0b85906001600160801b0319825416906001600160801b0316179055565b602081015184546001600160801b031660809190911b6fffffffffffffffffffffffffffffffff1916178455604081015160018501550151910155565b91906137c1576106519161374a565b634e487b7160e01b600052600060045260246000fd5b6137df6136d7565b906137e86136d7565b926000806007549284151580613c16575b613801610653565b94600086526020956000878201524260408201526060904360608201529082613bf7575b60408201805191600091834211613bd0575b8a9061384c62093a80869896959495046125c3565b966000975b60ff8910613a96575b505050905061388e94508291508c8c8761387661187b96600755565b6139ed575b5050506000526004602052604060002090565b61389d575b5050505050505050565b613927976139219685808094019542875111613995575b5050500191825190428211613934575b505050505061391c6138e96138e3836000526010602052604060002090565b54612626565b91826138ff826000526010602052604060002090565b554260408601524360608601526000526011602052604060002090565b610e02565b906137b2565b3880808080808080613893565b5110613942575b80806138c4565b61395f6139719161395961398d95890151600f0b90565b90613713565b91516000526013602052604060002090565b906001600160801b0319825416906001600160801b0316179055565b38808061393b565b6139a86139ae926139cf940151600f0b90565b90612db2565b838301518651146139d7575b61397186516000526013602052604060002090565b3882816138b4565b6139e890613959858c0151600f0b90565b6139ba565b613a3d613a47916139596118d485613a36613a2f613a20613a148b613a4e9b0151600f0b90565b878c0151600f0b613959565b998d01996118f28b51600f0b90565b600f0b8952565b51600f0b90565b8651600f0b612db2565b600f0b8552565b6000613a5e610b838351600f0b90565b12613a8c575b506000613a75610b838551600f0b90565b12613a83575b888c8c61387b565b60008352613a7b565b6000905238613a64565b613a9f90612645565b60009042811115613ba057506118f7613aea916118e8613ae3613ad942985b8d01966118ce610b83613ad28a51600f0b90565b928c61255e565b8c51600f0b613713565b600f0b8b52565b6000613afa610b838951600f0b90565b12613b97575b6000613b10610b838351600f0b90565b12613b8d575b5081938282528c613b3982890197611965895161195f61195161194b8a8061255e565b98428503613b5e575050505050505061388e9261187b9143905290388981808061385a565b60019192939495969750613b808961187b8c6000526004602052604060002090565b0197959092919493613851565b6000905238613b16565b60008752613b00565b93613aea91506118f7906118e8613ae3613ad9613bca611a068a6000526013602052604060002090565b93613abe565b9150613bf1613be6611a2960608701514361255e565b61138a84514261255e565b91613837565b9050613c106112e6836000526004602052604060002090565b90613825565b602082018051421080613d3e575b613d05575b89896020820196428851119081613cee575b50613c9e575b5050613c5b611a0682516000526013602052604060002090565b94519081613c6b575b50506137f9565b51919350908103613c81575082915b3880613c64565b611a06613c98916000526013602052604060002090565b91613c7a565b613cd2613ce091613a366020613cc8613cbb613ce79751600f0b90565b630784ce0090600f0b0590565b600f0b9201918252565b6118ce610b83428a5161255e565b600f0b8a52565b8989613c41565b9050613cfe610b838451600f0b90565b1338613c3b565b613d39613a2f613d2b613d1c613cbb8751600f0b90565b600f0b60208c01908152613a36565b6118ce610b8342865161255e565b613c29565b5084613d4e610b838551600f0b90565b13613c24565b613d5e813361365b565b15613e74576001600160a01b0380613d80836000526009602052604060002090565b5416600091838352600960205280604084205416908115613e70573390613db1866000526009602052604060002090565b54161460ff613dd73361083d856001600160a01b0316600052600c602052604060002090565b54168115613e68575b5015613e6457828491613e10613e0084600052600b602052604060002090565b6001600160a01b03198154169055565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258280a4613e3e83336144e5565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4565b8280fd5b905038613de0565b8380fd5b60405162461bcd60e51b815260206004820152602f60248201527f5468652063616c6c6572206973206e6f7420746865206f776e65722c206e6f7260448201527f20676976656e20617070726f76616c00000000000000000000000000000000006064820152608490fd5b613efe826001600160a01b03831692613ef98415156123a4565b61463e565b60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600190565b9060408201613f3f6114c8825162093a80900490565b906000915b60ff8310613f80575b50505050610fb1610fb1826000613f6b610b836106d59651600f0b90565b12613f775751600f0b90565b60008152613a36565b613f8990612645565b6000929084811115614006575083925b6020860190613fd1613fca613fc0613fb28551600f0b90565b6118ce610b8389518b61255e565b8951600f0b613713565b600f0b8852565b858514613fff5781613fee613ff5926118f26001969551600f0b90565b600f0b9052565b8383520191613f44565b5050613f4d565b925061401f611a06846000526013602052604060002090565b613f99565b614030438311156123a4565b600090614047816000526010602052604060002090565b546000905b6080821061418a575b50506118f761411b61408561407f614125969561391c613a36966000526011602052604060002090565b5061256b565b936007549061409482826141fa565b6140ab6112e6826000526004602052604060002090565b92811015614166576112e66113056140c292612626565b906140e960406140db606085015160608701519061255e565b93015160408501519061255e565b905b6040840151938361413d575b505050506118ce610b8361410f6020880151600f0b90565b9260408801519061255e565b8351600f0b613713565b6000600f82900b12612b8b576001600160801b031690565b61195f9261137a61415d96959360606141589401519061255e565b612606565b388080806140f7565b5061417560608301514361255e565b9061418460408401514261255e565b906140eb565b9092818110156141f4576141af6141a96141a48484612655565b612626565b60011c90565b908560026141cb8461391c886000526011602052604060002090565b500154116141e05750600190935b019061404c565b9391506141ee60019161254f565b916141d9565b92614055565b60009182915b6080831061420f575b50505090565b9091928281101561427257828101808211611438576001808201809211611438571c90826002614249846000526004602052604060002090565b01541161425e5750600190935b019190614200565b93925061426c60019161254f565b92614256565b92614209565b904201908142116114385762093a8080920482810292818404149015171561143857801561044157428211156142fa576106d5916142c06142b842612634565b821115612746565b6142ce610f84600654612540565b6142db6006548095613edf565b506142f3610b61856000526012602052604060002090565b91846133c2565b60405162461bcd60e51b815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201527f66757475726500000000000000000000000000000000000000000000000000006064820152608490fd5b8181039291600013801582851316918412161761143857565b60008181526010602052604081205490918161439b575050905090565b829183905b60808210614427575b505091614402612e386143f86143d761407f6106d5989661391c610b83996000526011602052604060002090565b946118ce610b836143ec6020890151600f0b90565b92604089015190614365565b8451600f0b613713565b8061440e8351600f0b90565b600f0b1261441f575b5051600f0b90565b815238614417565b90928181101561448f578181019081811161143857600191828101809111611438578790831c926144668461391c886000526011602052604060002090565b5001541161447b5750600190935b01906143a0565b93915061448960019161254f565b91614474565b926143a9565b908060005260096020526144bc6001600160a01b03928380604060002054169116146123a4565b600052600b60205260406000209081549081166144d7575050565b6001600160a01b0319169055565b600082815260096020526001600160a01b0361450c816040842054169184168092146123a4565b838252600960205261452b604083206001600160a01b03198154169055565b8152600a6020526040812054600019810190811161143857838261455c6145c396600052600f602052604060002090565b548381036145d157506145986145a993614589876001600160a01b0316600052600e602052604060002090565b90600052602052604060002090565b55600052600f602052604060002090565b556001600160a01b0316600052600a602052604060002090565b6145cd815461254f565b9055565b83614598916146206145fd6145a9976145898b6001600160a01b0316600052600e602052604060002090565b5480614598846145898d6001600160a01b0316600052600e602052604060002090565b55614589876001600160a01b0316600052600e602052604060002090565b6146ca91600081815260209060098252600f6001600160a01b039260409361466b818686205416156123a4565b8584526009825284842080546001600160a01b0319166001600160a01b03891617905586168352600a81528383205494600e82528484208685528252808585205583525220556001600160a01b0316600052600a602052604060002090565b6145cd815461262656feff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6245e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5ca164736f6c6343000816000a
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610412578063026e402b1461040d578063047fc9aa1461040857806305ae4f8c1461040357806306fdde031461035e578063081812fc146103fe578063095cf5c6146103f9578063095ea7b3146103f45780630d6a2033146103ef5780630ec84dda146103ea57806318160ddd146103e55780631e077945146103e057806320606b70146103db578063210ca05d146103d657806323857d51146103d157806323b872dd146103cc5780632e1a7d4d146103c75780632f745c59146103c2578063313ce567146103bd57806342842e0e146103b8578063430c2081146103b357806344acb42a146103ae57806346c96aac146103a95780634b19becc146103a457806354fd4d501461039f5780635594a0451461039a5780635633e0a61461039557806357e871e7146103905780636352211e1461038b57806370a08231146103865780637116c60c1461038157806385f2aef21461037c5780638ad4c447146103775780638c0e8349146103725780638c2c9baf1461036d5780638fbb38ff14610368578063900cf0cf1461036357806395d89b411461035e578063981b24d014610359578063986b7d8a146103545780639d507b8b1461034f578063a22cb4651461034a578063b2383e5514610345578063b45a3c0e14610340578063b52c05fe1461033b578063b88d4fde14610336578063c1f0fb9f14610331578063c2c4c5c11461032c578063c87b56dd14610327578063ccc41a1114610322578063d1c2babb1461031d578063e0514aba14610318578063e58f594714610313578063e7e242d41461030e578063e985e9c514610309578063ec32e6df14610304578063ee00ef3a146102ff578063f487f26c146102fa578063f52a36f7146102f5578063f8a05763146102f0578063f8c8765e146102eb578063f8e3bf3c146102e6578063fbd3a29d146102e15763fd4a77f1146102dc57600080fd5b6121b8565b612167565b6120d2565b611fd0565b611fa1565b611f72565b611ee5565b611ec6565b611e80565b611e1e565b611e00565b611dd4565b611db3565b611bad565b611b78565b611a61565b6117bb565b61177d565b6116f4565b6116a4565b61166c565b6115da565b611530565b61143d565b6113e6565b611298565b6106d8565b61127a565b611249565b611228565b61120a565b6111a9565b611182565b611164565b61112a565b6110f5565b6110da565b611095565b61106e565b611010565b610ec4565b610e9d565b610e2f565b610dd1565b610d97565b610d7b565b610d33565b610ae5565b610aca565b610a69565b610a3f565b610a04565b6109b1565b610995565b6108f6565b6108ca565b6107b3565b61076f565b61073a565b610594565b610571565b6104e1565b610446565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361044157565b600080fd5b346104415760203660031901126104415760043561046381610417565b63ffffffff60e01b166000526005602052602060ff604060002054166040519015158152f35b600435906001600160a01b038216820361044157565b602435906001600160a01b038216820361044157565b604435906001600160a01b038216820361044157565b606435906001600160a01b038216820361044157565b34610441576040366003190112610441576104fa610489565b60243560009181835260096020526001600160a01b0380604085205416916105238333146121f9565b83855260166020526040852080546001600160a01b0319166001600160a01b03831617905516907f510b11bb3f3c799b11307c01ab7db0d335683ef5b2da98f7697de744f465eacc8480a480f35b3461044157600036600319011261044157602061058c612251565b604051908152f35b34610441576040366003190112610441576004356000526011602052602060016105c46024356040600020610e02565b500154604051908152f35b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761060157604052565b6105cf565b6080810190811067ffffffffffffffff82111761060157604052565b90601f8019910116810190811067ffffffffffffffff82111761060157604052565b60405190610651826105e5565b565b6040519061065182610606565b67ffffffffffffffff811161060157601f01601f191660200190565b60005b83811061068f5750506000910152565b818101518382015260200161067f565b906020916106b88151809281855285808601910161067c565b601f01601f1916010190565b9060206106d592818152019061069f565b90565b34610441576000366003190112610441576107366040516106f8816105e5565b600681527f7665434c454f0000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061069f565b0390f35b3461044157602036600319011261044157600435600052600b60205260206001600160a01b0360406000205416604051908152f35b3461044157602036600319011261044157610788610489565b600254906001600160a01b038083163303610441576001600160a01b03199116911617600255600080f35b34610441576040366003190112610441576107cc610489565b60243560009181835260096020526001600160a01b03806040852054169081156108c657808316928284146108c25761086461089392610816876000526009602052604060002090565b5416331460ff6108553361083d886001600160a01b0316600052600c602052604060002090565b906001600160a01b0316600052602052604060002090565b541681156108ba575b506122be565b61087885600052600b602052604060002090565b906001600160a01b03166001600160a01b0319825416179055565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b90503861085e565b8580fd5b8480fd5b346104415760203660031901126104415760043560005260146020526020604060002054604051908152f35b3461044157604036600319011261044157600435602435600854600160ff8216036104415760029060ff1916176008556000918083526012602052604083209160405191610943836105e5565b8460018554600f0b9586865201546020850190815283156109915761096f6109779261097c97136122e6565b514210612332565b612dea565b61098e600160ff196008541617600855565b80f35b5080fd5b3461044157600036600319011261044157602061058c426125a2565b346104415760203660031901126104415760043560009080825260096020526109e86001600160a01b0360408420541633146121f9565b81526016602052604081206001600160a01b0319815416905580f35b346104415760003660031901126104415760206040517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a8668152f35b346104415760003660031901126104415760206001600160a01b0360005460101c16604051908152f35b3461044157602036600319011261044157600435600052600d6020526020604060002054604051908152f35b6060906003190112610441576001600160a01b0390600435828116810361044157916024359081168103610441579060443590565b3461044157610ae3610adb36610a95565b90339261350e565b005b34610441576020806003193601126104415760043590600854600160ff8216036104415760ff1916600217600855610b25610b20833361365b565b6123a4565b610b39826000526014602052604060002090565b541580610d03575b610b4a906123c1565b610b66610b61836000526012602052604060002090565b6122c5565b610b7582820151421015612433565b610b89610b838251600f0b90565b600f0b90565b610b91610644565b93610bb96000958681528686820152610bb4836000526012602052604060002090565b61247f565b610bdc610bc4612251565b93610bcd610644565b908782528787830152836137d7565b610c03610bf7610bf787546001600160a01b039060101c1690565b6001600160a01b031690565b60405163a9059cbb60e01b815233600482015260248101849052908590829060449082908a905af1918215610cfe57610c797f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9493610ca3936000805160206146f5833981519152988a92610cd1575b50506123a4565b610c8281613d54565b60405191829133954291846040919493926060820195825260208201520152565b0390a2610cae612251565b60408051928352602083019190915290a161098e600160ff196008541617600855565b610cf09250803d10610cf7575b610ce88183610622565b8101906124b1565b3880610c72565b503d610cde565b612245565b50610b4a610d2c610d28610d21856000526015602052604060002090565b5460ff1690565b1590565b9050610b41565b34610441576040366003190112610441576001600160a01b03610d54610489565b16600052600e60205260406000206024356000526020526020604060002054604051908152f35b3461044157600036600319011261044157602060405160128152f35b3461044157610da536610a95565b60405191602083019383851067ffffffffffffffff86111761060157610ae39460405260008452612852565b34610441576040366003190112610441576020610df8610def610489565b6024359061365b565b6040519015158152f35b90633b9aca00811015610e19576003020190600090565b634e487b7160e01b600052603260045260246000fd5b34610441576040366003190112610441576024356004356000526011602052604060002090633b9aca0081101561044157610e6991610e02565b508054600182015460029092015460408051600f84810b8252608094851d900b602082015290810193909352606083015290f35b346104415760003660031901126104415760206001600160a01b0360015416604051908152f35b3461044157604036600319011261044157611002600435602435610ee98115156122be565b610f0b610f06610d28610d21856000526015602052604060002090565b6124c6565b610f1d610f18833361365b565b6122be565b610f34610b61836000526012602052604060002090565b90610ff7610f46610b838451600f0b90565b6020840193610f5785514210612332565b610f628285106122be565b610f6a612511565b956000875285516020880152610f89610f84600654612540565b600655565b610f9560065433613edf565b50610fd3610fcc610fbd610fb188610fab612511565b9761255e565b6001600160801b031690565b6001600160801b0316600f0b90565b600f0b8452565b85516020840152610ff283610bb4836000526012602052604060002090565b6137d7565b600654915191612f8c565b600654604051908152602090f35b3461044157600036600319011261044157610736604051611030816105e5565b600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015260405191829160208352602083019061069f565b346104415760003660031901126104415760206001600160a01b0360035416604051908152f35b3461044157602036600319011261044157600435600052601060205260206110ca604060002054601183526040600020610e02565b505460801d60405190600f0b8152f35b34610441576000366003190112610441576020604051438152f35b3461044157602036600319011261044157600435600052600960205260206001600160a01b0360406000205416604051908152f35b34610441576020366003190112610441576001600160a01b0361114b610489565b16600052600a6020526020604060002054604051908152f35b3461044157602036600319011261044157602061058c6004356125a2565b346104415760003660031901126104415760206001600160a01b0360025416604051908152f35b3461044157602036600319011261044157600435600052600460205260406000208054610736600260018401549301546040519383859460801d90600f0b85909493926060926080830196600f0b8352600f0b602083015260408201520152565b34610441576000366003190112610441576020600654604051908152f35b3461044157604036600319011261044157602061058c602435600435614024565b34610441576020366003190112610441576004356000526015602052602060ff604060002054166040519015158152f35b34610441576000366003190112610441576020600754604051908152f35b34610441576020366003190112610441576107366113406004356112be438211156123a4565b61133a6007546112ce81846141fa565b926112eb6112e6856000526004602052604060002090565b61256b565b9360009281101561139a576112e661130561131592612626565b6000526004602052604060002090565b60608501908151606082019384518203611350575b50505050505b6040830151612655565b90613f29565b6040519081529081906020820190565b61139095509161137a604061136c6113809461138a979661255e565b92015160408a01519061255e565b906125f3565b925190519061255e565b90612606565b388080808061132a565b5060608401908151904382036113b3575b505050611330565b6113de93506113c861138a926113d69261255e565b61137a60408801514261255e565b91514361255e565b3880806113ab565b34610441576020366003190112610441576004356001600160a01b0360015416330361044157600081815260146020526040812054909160001982019182116114385782526014602052604082205580f35b61252a565b346104415760403660031901126104415760085460043560001960ff8316016104415760026115149260ff19161760085561147b610b20823361365b565b806000526012602052604060002090600160405192611499846105e5565b8054600f0b8452015490602083019182526114fb6114cd6114c86114bf60243542612655565b62093a80900490565b6125c3565b926114da42825111612662565b6114f360006114ea8751600f0b90565b600f0b136126ae565b5183116126fa565b61150f61150742612634565b831115612746565b6130ef565b610ae3600160ff196008541617600855565b8015150361044157565b3461044157604036600319011261044157611549610489565b60243561155581611526565b6115aa816115996001600160a01b03851694611573338714156123a4565b33600052600c6020526040600020906001600160a01b0316600052602052604060002090565b9060ff801983541691151516179055565b60405190151581527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b346104415760403660031901126104415760085460043560243560001960ff8416016104415760026115149360ff19161760085561161b610b20833361365b565b81600052601260205260406000209161166760016040519461163c866105e5565b8054600f0b86520154602085019081526116578415156123a4565b61096f60008651600f0b136122e6565b6131bd565b3461044157602036600319011261044157600435600052601260205260408060002060018154600f0b91015482519182526020820152f35b3461044157604036600319011261044157600854600160ff8216036104415760ff1990811660021760085560209060016116e333602435600435614278565b916008541617600855604051908152f35b346104415760803660031901126104415761170d610489565b61171561049f565b6064359167ffffffffffffffff831161044157366023840112156104415782600401359161174283610660565b926117506040519485610622565b8084523660248287010111610441576020816000926024610ae39801838801378501015260443591612852565b34610441576020366003190112610441576001600160a01b03600154163303610441576004356000908152601560205260409020805460ff19169055005b3461044157600080600319360112611a5e57604051906117da826105e5565b808252806020809301528060206040516117f3816105e5565b82815201526118006136d7565b506118096136d7565b5060075491611816610653565b908282528260208301524260408301526060914360608201529184611a3f575b60408301918251928592844211611a13575b96939061185c62093a8083959495046125c3565b9787985b60ff8a10611880575b8861098e8961187b8a61130581600755565b61374a565b61188a8991612645565b93888783964281116000146119d25750610b83966118e86118e16118fe946118dc6118d46118f7966118ce429e8f925b86019b6118c88d51600f0b90565b9361255e565b906136fc565b9151600f0b90565b613713565b600f0b8d52565b8351600f0b612db2565b612db2565b600f0b8252565b8161190d610b838b51600f0b90565b126119ca575b81611922610b838351600f0b90565b126119c2575b5050829483835261196c82890197611965895161195f61195161194b8a8061255e565b8b6125f3565b670de0b6b3a7640000900490565b90612655565b8952612626565b99428503611993575050505050505061098e929361187b9143905290849338808080611869565b600191929394959697506119b58961187b8d6000526004602052604060002090565b0198959291909493611860565b528738611928565b818952611913565b96506118f7906118e86118e16118fe946118dc6118d48c6118ce610b83611a0d611a06846000526013602052604060002090565b54600f0b90565b986118ba565b9250611a39611a2e611a2960608801514361255e565b6125db565b61138a83514261255e565b92611848565b9150611a586112e6856000526004602052604060002090565b91611836565b80fd5b3461044157602036600319011261044157600435611aac6001600160a01b03611aa4611a97846000526009602052604060002090565b546001600160a01b031690565b161515612a74565b6000611ac5610b61836000526012602052604060002090565b611add610bf7610bf76003546001600160a01b031690565b611ae7428561437e565b611afa610b8360208501519451600f0b90565b94611b326040519687958694859463dd9ec14960e01b8652600486019094939260609260808301968352602083015260408201520152565b03915afa8015610cfe5761073691600091611b55575b50604051918291826106c4565b611b7291503d806000833e611b6a8183610622565b810190612ac0565b38611b48565b3461044157602036600319011261044157600435600052601660205260206001600160a01b0360406000205416604051908152f35b346104415760403660031901126104415760043560243590611bdd610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b8082526004820184905293916020918281602481855afa908115610cfe57600091611d96575b50159485611d40575b5050611c25610ae394612b1f565b611c39836000526014602052604060002090565b541580611d1b575b611c4a906123c1565b611c56828414156122be565b611c63610f18843361365b565b611c70610f18833361365b565b611c87610b61846000526012602052604060002090565b91611d0e611ca2610b61836000526012602052604060002090565b94611d09611cb4610b838751600f0b90565b8686015188870151919691808210611d135750965b611cf2611cd4610644565b60008152600084820152610bb4866000526012602052604060002090565b6000611cfc610644565b92818452830152836137d7565b613d54565b6132c2565b905096611cc9565b50611c4a611d39610d28610d21866000526015602052604060002090565b9050611c41565b6040519081526004810184905294508190859060249082905afa938415610cfe57610ae394611c2591600091611d79575b501594611c17565b611d909150833d8511610cf757610ce88183610622565b38611d71565b611dad9150833d8511610cf757610ce88183610622565b38611c0e565b3461044157604036600319011261044157602061058c60243560043561437e565b346104415760203660031901126104415760043560005260106020526020604060002054604051908152f35b3461044157602036600319011261044157602061058c600435612b6b565b3461044157604036600319011261044157602060ff611e74611e3e610489565b6001600160a01b03611e4e61049f565b9116600052600c84526040600020906001600160a01b0316600052602052604060002090565b54166040519015158152f35b3461044157606036600319011261044157611e996104b5565b600854600160ff8216036104415760016116e3602093600260ff1980951617600855602435600435614278565b34610441576000366003190112610441576020604051630784ce008152f35b34610441576040366003190112610441576020611f00610489565b6024356000526009825260ff611f566001600160a01b03928360406000205416936016865280604060002054169082161493600052601785526040600020906001600160a01b0316600052602052604060002090565b54168115611f6a575b506040519015158152f35b905038611f5f565b346104415760203660031901126104415760043560005260136020526020604060002054600f0b604051908152f35b346104415760203660031901126104415760043560005260126020526020600160406000200154604051908152f35b3461044157608036600319011261044157611fe9610489565b612046611ff461049f565b611ffc6104b5565b6120046104cb565b916000549461202a60ff8760081c1615809781986120c4575b81156120a4575b50612b91565b8561203d600160ff196000541617600055565b61208b57612c03565b61204c57005b61205c61ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b61209f61010061ff00196000541617600055565b612c03565b303b159150816120b6575b5038612024565b6001915060ff1614386120af565b600160ff821610915061201d565b34610441576040366003190112610441576120eb610489565b6024356120f781611526565b6001600160a01b038216913383146104415781611599612137923360005260176020526040600020906001600160a01b0316600052602052604060002090565b60405190151581527f58781eab4a0743ab1c285a238be846a235f06cdb5b968030573a635e5f8c92fa60203392a3005b34610441576020366003190112610441576004356001600160a01b03600154163303610441576000908082526014602052604082205490600182018092116114385782526014602052604082205580f35b34610441576020366003190112610441576001600160a01b03600154163303610441576004356000908152601560205260409020805460ff19166001179055005b1561220057565b60405162461bcd60e51b815260206004820152600660248201527f216f776e657200000000000000000000000000000000000000000000000000006044820152606490fd5b6040513d6000823e3d90fd5b602460206001600160a01b0360005460101c16604051928380926370a0823160e01b82523060048301525afa908115610cfe5760009161228f575090565b90506020813d6020116122b6575b816122aa60209383610622565b81010312610441575190565b3d915061229d565b1561044157565b906040516122d2816105e5565b6020600182948054600f0b84520154910152565b156122ed57565b60405162461bcd60e51b815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006044820152606490fd5b1561233957565b60405162461bcd60e51b815260206004820152602760248201527f43616e6e6f742061646420746f20616e2065787069726564206c6f636b2e205760448201527f69746864726177000000000000000000000000000000000000000000000000006064820152608490fd5b156123ab57565b634e487b7160e01b600052600160045260246000fd5b156123c857565b60405162461bcd60e51b815260206004820152602b60248201527f41545441434845442c20726573657420766f74657320616e6420756e626f6f7360448201527f74206c69717569646974790000000000000000000000000000000000000000006064820152608490fd5b1561243a57565b60405162461bcd60e51b815260206004820152600860248201527f21455850495245440000000000000000000000000000000000000000000000006044820152606490fd5b9060206001916124aa8151600f0b85906001600160801b0319825416906001600160801b0316179055565b0151910155565b9081602091031261044157516106d581611526565b156124cd57565b606460405162461bcd60e51b815260206004820152602060248201527f564f5445442c20726573657420766f74657320616e642074727920616761696e6044820152fd5b6040519061251e826105e5565b60006020838281520152565b634e487b7160e01b600052601160045260246000fd5b60001981146114385760010190565b60001981019190821161143857565b9190820391821161143857565b9060405161257881610606565b606060028294805480600f0b855260801d600f0b6020850152600181015460408501520154910152565b6106d59060075460005260046020526125be604060002061256b565b613f29565b9062093a809182810292818404149015171561143857565b90670de0b6b3a7640000918083029283040361143857565b8181029291811591840414171561143857565b8115612610570490565b634e487b7160e01b600052601260045260246000fd5b906001820180921161143857565b90630784ce00820180921161143857565b9062093a80820180921161143857565b9190820180921161143857565b1561266957565b60405162461bcd60e51b815260206004820152600c60248201527f4c6f636b206578706972656400000000000000000000000000000000000000006044820152606490fd5b156126b557565b60405162461bcd60e51b815260206004820152601160248201527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006044820152606490fd5b1561270157565b60405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606490fd5b1561274d57565b60405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606490fd5b1561279957565b60405162461bcd60e51b815260206004820152600560248201527f5354414c450000000000000000000000000000000000000000000000000000006044820152606490fd5b9081602091031261044157516106d581610417565b90926106d594936080936001600160a01b0380921684521660208301526040820152816060820152019061069f565b3d1561284d573d9061283382610660565b916128416040519384610622565b82523d6000602084013e565b606090565b9193929061286e610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b815260048101879052602096918790829060249082905afa8015610cfe576128aa91600091612a57575b5015612792565b6128b63382848761350e565b813b6128c5575b505050509050565b9185916128f59360006001600160a01b03604051809781968295630a85bd0160e11b9b8c855233600486016127f3565b0393165af160009181612a28575b506129875783612911612822565b805191826129845760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b01fd5b9192507fffffffff00000000000000000000000000000000000000000000000000000000909116036129bd5780388080806128bd565b60405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a65637465642060448201527f746f6b656e7300000000000000000000000000000000000000000000000000006064820152608490fd5b612a49919250853d8711612a50575b612a418183610622565b8101906127de565b9038612903565b503d612a37565b612a6e9150883d8a11610cf757610ce88183610622565b386128a3565b15612a7b57565b60405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606490fd5b6020818303126104415780519067ffffffffffffffff8211610441570181601f82011215610441578051612af381610660565b92612b016040519485610622565b81845260208284010111610441576106d5916020808501910161067c565b15612b2657565b60405162461bcd60e51b815260206004820152600760248201527f21414354495645000000000000000000000000000000000000000000000000006044820152606490fd5b80600052600d6020526040600020544314612b8b576106d590429061437e565b50600090565b15612b9857565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608490fd5b92906000937fffffffffffffffffffff0000000000000000000000000000000000000000ffff75ffffffffffffffffffffffffffffffffffffffff000086549260101b1691161784556001600160a01b038092816001600160a01b031995168560015416176001551683600254161760025516906003541617600355436002612c96600080526004602052604060002090565b0155427f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed556301ffc9a760e01b6000526005602052612cfd7fc01909ce2b517f8cd3a46ae0cfde9179f9b675cf633d3d84c8226585cc73c1565b805460ff19166001179055565b6380ac58cd60e01b6000526005602052612d367f072ad3113145b5af48d301e3b9fc3bd1c97c3f26a14f5d44904b71469875631e612cf0565b635b5e139f60e01b6000526005602052612d6f7f3b767bd59d7164fff7ec5b80ca1165d9d6e12ee8656896fac4159b0760bfd9f7612cf0565b600654907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef823083838180a430908280a4610651600160ff196008541617600855565b90600f0b90600f0b01906f7fffffffffffffffffffffffffffffff1982126f7fffffffffffffffffffffffffffffff83131761143857565b612df2612251565b91612e5d612dfe612511565b94612e0a8151600f0b90565b95612e236020830197885160208401528290600f0b9052565b612e3f612e3885600f0b6118f28551600f0b90565b600f0b8352565b612e5782610bb4876000526012602052604060002090565b846137d7565b80151580612f84575b612ed5575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600060408201520152565b0390a3612ec2612251565b60408051928352602083019190915290a1565b612ef1610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f583398151915295612f5c612eb7926000805160206146d583398151915294600091612f65575b506123a4565b95505050612e6b565b612f7e915060203d602011610cf757610ce88183610622565b38612f56565b506001612e66565b90929192612ff6612f9b612251565b93612fa4612511565b8151600f0b96612fc26020840198895160208501528390600f0b9052565b612fd7610fcc86600f0b6118f28651600f0b90565b806130e7575b50612e5782610bb4876000526012602052604060002090565b801515806130df575b613050575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600560408201520152565b61306c610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956130d6612eb7926000805160206146d583398151915294600091612f6557506123a4565b95505050613004565b506000612fff565b875238612fdd565b9190916130fa612251565b91613103612511565b815191602081019283516020840152600f0b82528051600f0b916f7fffffffffffffffffffffffffffffff1983126f7fffffffffffffffffffffffffffffff841317611438576000805160206146f58339815191529661317d938352806131b55750612e5782610bb4876000526012602052604060002090565b519060405190815260006020820152600360408201524260608201526000805160206146d583398151915260803392a3612ec2612251565b845238612fdd565b6131c5612251565b916131d1612dfe612511565b801515806132ba575b61322b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600260408201520152565b613247610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956132b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506131df565b5060016131da565b909291926132d1612f9b612251565b801515806133ba575b61332b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600460408201520152565b613347610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956133b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506132df565b5060006132da565b909291926133d1612f9b612251565b801515806134ba575b61342b575b6000805160206146d5833981519152612eb76000805160206146f58339815191529551936040519182913395429184606091949392608082019582526020820152600160408201520152565b613447610bf7610bf76000546001600160a01b039060101c1690565b6040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082906000905af18015610cfe576000805160206146f5833981519152956134b1612eb7926000805160206146d583398151915294600091612f6557506123a4565b955050506133df565b5060016133da565b156134c957565b60405162461bcd60e51b815260206004820152600860248201527f61747461636865640000000000000000000000000000000000000000000000006044820152606490fd5b9192613528610bf7610bf76001546001600160a01b031690565b604051635b2fa89360e11b81526004810186905290602090829060249082905afa8015610cfe576135949261356a8792610f1894600091613642575015612792565b61357e826000526014602052604060002090565b54158061361d575b61358f906134c2565b61365b565b61359e8383614495565b6135bf83600052601660205260406000206001600160a01b03198154169055565b6135c983836144e5565b6135d3838261463e565b436135e884600052600d602052604060002090565b556001600160a01b0380911691167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4565b5061358f61363b610d28610d21856000526015602052604060002090565b9050613586565b612a6e915060203d602011610cf757610ce88183610622565b9060005260096020526001600160a01b039060ff6136b583604060002054169284811680851495600b602052604060002054161493600052600c6020526040600020906001600160a01b0316600052602052604060002090565b54169082156136cf575b5081156136ca575090565b905090565b9150386136bf565b604051906136e482610606565b60006060838281528260208201528260408201520152565b90600f0b90600f0b029081600f0b91820361143857565b600f91820b910b03906f7fffffffffffffffffffffffffffffff1982126f7fffffffffffffffffffffffffffffff83131761143857565b9060606002916137758151600f0b85906001600160801b0319825416906001600160801b0316179055565b602081015184546001600160801b031660809190911b6fffffffffffffffffffffffffffffffff1916178455604081015160018501550151910155565b91906137c1576106519161374a565b634e487b7160e01b600052600060045260246000fd5b6137df6136d7565b906137e86136d7565b926000806007549284151580613c16575b613801610653565b94600086526020956000878201524260408201526060904360608201529082613bf7575b60408201805191600091834211613bd0575b8a9061384c62093a80869896959495046125c3565b966000975b60ff8910613a96575b505050905061388e94508291508c8c8761387661187b96600755565b6139ed575b5050506000526004602052604060002090565b61389d575b5050505050505050565b613927976139219685808094019542875111613995575b5050500191825190428211613934575b505050505061391c6138e96138e3836000526010602052604060002090565b54612626565b91826138ff826000526010602052604060002090565b554260408601524360608601526000526011602052604060002090565b610e02565b906137b2565b3880808080808080613893565b5110613942575b80806138c4565b61395f6139719161395961398d95890151600f0b90565b90613713565b91516000526013602052604060002090565b906001600160801b0319825416906001600160801b0316179055565b38808061393b565b6139a86139ae926139cf940151600f0b90565b90612db2565b838301518651146139d7575b61397186516000526013602052604060002090565b3882816138b4565b6139e890613959858c0151600f0b90565b6139ba565b613a3d613a47916139596118d485613a36613a2f613a20613a148b613a4e9b0151600f0b90565b878c0151600f0b613959565b998d01996118f28b51600f0b90565b600f0b8952565b51600f0b90565b8651600f0b612db2565b600f0b8552565b6000613a5e610b838351600f0b90565b12613a8c575b506000613a75610b838551600f0b90565b12613a83575b888c8c61387b565b60008352613a7b565b6000905238613a64565b613a9f90612645565b60009042811115613ba057506118f7613aea916118e8613ae3613ad942985b8d01966118ce610b83613ad28a51600f0b90565b928c61255e565b8c51600f0b613713565b600f0b8b52565b6000613afa610b838951600f0b90565b12613b97575b6000613b10610b838351600f0b90565b12613b8d575b5081938282528c613b3982890197611965895161195f61195161194b8a8061255e565b98428503613b5e575050505050505061388e9261187b9143905290388981808061385a565b60019192939495969750613b808961187b8c6000526004602052604060002090565b0197959092919493613851565b6000905238613b16565b60008752613b00565b93613aea91506118f7906118e8613ae3613ad9613bca611a068a6000526013602052604060002090565b93613abe565b9150613bf1613be6611a2960608701514361255e565b61138a84514261255e565b91613837565b9050613c106112e6836000526004602052604060002090565b90613825565b602082018051421080613d3e575b613d05575b89896020820196428851119081613cee575b50613c9e575b5050613c5b611a0682516000526013602052604060002090565b94519081613c6b575b50506137f9565b51919350908103613c81575082915b3880613c64565b611a06613c98916000526013602052604060002090565b91613c7a565b613cd2613ce091613a366020613cc8613cbb613ce79751600f0b90565b630784ce0090600f0b0590565b600f0b9201918252565b6118ce610b83428a5161255e565b600f0b8a52565b8989613c41565b9050613cfe610b838451600f0b90565b1338613c3b565b613d39613a2f613d2b613d1c613cbb8751600f0b90565b600f0b60208c01908152613a36565b6118ce610b8342865161255e565b613c29565b5084613d4e610b838551600f0b90565b13613c24565b613d5e813361365b565b15613e74576001600160a01b0380613d80836000526009602052604060002090565b5416600091838352600960205280604084205416908115613e70573390613db1866000526009602052604060002090565b54161460ff613dd73361083d856001600160a01b0316600052600c602052604060002090565b54168115613e68575b5015613e6457828491613e10613e0084600052600b602052604060002090565b6001600160a01b03198154169055565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258280a4613e3e83336144e5565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4565b8280fd5b905038613de0565b8380fd5b60405162461bcd60e51b815260206004820152602f60248201527f5468652063616c6c6572206973206e6f7420746865206f776e65722c206e6f7260448201527f20676976656e20617070726f76616c00000000000000000000000000000000006064820152608490fd5b613efe826001600160a01b03831692613ef98415156123a4565b61463e565b60007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600190565b9060408201613f3f6114c8825162093a80900490565b906000915b60ff8310613f80575b50505050610fb1610fb1826000613f6b610b836106d59651600f0b90565b12613f775751600f0b90565b60008152613a36565b613f8990612645565b6000929084811115614006575083925b6020860190613fd1613fca613fc0613fb28551600f0b90565b6118ce610b8389518b61255e565b8951600f0b613713565b600f0b8852565b858514613fff5781613fee613ff5926118f26001969551600f0b90565b600f0b9052565b8383520191613f44565b5050613f4d565b925061401f611a06846000526013602052604060002090565b613f99565b614030438311156123a4565b600090614047816000526010602052604060002090565b546000905b6080821061418a575b50506118f761411b61408561407f614125969561391c613a36966000526011602052604060002090565b5061256b565b936007549061409482826141fa565b6140ab6112e6826000526004602052604060002090565b92811015614166576112e66113056140c292612626565b906140e960406140db606085015160608701519061255e565b93015160408501519061255e565b905b6040840151938361413d575b505050506118ce610b8361410f6020880151600f0b90565b9260408801519061255e565b8351600f0b613713565b6000600f82900b12612b8b576001600160801b031690565b61195f9261137a61415d96959360606141589401519061255e565b612606565b388080806140f7565b5061417560608301514361255e565b9061418460408401514261255e565b906140eb565b9092818110156141f4576141af6141a96141a48484612655565b612626565b60011c90565b908560026141cb8461391c886000526011602052604060002090565b500154116141e05750600190935b019061404c565b9391506141ee60019161254f565b916141d9565b92614055565b60009182915b6080831061420f575b50505090565b9091928281101561427257828101808211611438576001808201809211611438571c90826002614249846000526004602052604060002090565b01541161425e5750600190935b019190614200565b93925061426c60019161254f565b92614256565b92614209565b904201908142116114385762093a8080920482810292818404149015171561143857801561044157428211156142fa576106d5916142c06142b842612634565b821115612746565b6142ce610f84600654612540565b6142db6006548095613edf565b506142f3610b61856000526012602052604060002090565b91846133c2565b60405162461bcd60e51b815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201527f66757475726500000000000000000000000000000000000000000000000000006064820152608490fd5b8181039291600013801582851316918412161761143857565b60008181526010602052604081205490918161439b575050905090565b829183905b60808210614427575b505091614402612e386143f86143d761407f6106d5989661391c610b83996000526011602052604060002090565b946118ce610b836143ec6020890151600f0b90565b92604089015190614365565b8451600f0b613713565b8061440e8351600f0b90565b600f0b1261441f575b5051600f0b90565b815238614417565b90928181101561448f578181019081811161143857600191828101809111611438578790831c926144668461391c886000526011602052604060002090565b5001541161447b5750600190935b01906143a0565b93915061448960019161254f565b91614474565b926143a9565b908060005260096020526144bc6001600160a01b03928380604060002054169116146123a4565b600052600b60205260406000209081549081166144d7575050565b6001600160a01b0319169055565b600082815260096020526001600160a01b0361450c816040842054169184168092146123a4565b838252600960205261452b604083206001600160a01b03198154169055565b8152600a6020526040812054600019810190811161143857838261455c6145c396600052600f602052604060002090565b548381036145d157506145986145a993614589876001600160a01b0316600052600e602052604060002090565b90600052602052604060002090565b55600052600f602052604060002090565b556001600160a01b0316600052600a602052604060002090565b6145cd815461254f565b9055565b83614598916146206145fd6145a9976145898b6001600160a01b0316600052600e602052604060002090565b5480614598846145898d6001600160a01b0316600052600e602052604060002090565b55614589876001600160a01b0316600052600e602052604060002090565b6146ca91600081815260209060098252600f6001600160a01b039260409361466b818686205416156123a4565b8584526009825284842080546001600160a01b0319166001600160a01b03891617905586168352600a81528383205494600e82528484208685528252808585205583525220556001600160a01b0316600052600a602052604060002090565b6145cd815461262656feff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6245e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5ca164736f6c6343000816000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.