Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
VotingEscrow
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {IERC721, IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC20} from "./interfaces/IERC20.sol"; import {IVeArtProxy} from "./interfaces/IVeArtProxy.sol"; import {IVotingEscrow} from "./interfaces/IVotingEscrow.sol"; import {Constants} from "./libraries/Constants.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` (2 years). contract VotingEscrow is Initializable, IERC721, IERC721Metadata, IVotes { enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME, MERGE_TYPE, SPLIT_TYPE } struct LockedBalance { int128 amount; uint start; uint end; } struct Point { int128 bias; int128 slope; // # -dweight / dt uint ts; uint 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 { uint timestamp; uint[] tokenIds; } /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit( address indexed provider, uint tokenId, uint value, uint indexed locktime, DepositType deposit_type, uint ts ); event Withdraw(address indexed provider, uint tokenId, uint value, uint ts); event Supply(uint prevSupply, uint supply); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ address public immutable token; address public voter; address public team; address public artProxy; address public distributor; mapping(uint => Point) public point_history; // 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 uint internal tokenId; /// @notice Contract constructor /// @param token_addr `SWPx` token address constructor(address token_addr) { token = token_addr; _disableInitializers(); } function initialize(address art_proxy, address _voter) external initializer { voter = _voter; team = msg.sender; artProxy = art_proxy; _entered_state = 1; point_history[0].blk = block.number; point_history[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), tokenId); // burn-ish emit Transfer(address(this), address(0), tokenId); } /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /// @dev reentrancy guard uint8 internal constant _not_entered = 1; uint8 internal constant _entered = 2; uint8 internal _entered_state; modifier nonreentrant() { require(_entered_state != _entered); _entered_state = _entered; _; _entered_state = _not_entered; } /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string constant public name = "veSwapX"; string constant public symbol = "veSWPx"; string constant public version = "1.0.0"; uint8 constant public decimals = 18; function setTeam(address _team) external { require(msg.sender == team); team = _team; } function setArtProxy(address _proxy) external { require(msg.sender == team); artProxy = _proxy; } function setDistributor(address _distributor) external { require(msg.sender == team); distributor = _distributor; } /// @dev Returns current token URI metadata /// @param _tokenId Token ID to fetch URI for. function tokenURI(uint _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,uint(int256(_locked.amount))); } /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from NFT ID to the address that owns it. mapping(uint => address) internal idToOwner; /// @dev Mapping from owner address to count of his tokens. mapping(address => uint) internal ownerToNFTokenCount; /// @dev Returns the address of the owner of the NFT. /// @param _tokenId The identifier for an NFT. function ownerOf(uint _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 (uint) { 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 (uint) { return _balance(_owner); } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from NFT ID to approved address. mapping(uint => address) internal idToApprovals; /// @dev Mapping from owner address to mapping of operator addresses. mapping(address => mapping(address => bool)) internal ownerToOperators; mapping(uint => uint) public ownership_change; /// @dev Get the approved address for a single NFT. /// @param _tokenId ID of the NFT to query the approval of. function getApproved(uint _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, uint _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, uint _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, uint _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, uint _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, uint _tokenId, address _sender ) internal { 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); // Remove NFT. Throws if `_tokenId` is not a valid NFT _removeTokenFrom(_from, _tokenId); // auto re-delegate _moveTokenDelegates(delegates(_from), delegates(_to), _tokenId); // Add NFT _addTokenTo(_to, _tokenId); // Set the block of ownership transfer (for Flash NFT protection) ownership_change[_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, uint _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, uint _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. uint 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. /// 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, uint _tokenId, bytes memory _data ) public { _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 Mapping from owner address to mapping of index to tokenIds mapping(address => mapping(uint => uint)) internal ownerToNFTokenIdList; /// @dev Mapping from NFT ID to index of owner mapping(uint => uint) internal tokenToOwnerIndex; /// @dev Get token by index function tokenOfOwnerByIndex(address _owner, uint _tokenIndex) external view returns (uint) { 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, uint _tokenId) internal { uint 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, uint _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, uint _tokenId) internal returns (bool) { // Throws if `_to` is zero address assert(_to != address(0)); // checkpoint for gov _moveTokenDelegates(address(0), delegates(_to), _tokenId); // 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, uint _tokenId) internal { // Delete uint current_count = _balance(_from) - 1; uint current_index = tokenToOwnerIndex[_tokenId]; if (current_count == current_index) { // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][current_count] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } else { uint lastTokenId = ownerToNFTokenIdList[_from][current_count]; // Add // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][current_index] = lastTokenId; // update tokenToOwnerIndex tokenToOwnerIndex[lastTokenId] = current_index; // Delete // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][current_count] = 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, uint _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(uint _tokenId) internal { require(_isApprovedOrOwner(msg.sender, _tokenId), "caller is not owner nor approved"); address owner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // checkpoint for gov _moveTokenDelegates(delegates(owner), address(0), _tokenId); // Remove token //_removeTokenFrom(msg.sender, _tokenId); _removeTokenFrom(owner, _tokenId); emit Transfer(owner, address(0), _tokenId); } /*////////////////////////////////////////////////////////////// ESCROW STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint => uint) public user_point_epoch; mapping(uint => Point[1000000000]) public user_point_history; // user -> Point[user_epoch] mapping(uint => LockedBalance) public locked; uint public epoch; mapping(uint => int128) public slope_changes; // time -> signed slope change uint public supply; uint internal constant MAXTIME = 2 * 365 * 86400; int128 internal constant iMAXTIME = 2 * 365 * 86400; uint internal constant MULTIPLIER = 1 ether; event DepositCheckpoint(address user, uint256 tokenId, int128 bias, int128 slope, uint ts, uint blk); /*////////////////////////////////////////////////////////////// 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 get_last_user_slope(uint _tokenId) external view returns (int128) { uint uepoch = user_point_epoch[_tokenId]; return user_point_history[_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 user_point_history__ts(uint _tokenId, uint _idx) external view returns (uint) { return user_point_history[_tokenId][_idx].ts; } /// @notice Get timestamp when `_tokenId`'s lock started /// @param _tokenId User NFT /// @return Epoch time of the lock start function locked__start(uint _tokenId) external view returns (uint) { return locked[_tokenId].start; } /// @notice Get timestamp when `_tokenId`'s lock finishes /// @param _tokenId User NFT /// @return Epoch time of the lock end function locked__end(uint _tokenId) external view returns (uint) { return locked[_tokenId].end; } /// @notice Record global and per-user data to checkpoint /// @param _tokenId NFT token ID. No user checkpoint if 0 /// @param old_locked Pevious locked amount / end lock time for the user /// @param new_locked New locked amount / end lock time for the user function _checkpoint( uint _tokenId, LockedBalance memory old_locked, LockedBalance memory new_locked ) internal { Point memory u_old; Point memory u_new; int128 old_dslope = 0; int128 new_dslope = 0; uint _epoch = epoch; if (_tokenId != 0) { // Calculate slopes and biases // Kept at zero when they have to if (old_locked.end > block.timestamp && old_locked.amount > 0) { u_old.slope = old_locked.amount / iMAXTIME; u_old.bias = u_old.slope * int128(int256(old_locked.end - block.timestamp)); } if (new_locked.end > block.timestamp && new_locked.amount > 0) { u_new.slope = new_locked.amount / iMAXTIME; u_new.bias = u_new.slope * int128(int256(new_locked.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 old_dslope = slope_changes[old_locked.end]; if (new_locked.end != 0) { if (new_locked.end == old_locked.end) { new_dslope = old_dslope; } else { new_dslope = slope_changes[new_locked.end]; } } } Point memory last_point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number}); if (_epoch > 0) { last_point = point_history[_epoch]; } uint last_checkpoint = last_point.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 initial_last_point = last_point; uint block_slope = 0; // dblock/dt if (block.timestamp > last_point.ts) { block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.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 { uint t_i = (last_checkpoint / Constants.EPOCH_LENGTH) * Constants.EPOCH_LENGTH; for (uint 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 t_i += Constants.EPOCH_LENGTH; int128 d_slope = 0; if (t_i > block.timestamp) { t_i = block.timestamp; } else { d_slope = slope_changes[t_i]; } last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); last_point.slope += d_slope; if (last_point.bias < 0) { // This can happen last_point.bias = 0; } if (last_point.slope < 0) { // This cannot happen - just in case last_point.slope = 0; } last_checkpoint = t_i; last_point.ts = t_i; last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER; _epoch += 1; if (t_i == block.timestamp) { last_point.blk = block.number; break; } else { point_history[_epoch] = last_point; } } } 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) last_point.slope += (u_new.slope - u_old.slope); last_point.bias += (u_new.bias - u_old.bias); if (last_point.slope < 0) { last_point.slope = 0; } if (last_point.bias < 0) { last_point.bias = 0; } } // Record the changed point into history point_history[_epoch] = last_point; 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 (old_locked.end > block.timestamp) { // old_dslope was <something> - u_old.slope, so we cancel that old_dslope += u_old.slope; if (new_locked.end == old_locked.end) { old_dslope -= u_new.slope; // It was a new deposit, not extension } slope_changes[old_locked.end] = old_dslope; } if (new_locked.end > block.timestamp) { if (new_locked.end > old_locked.end) { new_dslope -= u_new.slope; // old slope disappeared at this point slope_changes[new_locked.end] = new_dslope; } // else: we recorded it already in old_dslope } // Now handle user history uint user_epoch = user_point_epoch[_tokenId] + 1; user_point_epoch[_tokenId] = user_epoch; u_new.ts = block.timestamp; u_new.blk = block.number; user_point_history[_tokenId][user_epoch] = u_new; emit DepositCheckpoint(ownerOf(_tokenId), _tokenId, u_new.bias, u_new.slope, u_new.ts, u_new.blk); } } /// @notice Deposit and lock tokens for a user /// @param _tokenId NFT that holds lock /// @param _value Amount to deposit /// @param unlock_time New time when to unlock the tokens, or 0 if unchanged /// @param locked_balance Previous locked amount / timestamp /// @param deposit_type The type of deposit function _deposit_for( uint _tokenId, uint _value, uint unlock_time, LockedBalance memory locked_balance, DepositType deposit_type ) internal { LockedBalance memory _locked = locked_balance; uint supply_before = supply; supply = supply_before + _value; LockedBalance memory old_locked; (old_locked.amount, old_locked.start, old_locked.end) = (_locked.amount, _locked.start, _locked.end); // Adding to existing lock, or if a lock is expired - creating a new one _locked.amount += int128(int256(_value)); if (unlock_time != 0) { _locked.end = unlock_time; } if (_locked.start == 0) { _locked.start = block.timestamp; } 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, old_locked, _locked); address from = msg.sender; if (_value != 0 && deposit_type != DepositType.MERGE_TYPE && deposit_type != DepositType.SPLIT_TYPE ) { assert(IERC20(token).transferFrom(from, address(this), _value)); } emit Deposit(from, _tokenId, _value, _locked.end, deposit_type, block.timestamp); emit Supply(supply_before, supply_before + _value); } function block_number() external view returns (uint) { return block.number; } /// @notice Record global data to checkpoint function checkpoint() external { _checkpoint(0, LockedBalance(0, 0, 0), LockedBalance(0, 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 deposit_for(uint _tokenId, uint _value) external nonreentrant returns(uint votingPower) { 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 expired lock. Withdraw'); _deposit_for(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE); return _balanceOfNFT(_tokenId, block.timestamp); } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function _create_lock(uint _value, uint _lock_duration, address _to) internal returns (uint) { uint unlock_time = (block.timestamp + _lock_duration) / Constants.EPOCH_LENGTH * Constants.EPOCH_LENGTH; // Locktime is rounded down to weeks require(_value > 0); // dev: need non-zero value require(unlock_time > block.timestamp, 'Can only lock until time in the future'); require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 2 years max'); ++tokenId; uint _tokenId = tokenId; _mint(_to, _tokenId); _deposit_for(_tokenId, _value, unlock_time, 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 _lock_duration Number of seconds to lock tokens for (rounded down to nearest week) function create_lock(uint _value, uint _lock_duration) external nonreentrant returns (uint newTokenId, uint votingPower) { newTokenId = _create_lock(_value, _lock_duration, msg.sender); votingPower = _balanceOfNFT(newTokenId, block.timestamp); } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function create_lock_for(uint _value, uint _lock_duration, address _to) external nonreentrant returns (uint newTokenId, uint votingPower) { newTokenId = _create_lock(_value, _lock_duration, _to); votingPower = _balanceOfNFT(newTokenId, block.timestamp); } /// @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 increase_amount(uint _tokenId, uint _value) external nonreentrant returns (uint votingPower) { 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 expired lock. Withdraw'); _deposit_for(_tokenId, _value, 0, _locked, DepositType.INCREASE_LOCK_AMOUNT); return _balanceOfNFT(_tokenId, block.timestamp); } /// @notice Extend the unlock time for `_tokenId` /// @param _lock_duration New number of seconds until tokens unlock function increase_unlock_time(uint _tokenId, uint _lock_duration) external nonreentrant returns (uint votingPower) { assert(_isApprovedOrOwner(msg.sender, _tokenId)); LockedBalance memory _locked = locked[_tokenId]; uint unlock_time = (block.timestamp + _lock_duration) / Constants.EPOCH_LENGTH * Constants.EPOCH_LENGTH; // Locktime is rounded down to weeks require(_locked.end > block.timestamp, 'Lock expired'); require(_locked.amount > 0, 'Nothing is locked'); require(unlock_time > _locked.end, 'Can only increase lock duration'); require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 2 years max'); _deposit_for(_tokenId, 0, unlock_time, _locked, DepositType.INCREASE_UNLOCK_TIME); return _balanceOfNFT(_tokenId, block.timestamp); } /// @notice Withdraw all tokens for `_tokenId` /// @dev Only possible if the lock has expired function withdraw(uint _tokenId) external nonreentrant { assert(_isApprovedOrOwner(msg.sender, _tokenId)); require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached"); LockedBalance memory _locked = locked[_tokenId]; require(block.timestamp >= _locked.end, "The lock didn't expire"); uint value = uint(int256(_locked.amount)); locked[_tokenId] = LockedBalance(0, 0, 0); uint supply_before = supply; supply = supply_before - value; // 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, 0)); assert(IERC20(token).transfer(msg.sender, value)); // Burn the NFT _burn(_tokenId); emit Withdraw(msg.sender, _tokenId, value, block.timestamp); emit Supply(supply_before, supply_before - value); } /*/////////////////////////////////////////////////////////////// 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 max_epoch Don't go beyond this epoch /// @return Approximate timestamp for block function _find_block_epoch(uint _block, uint max_epoch) internal view returns (uint) { // Binary search uint _min = 0; uint _max = max_epoch; for (uint i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint _mid = (_min + _max + 1) / 2; if (point_history[_mid].blk <= _block) { _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(uint _tokenId, uint _t) internal view returns (uint) { uint _epoch = user_point_epoch[_tokenId]; if (_epoch == 0) { return 0; } else { Point memory last_point = user_point_history[_tokenId][_epoch]; last_point.bias -= last_point.slope * int128(int256(_t) - int256(last_point.ts)); if (last_point.bias < 0) { last_point.bias = 0; } return uint(int256(last_point.bias)); } } function balanceOfNFT(uint _tokenId) external view returns (uint) { if (ownership_change[_tokenId] == block.number) return 0; return _balanceOfNFT(_tokenId, block.timestamp); } function balanceOfNFTAt(uint _tokenId, uint _t) external view returns (uint) { 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(uint _tokenId, uint _block) internal view returns (uint) { // Copying and pasting totalSupply code because Vyper cannot pass by // reference yet assert(_block <= block.number); // Binary search uint _min = 0; uint _max = user_point_epoch[_tokenId]; for (uint i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint _mid = (_min + _max + 1) / 2; if (user_point_history[_tokenId][_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } Point memory upoint = user_point_history[_tokenId][_min]; uint max_epoch = epoch; uint _epoch = _find_block_epoch(_block, max_epoch); Point memory point_0 = point_history[_epoch]; uint d_block = 0; uint d_t = 0; if (_epoch < max_epoch) { Point memory point_1 = point_history[_epoch + 1]; d_block = point_1.blk - point_0.blk; d_t = point_1.ts - point_0.ts; } else { d_block = block.number - point_0.blk; d_t = block.timestamp - point_0.ts; } uint block_time = point_0.ts; if (d_block != 0) { block_time += (d_t * (_block - point_0.blk)) / d_block; } upoint.bias -= upoint.slope * int128(int256(block_time - upoint.ts)); if (upoint.bias >= 0) { return uint(uint128(upoint.bias)); } else { return 0; } } function balanceOfAtNFT(uint _tokenId, uint _block) external view returns (uint) { 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(uint _block) external view returns (uint) { assert(_block <= block.number); uint _epoch = epoch; uint target_epoch = _find_block_epoch(_block, _epoch); Point memory point = point_history[target_epoch]; uint dt = 0; if (target_epoch < _epoch) { Point memory point_next = point_history[target_epoch + 1]; if (point.blk != point_next.blk) { dt = ((_block - point.blk) * (point_next.ts - point.ts)) / (point_next.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 _supply_at(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 _supply_at(Point memory point, uint t) internal view returns (uint) { Point memory last_point = point; uint t_i = (last_point.ts / Constants.EPOCH_LENGTH) * Constants.EPOCH_LENGTH; for (uint i = 0; i < 255; ++i) { t_i += Constants.EPOCH_LENGTH; int128 d_slope = 0; if (t_i > t) { t_i = t; } else { d_slope = slope_changes[t_i]; } last_point.bias -= last_point.slope * int128(int256(t_i - last_point.ts)); if (t_i == t) { break; } last_point.slope += d_slope; last_point.ts = t_i; } if (last_point.bias < 0) { last_point.bias = 0; } return uint(uint128(last_point.bias)); } function totalSupply() external view returns (uint) { 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(uint t) public view returns (uint) { uint _epoch = epoch; Point memory last_point = point_history[_epoch]; return _supply_at(last_point, t); } /*/////////////////////////////////////////////////////////////// GAUGE VOTING LOGIC //////////////////////////////////////////////////////////////*/ mapping(uint => uint) public attachments; mapping(uint => bool) public voted; function setVoter(address _voter) external { require(msg.sender == team); voter = _voter; } function voting(uint _tokenId) external { require(msg.sender == voter); voted[_tokenId] = true; } function abstain(uint _tokenId) external { require(msg.sender == voter); voted[_tokenId] = false; } function attach(uint _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] + 1; } function detach(uint _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] - 1; } function merge(uint _from, uint _to) external returns (uint votingPower) { require(attachments[_from] == 0 && !voted[_from], "attached"); require(_from != _to); require(_isApprovedOrOwner(msg.sender, _from)); require(_isApprovedOrOwner(msg.sender, _to)); LockedBalance memory _locked0 = locked[_from]; LockedBalance memory _locked1 = locked[_to]; require(_locked0.end > block.timestamp && _locked1.end > block.timestamp); uint value0 = uint(int256(_locked0.amount)); uint end = _locked0.end >= _locked1.end ? _locked0.end : _locked1.end; _locked1.start = _locked0.start >= _locked1.start ? _locked1.start : _locked0.start; locked[_from] = LockedBalance(0, 0, 0); supply = supply - value0; _checkpoint(_from, _locked0, LockedBalance(0, 0, 0)); _burn(_from); _deposit_for(_to, value0, end, _locked1, DepositType.MERGE_TYPE); return _balanceOfNFT(_to, block.timestamp); } /** * @notice split NFT into multiple * @param amounts % of split * @param _tokenId NFTs ID */ function split(uint[] memory amounts, uint _tokenId) external returns(uint256[] memory newTokenIds, uint256[] memory votingPowers) { // check permission and vote require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached"); require(_isApprovedOrOwner(msg.sender, _tokenId)); // save old data and totalWeight address _to = idToOwner[_tokenId]; LockedBalance memory _locked = locked[_tokenId]; require(_locked.amount > 0); // dev: need non-zero value // require() // reset supply, _deposit_for increase it supply = supply - uint128(_locked.amount); uint i; uint totalWeight = 0; for(i = 0; i < amounts.length; i++){ totalWeight += amounts[i]; } // remove old data locked[_tokenId] = LockedBalance(0, 0, 0); _checkpoint(_tokenId, _locked, LockedBalance(0, 0, 0)); _burn(_tokenId); // save end uint unlock_time = _locked.end; require(unlock_time > block.timestamp, 'Can only lock until time in the future'); require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 2 years max'); newTokenIds = new uint256[](amounts.length); votingPowers = new uint256[](amounts.length); // mint uint _value = 0; for(i = 0; i < amounts.length; i++){ ++tokenId; _tokenId = tokenId; _mint(_to, _tokenId); _value = uint128(_locked.amount) * amounts[i] / totalWeight; locked[_tokenId].start = _locked.start; _deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.SPLIT_TYPE); newTokenIds[i] = _tokenId; votingPowers[i] = _balanceOfNFT(_tokenId, block.timestamp); } } /*/////////////////////////////////////////////////////////////// DAO VOTING STORAGE //////////////////////////////////////////////////////////////*/ /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice A record of each accounts delegate mapping(address => address) private _delegates; uint public constant MAX_DELEGATES = 1024; // avoid too much gas /// @notice A record of delegated token checkpoints for each account, by index mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping(address => uint32) public numCheckpoints; /// @notice A record of states for signing / validating signatures mapping(address => uint) public nonces; /** * @notice Overrides the standard `Comp.sol` delegates mapping to return * the delegator's own address if they haven't delegated. * This avoids having to delegate to oneself. */ function delegates(address delegator) public view returns (address) { address current = _delegates[delegator]; return current == address(0) ? delegator : current; } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getVotes(address account) external view returns (uint) { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } uint[] storage _tokenIds = checkpoints[account][nCheckpoints - 1].tokenIds; uint votes = 0; for (uint i = 0; i < _tokenIds.length; i++) { uint tId = _tokenIds[i]; votes = votes + _balanceOfNFT(tId, block.timestamp); } return votes; } function getPastVotesIndex(address account, uint timestamp) public view returns (uint32) { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (checkpoints[account][0].timestamp > timestamp) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint storage cp = checkpoints[account][center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function getPastVotes(address account, uint timestamp) public view returns (uint) { uint32 _checkIndex = getPastVotesIndex(account, timestamp); // Sum votes uint[] storage _tokenIds = checkpoints[account][_checkIndex].tokenIds; uint votes = 0; for (uint i = 0; i < _tokenIds.length; i++) { uint tId = _tokenIds[i]; // Use the provided input timestamp here to get the right decay votes = votes + _balanceOfNFT(tId, timestamp); } return votes; } function getPastTotalSupply(uint256 timestamp) external view returns (uint) { return totalSupplyAtT(timestamp); } /*/////////////////////////////////////////////////////////////// DAO VOTING LOGIC //////////////////////////////////////////////////////////////*/ function _moveTokenDelegates( address srcRep, address dstRep, uint _tokenId ) internal { if (srcRep != dstRep && _tokenId > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint[] storage srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].tokenIds : checkpoints[srcRep][0].tokenIds; uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep); uint[] storage srcRepNew = checkpoints[srcRep][ nextSrcRepNum ].tokenIds; // All the same except _tokenId for (uint i = 0; i < srcRepOld.length; i++) { uint tId = srcRepOld[i]; if (tId != _tokenId) { srcRepNew.push(tId); } } numCheckpoints[srcRep] = srcRepNum + 1; } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint[] storage dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].tokenIds : checkpoints[dstRep][0].tokenIds; uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep); uint[] storage dstRepNew = checkpoints[dstRep][ nextDstRepNum ].tokenIds; // All the same plus _tokenId require( dstRepOld.length + 1 <= MAX_DELEGATES, "dstRep would have too many tokenIds" ); for (uint i = 0; i < dstRepOld.length; i++) { uint tId = dstRepOld[i]; dstRepNew.push(tId); } dstRepNew.push(_tokenId); numCheckpoints[dstRep] = dstRepNum + 1; } } } function _findWhatCheckpointToWrite(address account) internal view returns (uint32) { uint _timestamp = block.timestamp; uint32 _nCheckPoints = numCheckpoints[account]; if ( _nCheckPoints > 0 && checkpoints[account][_nCheckPoints - 1].timestamp == _timestamp ) { return _nCheckPoints - 1; } else { return _nCheckPoints; } } function _moveAllDelegates( address owner, address srcRep, address dstRep ) internal { // You can only redelegate what you own if (srcRep != dstRep) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint[] storage srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].tokenIds : checkpoints[srcRep][0].tokenIds; uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep); uint[] storage srcRepNew = checkpoints[srcRep][ nextSrcRepNum ].tokenIds; // All the same except what owner owns for (uint i = 0; i < srcRepOld.length; i++) { uint tId = srcRepOld[i]; if (idToOwner[tId] != owner) { srcRepNew.push(tId); } } numCheckpoints[srcRep] = srcRepNum + 1; } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint[] storage dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].tokenIds : checkpoints[dstRep][0].tokenIds; uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep); uint[] storage dstRepNew = checkpoints[dstRep][ nextDstRepNum ].tokenIds; uint ownerTokenCount = ownerToNFTokenCount[owner]; require( dstRepOld.length + ownerTokenCount <= MAX_DELEGATES, "dstRep would have too many tokenIds" ); // All the same for (uint i = 0; i < dstRepOld.length; i++) { uint tId = dstRepOld[i]; dstRepNew.push(tId); } // Plus all that's owned for (uint i = 0; i < ownerTokenCount; i++) { uint tId = ownerToNFTokenIdList[owner][i]; dstRepNew.push(tId); } numCheckpoints[dstRep] = dstRepNum + 1; } } } function _delegate(address delegator, address delegatee) internal { /// @notice differs from `_delegate()` in `Comp.sol` to use `delegates` override method to simulate auto-delegation address currentDelegate = delegates(delegator); _delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); _moveAllDelegates(delegator, currentDelegate, delegatee); } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee) public { if (delegatee == address(0)) delegatee = msg.sender; return _delegate(msg.sender, delegatee); } function delegateBySig( address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s ) public { require(delegatee != msg.sender); require(delegatee != address(0)); bytes32 domainSeparator = keccak256( abi.encode( DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes(version)), block.chainid, address(this) ) ); bytes32 structHash = keccak256( abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry) ); bytes32 digest = keccak256( abi.encodePacked("\x19\x01", domainSeparator, structHash) ); address signatory = ecrecover(digest, v, r, s); require( signatory != address(0), "VotingEscrow::delegateBySig: invalid signature" ); require( nonce == nonces[signatory]++, "VotingEscrow::delegateBySig: invalid nonce" ); require( block.timestamp <= expiry, "VotingEscrow::delegateBySig: signature expired" ); return _delegate(signatory, delegatee); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol) pragma solidity ^0.8.0; /** * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. * * _Available since v4.5._ */ interface IVotes { /** * @dev Emitted when an account changes their delegate. */ event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /** * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. */ event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); /** * @dev Returns the current amount of votes that `account` has. */ function getVotes(address account) external view returns (uint256); /** * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`). */ function getPastVotes(address account, uint256 blockNumber) external view returns (uint256); /** * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`). * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ function getPastTotalSupply(uint256 blockNumber) external view returns (uint256); /** * @dev Returns the delegate that `account` has chosen. */ function delegates(address account) external view returns (address); /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(address delegatee) external; /** * @dev Delegates votes from signer to `delegatee`. */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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] * ``` * 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 Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ 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.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (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.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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, uint amount) external returns (bool); function decimals() external view returns (uint8); function symbol() external view returns (string memory); function balanceOf(address) external view returns (uint); function transferFrom(address sender, address recipient, uint amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; interface IVeArtProxy { function _tokenURI(uint _tokenId, uint _balanceOf, uint _locked_end, uint _value) external pure returns (string memory output); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; interface IVotingEscrow { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } struct LockedBalance { int128 amount; uint start; uint end; } function create_lock_for(uint _value, uint _lock_duration, address _to) external returns (uint); function locked(uint id) external view returns(LockedBalance memory); function tokenOfOwnerByIndex(address _owner, uint _tokenIndex) external view returns (uint); function token() external view returns (address); function team() external returns (address); function epoch() external view returns (uint); function point_history(uint loc) external view returns (Point memory); function user_point_history(uint tokenId, uint loc) external view returns (Point memory); function user_point_epoch(uint tokenId) external view returns (uint); function ownerOf(uint) external view returns (address); function isApprovedOrOwner(address, uint) external view returns (bool); function transferFrom(address, address, uint) external; function voted(uint) external view returns (bool); function attachments(uint) external view returns (uint); function voting(uint tokenId) external; function abstain(uint tokenId) external; function attach(uint tokenId) external; function detach(uint tokenId) external; function checkpoint() external; function deposit_for(uint tokenId, uint value) external; function balanceOfAtNFT(uint _tokenId, uint _block) external view returns (uint); function balanceOfNFT(uint _id) external view returns (uint); function balanceOf(address _owner) external view returns (uint); function totalSupply() external view returns (uint); function supply() external view returns (uint); function decimals() external view returns(uint8); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; library Constants { uint256 internal constant EPOCH_LENGTH = 1 hours; // 7 days; }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"token_addr","type":"address"}],"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":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","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":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"int128","name":"bias","type":"int128"},{"indexed":false,"internalType":"int128","name":"slope","type":"int128"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blk","type":"uint256"}],"name":"DepositCheckpoint","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":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DELEGATES","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":"block_number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"}],"name":"create_lock","outputs":[{"internalType":"uint256","name":"newTokenId","type":"uint256"},{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"create_lock_for","outputs":[{"internalType":"uint256","name":"newTokenId","type":"uint256"},{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"deposit_for","outputs":[{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"detach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributor","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":"timestamp","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPastVotesIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"get_last_user_slope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"increase_amount","outputs":[{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"}],"name":"increase_unlock_time","outputs":[{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"art_proxy","type":"address"},{"internalType":"address","name":"_voter","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":"uint256","name":"","type":"uint256"}],"name":"locked","outputs":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint256","name":"start","type":"uint256"},{"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":"_tokenId","type":"uint256"}],"name":"locked__start","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":[{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":"ownership_change","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"point_history","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":"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":"_proxy","type":"address"}],"name":"setArtProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"}],"name":"setDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_team","type":"address"}],"name":"setTeam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voter","type":"address"}],"name":"setVoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"slope_changes","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"split","outputs":[{"internalType":"uint256[]","name":"newTokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"votingPowers","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":[],"name":"token","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":"user_point_epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"user_point_history","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":"user_point_history__ts","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
60a06040523480156200001157600080fd5b506040516200540438038062005404833981016040819052620000349162000114565b6001600160a01b0381166080526200004b62000052565b5062000146565b600054610100900460ff1615620000bf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000112576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012757600080fd5b81516001600160a01b03811681146200013f57600080fd5b9392505050565b6080516152946200017060003960008181610c2401528181611144015261376a01526152946000f3fe608060405234801561001057600080fd5b506004361061043e5760003560e01c80637116c60c11610236578063bfe109281161013b578063e441135c116100c3578063f1127ed811610087578063f1127ed814610bbe578063f8a0576314610be9578063fbd3a29d14610c0c578063fc0c546a14610c1f578063fd4a77f114610c4657600080fd5b8063e441135c14610b15578063e7a324dc14610b35578063e7e242d414610b5c578063e985e9c514610b6f578063ee99fe2814610bab57600080fd5b8063c87b56dd1161010a578063c87b56dd14610a8b578063d1c2babb14610a9e578063d1febfb914610ab1578063d4e54c3b14610aef578063e0514aba14610b0257600080fd5b8063bfe1092814610a4a578063c1f0fb9f14610a5d578063c2c4c5c114610a70578063c3cda52014610a7857600080fd5b806395d89b41116101be578063a183af521161018d578063a183af52146109aa578063a22cb465146109bd578063a4d855df146109d0578063b45a3c0e146109e3578063b88d4fde14610a3757600080fd5b806395d89b411461094c578063981b24d014610971578063986b7d8a146109845780639ab24eb01461099757600080fd5b806385f2aef21161020557806385f2aef2146108e75780638c2c9baf146108fa5780638e539e8c1461090d5780638fbb38ff14610920578063900cf0cf1461094357600080fd5b80637116c60c1461087e578063711974841461089157806375619ab5146108b45780637ecebe00146108c757600080fd5b806335cf668a116103475780635594a045116102cf5780636352211e116102935780636352211e146107d457806365fc3873146107fd5780636f548837146108255780636fcfff451461084557806370a082311461086b57600080fd5b80635594a0451461077157806356afe74414610784578063587cde1e146107a55780635c19a95c146107b85780635f5b0c32146107cb57600080fd5b8063461f711c11610316578063461f711c146106e857806346c96aac1461070e578063485cc955146107275780634bc2a6571461073a57806354fd4d501461074d57600080fd5b806335cf668a1461068c5780633a46b1a8146106af57806342842e0e146106c2578063430c2081146106d557600080fd5b806318160ddd116103ca57806325a58b561161039957806325a58b56146106105780632e1a7d4d146106165780632e720f7d146106295780632f745c591461063c578063313ce5671461067257600080fd5b806318160ddd146105bb5780631c984bc3146105c357806320606b70146105d657806323b872dd146105fd57600080fd5b8063081812fc11610411578063081812fc146104f7578063095cf5c614610538578063095ea7b31461054d5780630d6a2033146105605780631376f3da1461058057600080fd5b806301ffc9a714610443578063047fc9aa1461048557806306fdde031461049c5780630758c7d8146104cf575b600080fd5b61047061045136600461482d565b6001600160e01b03191660009081526005602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61048e60145481565b60405190815260200161047c565b6104c2604051806040016040528060078152602001660eccaa6eec2e0b60cb1b81525081565b60405161047c91906148a2565b6104e26104dd3660046148d1565b610c59565b60405163ffffffff909116815260200161047c565b6105206105053660046148fb565b6000908152600a60205260409020546001600160a01b031690565b6040516001600160a01b03909116815260200161047c565b61054b610546366004614914565b610dcc565b005b61054b61055b3660046148d1565b610e05565b61048e61056e3660046148fb565b60156020526000908152604090205481565b61059361058e36600461492f565b610eed565b60408051600f95860b81529390940b602084015292820152606081019190915260800161047c565b61048e610f34565b61048e6105d136600461492f565b610f44565b61048e7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b61054b61060b366004614951565b610f76565b4361048e565b61054b6106243660046148fb565b610f87565b61054b610637366004614914565b611267565b61048e61064a3660046148d1565b6001600160a01b03919091166000908152600d60209081526040808320938352929052205490565b61067a601281565b60405160ff909116815260200161047c565b61048e61069a3660046148fb565b60009081526011602052604090206001015490565b61048e6106bd3660046148d1565b6112a0565b61054b6106d0366004614951565b61133f565b6104706106e33660046148d1565b61135a565b6106fb6106f63660046148fb565b61136d565b604051600f9190910b815260200161047c565b600054610520906201000090046001600160a01b031681565b61054b61073536600461498d565b6113b0565b61054b610748366004614914565b611624565b6104c2604051806040016040528060058152602001640312e302e360dc1b81525081565b600254610520906001600160a01b031681565b610797610792366004614a07565b611665565b60405161047c929190614aee565b6105206107b3366004614914565b6119fd565b61054b6107c6366004614914565b611a2d565b61048e61040081565b6105206107e23660046148fb565b6000908152600860205260409020546001600160a01b031690565b61081061080b36600461492f565b611a4b565b6040805192835260208301919091520161047c565b61048e6108333660046148fb565b600c6020526000908152604090205481565b6104e2610853366004614914565b60196020526000908152604090205463ffffffff1681565b61048e610879366004614914565b611a9f565b61048e61088c3660046148fb565b611abd565b6106fb61089f3660046148fb565b601360205260009081526040902054600f0b81565b61054b6108c2366004614914565b611b1d565b61048e6108d5366004614914565b601a6020526000908152604090205481565b600154610520906001600160a01b031681565b61048e61090836600461492f565b611b56565b61048e61091b3660046148fb565b611b62565b61047061092e3660046148fb565b60166020526000908152604090205460ff1681565b61048e60125481565b6104c2604051806040016040528060068152602001650eccaa6aea0f60d31b81525081565b61048e61097f3660046148fb565b611b6d565b61054b6109923660046148fb565b611d0f565b61048e6109a5366004614914565b611d59565b61048e6109b836600461492f565b611e2c565b61054b6109cb366004614b21565b611f4c565b61048e6109de36600461492f565b611fd0565b610a176109f13660046148fb565b601160205260009081526040902080546001820154600290920154600f9190910b919083565b60408051600f9490940b845260208401929092529082015260600161047c565b61054b610a45366004614b80565b61219f565b600354610520906001600160a01b031681565b61054b610a6b3660046148fb565b61233e565b61054b612373565b61054b610a86366004614c2b565b6123c1565b6104c2610a993660046148fb565b61272a565b61048e610aac36600461492f565b61286e565b610593610abf3660046148fb565b600460205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b610810610afd366004614c8b565b612a7b565b61048e610b1036600461492f565b612ad0565b61048e610b233660046148fb565b600f6020526000908152604090205481565b61048e7fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b61048e610b6a3660046148fb565b612adc565b610470610b7d36600461498d565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205460ff1690565b61048e610bb936600461492f565b612b04565b61048e610bcc366004614cc0565b601860209081526000928352604080842090915290825290205481565b61048e610bf73660046148fb565b60009081526011602052604090206002015490565b61054b610c1a3660046148fb565b612beb565b6105207f000000000000000000000000000000000000000000000000000000000000000081565b61054b610c543660046148fb565b612c22565b6001600160a01b03821660009081526019602052604081205463ffffffff16808203610c89576000915050610dc6565b6001600160a01b03841660009081526018602052604081208491610cae600185614d0b565b63ffffffff16815260208101919091526040016000205411610cdd57610cd5600182614d0b565b915050610dc6565b6001600160a01b0384166000908152601860209081526040808320838052909152902054831015610d12576000915050610dc6565b600080610d20600184614d0b565b90505b8163ffffffff168163ffffffff161115610dc15760006002610d458484614d0b565b610d4f9190614d46565b610d599083614d0b565b6001600160a01b038816600090815260186020908152604080832063ffffffff851684529091529020805491925090879003610d9b57509350610dc692505050565b8054871115610dac57819350610dba565b610db7600183614d0b565b92505b5050610d23565b509150505b92915050565b6001546001600160a01b03163314610de357600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600860205260409020546001600160a01b031680610e2757600080fd5b806001600160a01b0316836001600160a01b031603610e4557600080fd5b6000828152600860209081526040808320546001600160a01b038581168552600b845282852033808752945291909320549216149060ff168180610e865750805b610e8f57600080fd5b6000848152600a602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b601060205281600052604060002081633b9aca008110610f0c57600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610f3f42611abd565b905090565b600082815260106020526040812082633b9aca008110610f6657610f66614d69565b6003020160010154905092915050565b610f8283838333612c5a565b505050565b60075460ff1660011901610f9a57600080fd5b6007805460ff19166002179055610fb13382612d29565b610fbd57610fbd614d7f565b600081815260156020526040902054158015610fe8575060008181526016602052604090205460ff16155b61100d5760405162461bcd60e51b815260040161100490614d95565b60405180910390fd5b60008181526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181018290529042101561108d5760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401611004565b80516040805160608101825260008082526020808301828152838501838152888452601190925293909120915182546001600160801b0319166001600160801b03909116178255915160018201559051600290910155601454600f9190910b906110f78282614db7565b601481905550611128848460405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b60405163a9059cbb60e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b99190614dce565b6111c5576111c5614d7f565b6111ce8461343a565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8161123c8482614db7565b6040805192835260208301919091520160405180910390a150506007805460ff191660011790555050565b6001546001600160a01b0316331461127e57600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000806112ad8484610c59565b6001600160a01b038516600090815260186020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156113355760008382815481106112fe576112fe614d69565b9060005260206000200154905061131581886134fb565b61131f9084614deb565b925050808061132d90614e03565b9150506112e1565b5095945050505050565b610f828383836040518060200160405280600081525061219f565b60006113668383612d29565b9392505050565b6000818152600f60209081526040808320546010909252822081633b9aca00811061139a5761139a614d69565b6003020154600160801b9004600f0b9392505050565b600054610100900460ff16158080156113d05750600054600160ff909116105b806113ea5750303b1580156113ea575060005460ff166001145b61144d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611004565b6000805460ff191660011790558015611470576000805461ff0019166101001790555b600080546001600160a01b03808516620100000262010000600160b01b0319909216919091178255600180546001600160a01b0319908116331782556002805493881693909116929092179091556007805460ff199081168317909155437f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee55427f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed5560056020527fc01909ce2b517f8cd3a46ae0cfde9179f9b675cf633d3d84c8226585cc73c15680548216831790557f072ad3113145b5af48d301e3b9fc3bd1c97c3f26a14f5d44904b71469875631e8054821683179055635b5e139f60e01b83527f3b767bd59d7164fff7ec5b80ca1165d9d6e12ee8656896fac4159b0760bfd9f7805490911690911790556006546040519091309160008051602061523f833981519152908290a4600654604051600090309060008051602061523f833981519152908390a48015610f82576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b6001546001600160a01b0316331461163b57600080fd5b600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6000818152601560205260409020546060908190158015611695575060008381526016602052604090205460ff16155b6116b15760405162461bcd60e51b815260040161100490614d95565b6116bb3384612d29565b6116c457600080fd5b6000838152600860209081526040808320546011835281842082516060810184528154600f0b808252600183015495820195909552600290910154928101929092526001600160a01b03169290911361171c57600080fd5b8051601454611734916001600160801b031690614db7565b6014556000805b875182101561177d5787828151811061175657611756614d69565b6020026020010151816117699190614deb565b90508161177581614e03565b92505061173b565b6040805160608082018352600080835260208084018281528486018381528d845260118352868420955186546001600160801b0319166001600160801b03909116178655905160018601555160029094019390935583519182018452808252918101829052918201526117f39088908590612d8c565b6117fc8761343a565b60408301514281116118205760405162461bcd60e51b815260040161100490614e1c565b61182e6303c2670042614deb565b81111561184d5760405162461bcd60e51b815260040161100490614e62565b885167ffffffffffffffff811115611867576118676149c0565b604051908082528060200260200182016040528015611890578160200160208202803683370190505b509650885167ffffffffffffffff8111156118ad576118ad6149c0565b6040519080825280602002602001820160405280156118d6578160200160208202803683370190505b50955060008093505b89518410156119f0576006600081546118f790614e03565b90915550600654985061190a868a6135cf565b50828a858151811061191e5761191e614d69565b602002602001015186600001516001600160801b031661193e9190614e99565b6119489190614eb8565b60208087015160008c8152601183526040908190206001810183905581516060810183528154600f0b81529384019290925260029091015490820152909150611998908a9083908590600561362e565b888885815181106119ab576119ab614d69565b6020026020010181815250506119c189426134fb565b8785815181106119d3576119d3614d69565b6020908102919091010152836119e881614e03565b9450506118df565b5050505050509250929050565b6001600160a01b038082166000908152601760205260408120549091168015611a265780611366565b5090919050565b6001600160a01b038116611a3e5750335b611a48338261387e565b50565b600754600090819060ff1660011901611a6357600080fd5b6007805460ff19166002179055611a7b8484336138f1565b9150611a8782426134fb565b6007805460ff19166001179055919491935090915050565b6001600160a01b038116600090815260096020526040812054610dc6565b601254600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152909190611b1581856139e5565b949350505050565b6001546001600160a01b03163314611b3457600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006113668383613ae4565b6000610dc682611abd565b600043821115611b7f57611b7f614d7f565b6012546000611b8e8483613dbd565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606082015291925083831015611c9d576000600481611bf1866001614deb565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606080830182905285015191925014611c975782606001518160600151611c5d9190614db7565b83604001518260400151611c719190614db7565b6060850151611c80908a614db7565b611c8a9190614e99565b611c949190614eb8565b91505b50611cec565b43826060015114611cec576060820151611cb79043614db7565b6040830151611cc69042614db7565b6060840151611cd59089614db7565b611cdf9190614e99565b611ce99190614eb8565b90505b611d0582828460400151611d009190614deb565b6139e5565b9695505050505050565b6000546201000090046001600160a01b03163314611d2c57600080fd5b600081815260156020526040902054611d4790600190614db7565b60009182526015602052604090912055565b6001600160a01b03811660009081526019602052604081205463ffffffff16808203611d885750600092915050565b6001600160a01b038316600090815260186020526040812081611dac600185614d0b565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b8254811015611e23576000838281548110611dec57611dec614d69565b90600052602060002001549050611e0381426134fb565b611e0d9084614deb565b9250508080611e1b90614e03565b915050611dcf565b50949350505050565b60075460009060ff1660011901611e4257600080fd5b6007805460ff19166002179055611e593384612d29565b611e6557611e65614d7f565b60008381526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181019190915282611eaa57611eaa614d7f565b60008160000151600f0b13611efa5760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401611004565b42816040015111611f1d5760405162461bcd60e51b815260040161100490614ecc565b611f2c8484600084600261362e565b611f3684426134fb565b9150506007805460ff1916600117905592915050565b336001600160a01b03831603611f6457611f64614d7f565b336000818152600b602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60075460009060ff1660011901611fe657600080fd5b6007805460ff19166002179055611ffd3384612d29565b61200957612009614d7f565b600083815260116020908152604080832081516060810183528154600f0b8152600182015493810193909352600201549082015290610e108061204c8642614deb565b6120569190614eb8565b6120609190614e99565b9050428260400151116120a45760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401611004565b60008260000151600f0b136120ef5760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401611004565b816040015181116121425760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401611004565b6121506303c2670042614deb565b81111561216f5760405162461bcd60e51b815260040161100490614e62565b61217e8560008385600361362e565b61218885426134fb565b925050506007805460ff1916600117905592915050565b6121ab84848433612c5a565b823b1561233857604051630a85bd0160e11b81526001600160a01b0384169063150b7a02906121e4903390889087908790600401614f10565b6020604051808303816000875af192505050801561221f575060408051601f3d908101601f1916820190925261221c91810190614f43565b60015b6122c7573d80801561224d576040519150601f19603f3d011682016040523d82523d6000602084013e612252565b606091505b5080516000036122bf5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401611004565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146123365760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401611004565b505b50505050565b6000546201000090046001600160a01b0316331461235b57600080fd5b6000908152601660205260409020805460ff19169055565b6123bf600060405180606001604052806000600f0b815260200160008152602001600081525060405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b565b336001600160a01b038716036123d657600080fd5b6001600160a01b0386166123e957600080fd5b60408051808201825260078152660eccaa6eec2e0b60cb1b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f1de6a1c189dcc4ee6a95fb1fdc3a550060accb8f042ce71a27c9dd46bee30732818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156125aa573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166126245760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401611004565b6001600160a01b0381166000908152601a6020526040812080549161264883614e03565b9190505589146126ad5760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401611004565b874211156127145760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401611004565b61271e818b61387e565b50505050505050505050565b6000818152600860205260409020546060906001600160a01b03166127915760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401611004565b60008281526011602090815260409182902082516060810184528154600f0b81526001820154928101929092526002908101549282019290925290546001600160a01b031663dd9ec149846127e681426134fb565b604080860151865191516001600160e01b031960e087901b168152612829949392600f0b9060040193845260208401929092526040830152606082015260800190565b600060405180830381865afa158015612846573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190614f60565b600082815260156020526040812054158015612899575060008381526016602052604090205460ff16155b6128b55760405162461bcd60e51b815260040161100490614d95565b8183036128c157600080fd5b6128cb3384612d29565b6128d457600080fd5b6128de3383612d29565b6128e757600080fd5b60008381526011602081815260408084208151606080820184528254600f90810b8352600180850154848801526002948501548487019081528b8a529787529785902085519283018652805490910b825296870154948101949094529401549082015290514210801561295d5750428160400151115b61296657600080fd5b60008260000151600f0b9050600082604001518460400151101561298e578260400151612994565b83604001515b90508260200151846020015110156129b05783602001516129b6565b82602001515b6020848101919091526040805160608101825260008082528184018181528284018281528c83526011909552929020905181546001600160801b0319166001600160801b03909116178155905160018201559051600290910155601454612a1e908390614db7565b601481905550612a4f878560405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b612a588761343a565b612a6686838386600461362e565b612a7086426134fb565b979650505050505050565b600754600090819060ff1660011901612a9357600080fd5b6007805460ff19166002179055612aab8585856138f1565b9150612ab782426134fb565b6007805460ff1916600117905591959194509092505050565b600061136683836134fb565b6000818152600c6020526040812054439003612afa57506000919050565b610dc682426134fb565b60075460009060ff1660011901612b1a57600080fd5b6007805460ff1916600290811790915560008481526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252909201549082015282612b6957600080fd5b60008160000151600f0b13612bb95760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401611004565b42816040015111612bdc5760405162461bcd60e51b815260040161100490614ecc565b611f2c8484600084600061362e565b6000546201000090046001600160a01b03163314612c0857600080fd5b600081815260156020526040902054611d47906001614deb565b6000546201000090046001600160a01b03163314612c3f57600080fd5b6000908152601660205260409020805460ff19166001179055565b600082815260156020526040902054158015612c85575060008281526016602052604090205460ff16155b612ca15760405162461bcd60e51b815260040161100490614d95565b612cab8183612d29565b612cb457600080fd5b612cbe8483613e43565b612cc88483613eaa565b612ce3612cd4856119fd565b612cdd856119fd565b84613f2b565b612ced838361428d565b6000828152600c60205260408082204390555183916001600160a01b03808716929088169160008051602061523f83398151915291a450505050565b600081815260086020908152604080832054600a8352818420546001600160a01b03918216808652600b855283862088841680885295529285205492938085149392909116149060ff168280612d7c5750815b80612a7057509695505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260408051608081018252600080825260208201819052918101829052606081019190915260125460009081908715612ef057428760400151118015612dfc575060008760000151600f0b135b15612e3f578651612e12906303c2670090614fce565b600f0b60208601526040870151612e2a904290614db7565b8560200151612e39919061500c565b600f0b85525b428660400151118015612e59575060008660000151600f0b135b15612e9c578551612e6f906303c2670090614fce565b600f0b60208501526040860151612e87904290614db7565b8460200151612e96919061500c565b600f0b84525b604080880151600090815260136020528190205490870151600f9190910b935015612ef0578660400151866040015103612ed857829150612ef0565b604080870151600090815260136020522054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612f65575060008181526004602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b604081015181600042831015612fb2576040840151612f849042614db7565b6060850151612f939043614db7565b612fa590670de0b6b3a7640000614e99565b612faf9190614eb8565b90505b6000610e10612fc18186614eb8565b612fcb9190614e99565b905060005b60ff81101561314457612fe5610e1083614deb565b9150600042831115612ff95742925061300d565b50600082815260136020526040902054600f0b5b6130178684614db7565b8760200151613026919061500c565b875188906130359083906150a1565b600f0b90525060208701805182919061304f9083906150f1565b600f90810b90915288516000910b1215905061306a57600087525b60008760200151600f0b121561308257600060208801525b60408088018490528501519295508592670de0b6b3a7640000906130a69085614db7565b6130b09086614e99565b6130ba9190614eb8565b85606001516130c99190614deb565b60608801526130d9600189614deb565b97504283036130ee5750436060870152613144565b6000888152600460209081526040918290208951918a01516001600160801b03908116600160801b02921691909117815590880151600182015560608801516002909101555061313d81614e03565b9050612fd0565b505060128590558b156131cf578860200151886020015161316591906150a1565b8460200181815161317691906150f1565b600f0b9052508851885161318a91906150a1565b845185906131999083906150f1565b600f90810b90915260208601516000910b121590506131ba57600060208501525b60008460000151600f0b12156131cf57600084525b6000858152600460209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b1561342c57428b60400151111561328357602089015161323590886150f1565b96508a604001518a604001510361325857602088015161325590886150a1565b96505b60408b810151600090815260136020522080546001600160801b0319166001600160801b0389161790555b428a6040015111156132db578a604001518a6040015111156132db5760208801516132ae90876150a1565b60408b810151600090815260136020522080546001600160801b0319166001600160801b03831617905595505b60008c8152600f60205260408120546132f5906001614deb565b905080600f60008f815260200190815260200160002081905550428960400181815250504389606001818152505088601060008f815260200190815260200160002082633b9aca00811061334b5761334b614d69565b825160208401516001600160801b03908116600160801b0291161760039190910291909101908155604082015160018201556060909101516002909101557f8d83e324303a2f547eb8572fb6b42fb04620c4a95f09c9a1c8c6e5ac8f4624ed6133c98e6000908152600860205260409020546001600160a01b031690565b8e8b600001518c602001518d604001518e60600151604051613422969594939291906001600160a01b039690961686526020860194909452600f92830b6040860152910b6060840152608083015260a082015260c00190565b60405180910390a1505b505050505050505050505050565b6134443382612d29565b6134905760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401611004565b6000818152600860205260408120546001600160a01b0316906134b39083610e05565b6134c76134bf826119fd565b600084613f2b565b6134d18183613eaa565b60405182906000906001600160a01b0384169060008051602061523f833981519152908390a45050565b6000828152600f602052604081205480820361351b576000915050610dc6565b600084815260106020526040812082633b9aca00811061353d5761353d614d69565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820183905260020154606082015291506135899085615140565b8160200151613598919061500c565b815182906135a79083906150a1565b600f90810b90915282516000910b121590506135c257600081525b51600f0b9150610dc69050565b60006001600160a01b0383166135e7576135e7614d7f565b6135f56000612cdd856119fd565b6135ff838361428d565b60405182906001600160a01b0385169060009060008051602061523f833981519152908290a450600192915050565b601454829061363d8682614deb565b601455604080516060810182526000808252602080830182815283850192835286519187015194870151909252929052600f9190910b81528251879084906136869083906150f1565b600f0b905250851561369a57604083018690525b82602001516000036136ad574260208401525b600088815260116020908152604091829020855181546001600160801b0319166001600160801b03909116178155908501516001820155908401516002909101556136f9888285612d8c565b33871580159061371b575060048560058111156137185761371861517f565b14155b8015613739575060058560058111156137365761373661517f565b14155b156137e3576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018a90527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af11580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d79190614dce565b6137e3576137e3614d7f565b8360400151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516138279493929190615195565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8361385b8a82614deb565b6040805192835260208301919091520160405180910390a1505050505050505050565b6000613889836119fd565b6001600160a01b0384811660008181526017602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610f82838284614323565b600080610e10806139028642614deb565b61390c9190614eb8565b6139169190614e99565b90506000851161392557600080fd5b4281116139445760405162461bcd60e51b815260040161100490614e1c565b6139526303c2670042614deb565b8111156139715760405162461bcd60e51b815260040161100490614e62565b60066000815461398090614e03565b9091555060065461399184826135cf565b5060008181526011602090815260409182902082516060810184528154600f0b815260018083015493820193909352600290910154928101929092526139dc9183918991869161362e565b95945050505050565b6000808390506000610e10808360400151613a009190614eb8565b613a0a9190614e99565b905060005b60ff811015613abc57613a24610e1083614deb565b9150600085831115613a3857859250613a4c565b50600082815260136020526040902054600f0b5b6040840151613a5b9084614db7565b8460200151613a6a919061500c565b84518590613a799083906150a1565b600f0b905250858303613a8c5750613abc565b8084602001818151613a9e91906150f1565b600f0b9052505060408301829052613ab581614e03565b9050613a0f565b5060008260000151600f0b1215613ad257600082525b50516001600160801b03169392505050565b600043821115613af657613af6614d7f565b6000838152600f6020526040812054815b6080811015613b965781831015613b965760006002613b268486614deb565b613b31906001614deb565b613b3b9190614eb8565b6000888152601060205260409020909150869082633b9aca008110613b6257613b62614d69565b600302016002015411613b7757809350613b85565b613b82600182614db7565b92505b50613b8f81614e03565b9050613b07565b50600085815260106020526040812083633b9aca008110613bb957613bb9614d69565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282019290925260029091015460608201526012549091506000613c0e8783613dbd565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508084841015613ced576000600481613c72876001614deb565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052860151919250613ccf9190614db7565b925083604001518160400151613ce59190614db7565b915050613d11565b6060830151613cfc9043614db7565b9150826040015142613d0e9190614db7565b90505b60408301518215613d4e578284606001518c613d2d9190614db7565b613d379084614e99565b613d419190614eb8565b613d4b9082614deb565b90505b6040870151613d5d9082614db7565b8760200151613d6c919061500c565b87518890613d7b9083906150a1565b600f90810b90915288516000910b129050613dab57505093516001600160801b03169650610dc695505050505050565b60009950505050505050505050610dc6565b60008082815b6080811015613e395781831015613e395760006002613de28486614deb565b613ded906001614deb565b613df79190614eb8565b6000818152600460205260409020600201549091508710613e1a57809350613e28565b613e25600182614db7565b92505b50613e3281614e03565b9050613dc3565b5090949350505050565b6000818152600860205260409020546001600160a01b03838116911614613e6c57613e6c614d7f565b6000818152600a60205260409020546001600160a01b031615613ea6576000818152600a6020526040902080546001600160a01b03191690555b5050565b6000818152600860205260409020546001600160a01b03838116911614613ed357613ed3614d7f565b600081815260086020526040902080546001600160a01b0319169055613ef982826146df565b6001600160a01b0382166000908152600960205260408120805460019290613f22908490614db7565b90915550505050565b816001600160a01b0316836001600160a01b031614158015613f4d5750600081115b15610f82576001600160a01b038316156140ce576001600160a01b03831660009081526019602052604081205463ffffffff169081613fb1576001600160a01b03851660009081526018602090815260408083208380529091529020600101613ff3565b6001600160a01b038516600090815260186020526040812090613fd5600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006140008661479e565b6001600160a01b038716600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561408d57600084828154811061405057614050614d69565b9060005260206000200154905086811461407a578254600181018455600084815260209020018190555b508061408581614e03565b915050614033565b506140998460016151d3565b6001600160a01b0388166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610f82576001600160a01b03821660009081526019602052604081205463ffffffff16908161412d576001600160a01b0384166000908152601860209081526040808320838052909152902060010161416f565b6001600160a01b038416600090815260186020526040812090614151600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061417c8561479e565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915290208354919250600190810191610400916141be9190614deb565b11156141dc5760405162461bcd60e51b8152600401611004906151fb565b60005b835481101561422e5760008482815481106141fc576141fc614d69565b60009182526020808320909101548554600181018755868452919092200155508061422681614e03565b9150506141df565b508054600181810183556000838152602090209091018690556142529085906151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600860205260409020546001600160a01b0316156142b2576142b2614d7f565b600081815260086020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260098084528285208054600d86528487208188528652848720889055878752600e865293862093909355908452909152805460019290613f22908490614deb565b806001600160a01b0316826001600160a01b031614610f82576001600160a01b038216156144d6576001600160a01b03821660009081526019602052604081205463ffffffff16908161439b576001600160a01b038416600090815260186020908152604080832083805290915290206001016143dd565b6001600160a01b0384166000908152601860205260408120906143bf600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006143ea8561479e565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561449557600084828154811061443a5761443a614d69565b600091825260208083209091015480835260089091526040909120549091506001600160a01b03908116908a1614614482578254600181018455600084815260209020018190555b508061448d81614e03565b91505061441d565b506144a18460016151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610f82576001600160a01b03811660009081526019602052604081205463ffffffff169081614535576001600160a01b03831660009081526018602090815260408083208380529091529020600101614577565b6001600160a01b038316600090815260186020526040812090614559600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006145848461479e565b6001600160a01b03808616600090815260186020908152604080832063ffffffff861684528252808320938b16835260099091529020548454929350600190910191610400906145d5908390614deb565b11156145f35760405162461bcd60e51b8152600401611004906151fb565b60005b845481101561464557600085828154811061461357614613614d69565b60009182526020808320909101548654600181018855878452919092200155508061463d81614e03565b9150506145f6565b5060005b81811015614697576001600160a01b0389166000908152600d60209081526040808320848452825282205485546001810187558684529190922001558061468f81614e03565b915050614649565b506146a38560016151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b6001600160a01b03821660009081526009602052604081205461470490600190614db7565b6000838152600e6020526040902054909150808203614753576001600160a01b0384166000908152600d602090815260408083208584528252808320839055858352600e909152812055612338565b6001600160a01b03939093166000908152600d6020908152604080832093835292815282822080548684528484208190558352600e9091528282209490945592839055908252812055565b6001600160a01b038116600090815260196020526040812054429063ffffffff16801580159061480757506001600160a01b038416600090815260186020526040812083916147ee600185614d0b565b63ffffffff168152602081019190915260400160002054145b1561136657611b15600182614d0b565b6001600160e01b031981168114611a4857600080fd5b60006020828403121561483f57600080fd5b813561136681614817565b60005b8381101561486557818101518382015260200161484d565b838111156123385750506000910152565b6000815180845261488e81602086016020860161484a565b601f01601f19169290920160200192915050565b6020815260006113666020830184614876565b80356001600160a01b03811681146148cc57600080fd5b919050565b600080604083850312156148e457600080fd5b6148ed836148b5565b946020939093013593505050565b60006020828403121561490d57600080fd5b5035919050565b60006020828403121561492657600080fd5b611366826148b5565b6000806040838503121561494257600080fd5b50508035926020909101359150565b60008060006060848603121561496657600080fd5b61496f846148b5565b925061497d602085016148b5565b9150604084013590509250925092565b600080604083850312156149a057600080fd5b6149a9836148b5565b91506149b7602084016148b5565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149ff576149ff6149c0565b604052919050565b60008060408385031215614a1a57600080fd5b823567ffffffffffffffff80821115614a3257600080fd5b818501915085601f830112614a4657600080fd5b8135602082821115614a5a57614a5a6149c0565b8160051b9250614a6b8184016149d6565b8281529284018101928181019089851115614a8557600080fd5b948201945b84861015614aa357853582529482019490820190614a8a565b9997909101359750505050505050565b600081518084526020808501945080840160005b83811015614ae357815187529582019590820190600101614ac7565b509495945050505050565b604081526000614b016040830185614ab3565b82810360208401526139dc8185614ab3565b8015158114611a4857600080fd5b60008060408385031215614b3457600080fd5b614b3d836148b5565b91506020830135614b4d81614b13565b809150509250929050565b600067ffffffffffffffff821115614b7257614b726149c0565b50601f01601f191660200190565b60008060008060808587031215614b9657600080fd5b614b9f856148b5565b9350614bad602086016148b5565b925060408501359150606085013567ffffffffffffffff811115614bd057600080fd5b8501601f81018713614be157600080fd5b8035614bf4614bef82614b58565b6149d6565b818152886020838501011115614c0957600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c08789031215614c4457600080fd5b614c4d876148b5565b95506020870135945060408701359350606087013560ff81168114614c7157600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614ca057600080fd5b8335925060208401359150614cb7604085016148b5565b90509250925092565b60008060408385031215614cd357600080fd5b614cdc836148b5565b9150602083013563ffffffff81168114614b4d57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614d2857614d28614cf5565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff80841680614d5d57614d5d614d30565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b600082821015614dc957614dc9614cf5565b500390565b600060208284031215614de057600080fd5b815161136681614b13565b60008219821115614dfe57614dfe614cf5565b500190565b600060018201614e1557614e15614cf5565b5060010190565b60208082526026908201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060408201526566757475726560d01b606082015260800190565b6020808252601e908201527f566f74696e67206c6f636b2063616e2062652032207965617273206d61780000604082015260600190565b6000816000190483118215151615614eb357614eb3614cf5565b500290565b600082614ec757614ec7614d30565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611d0590830184614876565b600060208284031215614f5557600080fd5b815161136681614817565b600060208284031215614f7257600080fd5b815167ffffffffffffffff811115614f8957600080fd5b8201601f81018413614f9a57600080fd5b8051614fa8614bef82614b58565b818152856020838501011115614fbd57600080fd5b6139dc82602083016020860161484a565b600081600f0b83600f0b80614fe557614fe5614d30565b60016001607f1b031982146000198214161561500357615003614cf5565b90059392505050565b600081600f0b83600f0b60016001607f1b0360008213600084138383048511828216161561503c5761503c614cf5565b60016001607f1b0319600085128281168783058712161561505f5761505f614cf5565b6000871292508582058712848416161561507b5761507b614cf5565b8585058712818416161561509157615091614cf5565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156150cc576150cc614cf5565b8160016001607f1b030183138116156150e7576150e7614cf5565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561511b5761511b614cf5565b8260016001607f1b031903821281161561513757615137614cf5565b50019392505050565b60008083128015600160ff1b85018412161561515e5761515e614cf5565b6001600160ff1b038401831381161561517957615179614cf5565b50500390565b634e487b7160e01b600052602160045260246000fd5b8481526020810184905260808101600684106151c157634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff8083168185168083038211156151f2576151f2614cf5565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ab3f9995a4d29008ce65cb5296e414f66fe543304d8d1fe03fa30e9a507fadbc64736f6c634300080d003300000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061043e5760003560e01c80637116c60c11610236578063bfe109281161013b578063e441135c116100c3578063f1127ed811610087578063f1127ed814610bbe578063f8a0576314610be9578063fbd3a29d14610c0c578063fc0c546a14610c1f578063fd4a77f114610c4657600080fd5b8063e441135c14610b15578063e7a324dc14610b35578063e7e242d414610b5c578063e985e9c514610b6f578063ee99fe2814610bab57600080fd5b8063c87b56dd1161010a578063c87b56dd14610a8b578063d1c2babb14610a9e578063d1febfb914610ab1578063d4e54c3b14610aef578063e0514aba14610b0257600080fd5b8063bfe1092814610a4a578063c1f0fb9f14610a5d578063c2c4c5c114610a70578063c3cda52014610a7857600080fd5b806395d89b41116101be578063a183af521161018d578063a183af52146109aa578063a22cb465146109bd578063a4d855df146109d0578063b45a3c0e146109e3578063b88d4fde14610a3757600080fd5b806395d89b411461094c578063981b24d014610971578063986b7d8a146109845780639ab24eb01461099757600080fd5b806385f2aef21161020557806385f2aef2146108e75780638c2c9baf146108fa5780638e539e8c1461090d5780638fbb38ff14610920578063900cf0cf1461094357600080fd5b80637116c60c1461087e578063711974841461089157806375619ab5146108b45780637ecebe00146108c757600080fd5b806335cf668a116103475780635594a045116102cf5780636352211e116102935780636352211e146107d457806365fc3873146107fd5780636f548837146108255780636fcfff451461084557806370a082311461086b57600080fd5b80635594a0451461077157806356afe74414610784578063587cde1e146107a55780635c19a95c146107b85780635f5b0c32146107cb57600080fd5b8063461f711c11610316578063461f711c146106e857806346c96aac1461070e578063485cc955146107275780634bc2a6571461073a57806354fd4d501461074d57600080fd5b806335cf668a1461068c5780633a46b1a8146106af57806342842e0e146106c2578063430c2081146106d557600080fd5b806318160ddd116103ca57806325a58b561161039957806325a58b56146106105780632e1a7d4d146106165780632e720f7d146106295780632f745c591461063c578063313ce5671461067257600080fd5b806318160ddd146105bb5780631c984bc3146105c357806320606b70146105d657806323b872dd146105fd57600080fd5b8063081812fc11610411578063081812fc146104f7578063095cf5c614610538578063095ea7b31461054d5780630d6a2033146105605780631376f3da1461058057600080fd5b806301ffc9a714610443578063047fc9aa1461048557806306fdde031461049c5780630758c7d8146104cf575b600080fd5b61047061045136600461482d565b6001600160e01b03191660009081526005602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61048e60145481565b60405190815260200161047c565b6104c2604051806040016040528060078152602001660eccaa6eec2e0b60cb1b81525081565b60405161047c91906148a2565b6104e26104dd3660046148d1565b610c59565b60405163ffffffff909116815260200161047c565b6105206105053660046148fb565b6000908152600a60205260409020546001600160a01b031690565b6040516001600160a01b03909116815260200161047c565b61054b610546366004614914565b610dcc565b005b61054b61055b3660046148d1565b610e05565b61048e61056e3660046148fb565b60156020526000908152604090205481565b61059361058e36600461492f565b610eed565b60408051600f95860b81529390940b602084015292820152606081019190915260800161047c565b61048e610f34565b61048e6105d136600461492f565b610f44565b61048e7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b61054b61060b366004614951565b610f76565b4361048e565b61054b6106243660046148fb565b610f87565b61054b610637366004614914565b611267565b61048e61064a3660046148d1565b6001600160a01b03919091166000908152600d60209081526040808320938352929052205490565b61067a601281565b60405160ff909116815260200161047c565b61048e61069a3660046148fb565b60009081526011602052604090206001015490565b61048e6106bd3660046148d1565b6112a0565b61054b6106d0366004614951565b61133f565b6104706106e33660046148d1565b61135a565b6106fb6106f63660046148fb565b61136d565b604051600f9190910b815260200161047c565b600054610520906201000090046001600160a01b031681565b61054b61073536600461498d565b6113b0565b61054b610748366004614914565b611624565b6104c2604051806040016040528060058152602001640312e302e360dc1b81525081565b600254610520906001600160a01b031681565b610797610792366004614a07565b611665565b60405161047c929190614aee565b6105206107b3366004614914565b6119fd565b61054b6107c6366004614914565b611a2d565b61048e61040081565b6105206107e23660046148fb565b6000908152600860205260409020546001600160a01b031690565b61081061080b36600461492f565b611a4b565b6040805192835260208301919091520161047c565b61048e6108333660046148fb565b600c6020526000908152604090205481565b6104e2610853366004614914565b60196020526000908152604090205463ffffffff1681565b61048e610879366004614914565b611a9f565b61048e61088c3660046148fb565b611abd565b6106fb61089f3660046148fb565b601360205260009081526040902054600f0b81565b61054b6108c2366004614914565b611b1d565b61048e6108d5366004614914565b601a6020526000908152604090205481565b600154610520906001600160a01b031681565b61048e61090836600461492f565b611b56565b61048e61091b3660046148fb565b611b62565b61047061092e3660046148fb565b60166020526000908152604090205460ff1681565b61048e60125481565b6104c2604051806040016040528060068152602001650eccaa6aea0f60d31b81525081565b61048e61097f3660046148fb565b611b6d565b61054b6109923660046148fb565b611d0f565b61048e6109a5366004614914565b611d59565b61048e6109b836600461492f565b611e2c565b61054b6109cb366004614b21565b611f4c565b61048e6109de36600461492f565b611fd0565b610a176109f13660046148fb565b601160205260009081526040902080546001820154600290920154600f9190910b919083565b60408051600f9490940b845260208401929092529082015260600161047c565b61054b610a45366004614b80565b61219f565b600354610520906001600160a01b031681565b61054b610a6b3660046148fb565b61233e565b61054b612373565b61054b610a86366004614c2b565b6123c1565b6104c2610a993660046148fb565b61272a565b61048e610aac36600461492f565b61286e565b610593610abf3660046148fb565b600460205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b610810610afd366004614c8b565b612a7b565b61048e610b1036600461492f565b612ad0565b61048e610b233660046148fb565b600f6020526000908152604090205481565b61048e7fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b61048e610b6a3660046148fb565b612adc565b610470610b7d36600461498d565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205460ff1690565b61048e610bb936600461492f565b612b04565b61048e610bcc366004614cc0565b601860209081526000928352604080842090915290825290205481565b61048e610bf73660046148fb565b60009081526011602052604090206002015490565b61054b610c1a3660046148fb565b612beb565b6105207f00000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf81565b61054b610c543660046148fb565b612c22565b6001600160a01b03821660009081526019602052604081205463ffffffff16808203610c89576000915050610dc6565b6001600160a01b03841660009081526018602052604081208491610cae600185614d0b565b63ffffffff16815260208101919091526040016000205411610cdd57610cd5600182614d0b565b915050610dc6565b6001600160a01b0384166000908152601860209081526040808320838052909152902054831015610d12576000915050610dc6565b600080610d20600184614d0b565b90505b8163ffffffff168163ffffffff161115610dc15760006002610d458484614d0b565b610d4f9190614d46565b610d599083614d0b565b6001600160a01b038816600090815260186020908152604080832063ffffffff851684529091529020805491925090879003610d9b57509350610dc692505050565b8054871115610dac57819350610dba565b610db7600183614d0b565b92505b5050610d23565b509150505b92915050565b6001546001600160a01b03163314610de357600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600860205260409020546001600160a01b031680610e2757600080fd5b806001600160a01b0316836001600160a01b031603610e4557600080fd5b6000828152600860209081526040808320546001600160a01b038581168552600b845282852033808752945291909320549216149060ff168180610e865750805b610e8f57600080fd5b6000848152600a602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b601060205281600052604060002081633b9aca008110610f0c57600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610f3f42611abd565b905090565b600082815260106020526040812082633b9aca008110610f6657610f66614d69565b6003020160010154905092915050565b610f8283838333612c5a565b505050565b60075460ff1660011901610f9a57600080fd5b6007805460ff19166002179055610fb13382612d29565b610fbd57610fbd614d7f565b600081815260156020526040902054158015610fe8575060008181526016602052604090205460ff16155b61100d5760405162461bcd60e51b815260040161100490614d95565b60405180910390fd5b60008181526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181018290529042101561108d5760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401611004565b80516040805160608101825260008082526020808301828152838501838152888452601190925293909120915182546001600160801b0319166001600160801b03909116178255915160018201559051600290910155601454600f9190910b906110f78282614db7565b601481905550611128848460405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b60405163a9059cbb60e01b8152336004820152602481018390527f00000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf6001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b99190614dce565b6111c5576111c5614d7f565b6111ce8461343a565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8161123c8482614db7565b6040805192835260208301919091520160405180910390a150506007805460ff191660011790555050565b6001546001600160a01b0316331461127e57600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000806112ad8484610c59565b6001600160a01b038516600090815260186020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156113355760008382815481106112fe576112fe614d69565b9060005260206000200154905061131581886134fb565b61131f9084614deb565b925050808061132d90614e03565b9150506112e1565b5095945050505050565b610f828383836040518060200160405280600081525061219f565b60006113668383612d29565b9392505050565b6000818152600f60209081526040808320546010909252822081633b9aca00811061139a5761139a614d69565b6003020154600160801b9004600f0b9392505050565b600054610100900460ff16158080156113d05750600054600160ff909116105b806113ea5750303b1580156113ea575060005460ff166001145b61144d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611004565b6000805460ff191660011790558015611470576000805461ff0019166101001790555b600080546001600160a01b03808516620100000262010000600160b01b0319909216919091178255600180546001600160a01b0319908116331782556002805493881693909116929092179091556007805460ff199081168317909155437f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee55427f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed5560056020527fc01909ce2b517f8cd3a46ae0cfde9179f9b675cf633d3d84c8226585cc73c15680548216831790557f072ad3113145b5af48d301e3b9fc3bd1c97c3f26a14f5d44904b71469875631e8054821683179055635b5e139f60e01b83527f3b767bd59d7164fff7ec5b80ca1165d9d6e12ee8656896fac4159b0760bfd9f7805490911690911790556006546040519091309160008051602061523f833981519152908290a4600654604051600090309060008051602061523f833981519152908390a48015610f82576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b6001546001600160a01b0316331461163b57600080fd5b600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6000818152601560205260409020546060908190158015611695575060008381526016602052604090205460ff16155b6116b15760405162461bcd60e51b815260040161100490614d95565b6116bb3384612d29565b6116c457600080fd5b6000838152600860209081526040808320546011835281842082516060810184528154600f0b808252600183015495820195909552600290910154928101929092526001600160a01b03169290911361171c57600080fd5b8051601454611734916001600160801b031690614db7565b6014556000805b875182101561177d5787828151811061175657611756614d69565b6020026020010151816117699190614deb565b90508161177581614e03565b92505061173b565b6040805160608082018352600080835260208084018281528486018381528d845260118352868420955186546001600160801b0319166001600160801b03909116178655905160018601555160029094019390935583519182018452808252918101829052918201526117f39088908590612d8c565b6117fc8761343a565b60408301514281116118205760405162461bcd60e51b815260040161100490614e1c565b61182e6303c2670042614deb565b81111561184d5760405162461bcd60e51b815260040161100490614e62565b885167ffffffffffffffff811115611867576118676149c0565b604051908082528060200260200182016040528015611890578160200160208202803683370190505b509650885167ffffffffffffffff8111156118ad576118ad6149c0565b6040519080825280602002602001820160405280156118d6578160200160208202803683370190505b50955060008093505b89518410156119f0576006600081546118f790614e03565b90915550600654985061190a868a6135cf565b50828a858151811061191e5761191e614d69565b602002602001015186600001516001600160801b031661193e9190614e99565b6119489190614eb8565b60208087015160008c8152601183526040908190206001810183905581516060810183528154600f0b81529384019290925260029091015490820152909150611998908a9083908590600561362e565b888885815181106119ab576119ab614d69565b6020026020010181815250506119c189426134fb565b8785815181106119d3576119d3614d69565b6020908102919091010152836119e881614e03565b9450506118df565b5050505050509250929050565b6001600160a01b038082166000908152601760205260408120549091168015611a265780611366565b5090919050565b6001600160a01b038116611a3e5750335b611a48338261387e565b50565b600754600090819060ff1660011901611a6357600080fd5b6007805460ff19166002179055611a7b8484336138f1565b9150611a8782426134fb565b6007805460ff19166001179055919491935090915050565b6001600160a01b038116600090815260096020526040812054610dc6565b601254600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152909190611b1581856139e5565b949350505050565b6001546001600160a01b03163314611b3457600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006113668383613ae4565b6000610dc682611abd565b600043821115611b7f57611b7f614d7f565b6012546000611b8e8483613dbd565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606082015291925083831015611c9d576000600481611bf1866001614deb565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606080830182905285015191925014611c975782606001518160600151611c5d9190614db7565b83604001518260400151611c719190614db7565b6060850151611c80908a614db7565b611c8a9190614e99565b611c949190614eb8565b91505b50611cec565b43826060015114611cec576060820151611cb79043614db7565b6040830151611cc69042614db7565b6060840151611cd59089614db7565b611cdf9190614e99565b611ce99190614eb8565b90505b611d0582828460400151611d009190614deb565b6139e5565b9695505050505050565b6000546201000090046001600160a01b03163314611d2c57600080fd5b600081815260156020526040902054611d4790600190614db7565b60009182526015602052604090912055565b6001600160a01b03811660009081526019602052604081205463ffffffff16808203611d885750600092915050565b6001600160a01b038316600090815260186020526040812081611dac600185614d0b565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b8254811015611e23576000838281548110611dec57611dec614d69565b90600052602060002001549050611e0381426134fb565b611e0d9084614deb565b9250508080611e1b90614e03565b915050611dcf565b50949350505050565b60075460009060ff1660011901611e4257600080fd5b6007805460ff19166002179055611e593384612d29565b611e6557611e65614d7f565b60008381526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181019190915282611eaa57611eaa614d7f565b60008160000151600f0b13611efa5760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401611004565b42816040015111611f1d5760405162461bcd60e51b815260040161100490614ecc565b611f2c8484600084600261362e565b611f3684426134fb565b9150506007805460ff1916600117905592915050565b336001600160a01b03831603611f6457611f64614d7f565b336000818152600b602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60075460009060ff1660011901611fe657600080fd5b6007805460ff19166002179055611ffd3384612d29565b61200957612009614d7f565b600083815260116020908152604080832081516060810183528154600f0b8152600182015493810193909352600201549082015290610e108061204c8642614deb565b6120569190614eb8565b6120609190614e99565b9050428260400151116120a45760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401611004565b60008260000151600f0b136120ef5760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401611004565b816040015181116121425760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401611004565b6121506303c2670042614deb565b81111561216f5760405162461bcd60e51b815260040161100490614e62565b61217e8560008385600361362e565b61218885426134fb565b925050506007805460ff1916600117905592915050565b6121ab84848433612c5a565b823b1561233857604051630a85bd0160e11b81526001600160a01b0384169063150b7a02906121e4903390889087908790600401614f10565b6020604051808303816000875af192505050801561221f575060408051601f3d908101601f1916820190925261221c91810190614f43565b60015b6122c7573d80801561224d576040519150601f19603f3d011682016040523d82523d6000602084013e612252565b606091505b5080516000036122bf5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401611004565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146123365760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401611004565b505b50505050565b6000546201000090046001600160a01b0316331461235b57600080fd5b6000908152601660205260409020805460ff19169055565b6123bf600060405180606001604052806000600f0b815260200160008152602001600081525060405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b565b336001600160a01b038716036123d657600080fd5b6001600160a01b0386166123e957600080fd5b60408051808201825260078152660eccaa6eec2e0b60cb1b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f1de6a1c189dcc4ee6a95fb1fdc3a550060accb8f042ce71a27c9dd46bee30732818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156125aa573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166126245760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401611004565b6001600160a01b0381166000908152601a6020526040812080549161264883614e03565b9190505589146126ad5760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401611004565b874211156127145760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401611004565b61271e818b61387e565b50505050505050505050565b6000818152600860205260409020546060906001600160a01b03166127915760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401611004565b60008281526011602090815260409182902082516060810184528154600f0b81526001820154928101929092526002908101549282019290925290546001600160a01b031663dd9ec149846127e681426134fb565b604080860151865191516001600160e01b031960e087901b168152612829949392600f0b9060040193845260208401929092526040830152606082015260800190565b600060405180830381865afa158015612846573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190614f60565b600082815260156020526040812054158015612899575060008381526016602052604090205460ff16155b6128b55760405162461bcd60e51b815260040161100490614d95565b8183036128c157600080fd5b6128cb3384612d29565b6128d457600080fd5b6128de3383612d29565b6128e757600080fd5b60008381526011602081815260408084208151606080820184528254600f90810b8352600180850154848801526002948501548487019081528b8a529787529785902085519283018652805490910b825296870154948101949094529401549082015290514210801561295d5750428160400151115b61296657600080fd5b60008260000151600f0b9050600082604001518460400151101561298e578260400151612994565b83604001515b90508260200151846020015110156129b05783602001516129b6565b82602001515b6020848101919091526040805160608101825260008082528184018181528284018281528c83526011909552929020905181546001600160801b0319166001600160801b03909116178155905160018201559051600290910155601454612a1e908390614db7565b601481905550612a4f878560405180606001604052806000600f0b8152602001600081526020016000815250612d8c565b612a588761343a565b612a6686838386600461362e565b612a7086426134fb565b979650505050505050565b600754600090819060ff1660011901612a9357600080fd5b6007805460ff19166002179055612aab8585856138f1565b9150612ab782426134fb565b6007805460ff1916600117905591959194509092505050565b600061136683836134fb565b6000818152600c6020526040812054439003612afa57506000919050565b610dc682426134fb565b60075460009060ff1660011901612b1a57600080fd5b6007805460ff1916600290811790915560008481526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252909201549082015282612b6957600080fd5b60008160000151600f0b13612bb95760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401611004565b42816040015111612bdc5760405162461bcd60e51b815260040161100490614ecc565b611f2c8484600084600061362e565b6000546201000090046001600160a01b03163314612c0857600080fd5b600081815260156020526040902054611d47906001614deb565b6000546201000090046001600160a01b03163314612c3f57600080fd5b6000908152601660205260409020805460ff19166001179055565b600082815260156020526040902054158015612c85575060008281526016602052604090205460ff16155b612ca15760405162461bcd60e51b815260040161100490614d95565b612cab8183612d29565b612cb457600080fd5b612cbe8483613e43565b612cc88483613eaa565b612ce3612cd4856119fd565b612cdd856119fd565b84613f2b565b612ced838361428d565b6000828152600c60205260408082204390555183916001600160a01b03808716929088169160008051602061523f83398151915291a450505050565b600081815260086020908152604080832054600a8352818420546001600160a01b03918216808652600b855283862088841680885295529285205492938085149392909116149060ff168280612d7c5750815b80612a7057509695505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260408051608081018252600080825260208201819052918101829052606081019190915260125460009081908715612ef057428760400151118015612dfc575060008760000151600f0b135b15612e3f578651612e12906303c2670090614fce565b600f0b60208601526040870151612e2a904290614db7565b8560200151612e39919061500c565b600f0b85525b428660400151118015612e59575060008660000151600f0b135b15612e9c578551612e6f906303c2670090614fce565b600f0b60208501526040860151612e87904290614db7565b8460200151612e96919061500c565b600f0b84525b604080880151600090815260136020528190205490870151600f9190910b935015612ef0578660400151866040015103612ed857829150612ef0565b604080870151600090815260136020522054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612f65575060008181526004602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b604081015181600042831015612fb2576040840151612f849042614db7565b6060850151612f939043614db7565b612fa590670de0b6b3a7640000614e99565b612faf9190614eb8565b90505b6000610e10612fc18186614eb8565b612fcb9190614e99565b905060005b60ff81101561314457612fe5610e1083614deb565b9150600042831115612ff95742925061300d565b50600082815260136020526040902054600f0b5b6130178684614db7565b8760200151613026919061500c565b875188906130359083906150a1565b600f0b90525060208701805182919061304f9083906150f1565b600f90810b90915288516000910b1215905061306a57600087525b60008760200151600f0b121561308257600060208801525b60408088018490528501519295508592670de0b6b3a7640000906130a69085614db7565b6130b09086614e99565b6130ba9190614eb8565b85606001516130c99190614deb565b60608801526130d9600189614deb565b97504283036130ee5750436060870152613144565b6000888152600460209081526040918290208951918a01516001600160801b03908116600160801b02921691909117815590880151600182015560608801516002909101555061313d81614e03565b9050612fd0565b505060128590558b156131cf578860200151886020015161316591906150a1565b8460200181815161317691906150f1565b600f0b9052508851885161318a91906150a1565b845185906131999083906150f1565b600f90810b90915260208601516000910b121590506131ba57600060208501525b60008460000151600f0b12156131cf57600084525b6000858152600460209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b1561342c57428b60400151111561328357602089015161323590886150f1565b96508a604001518a604001510361325857602088015161325590886150a1565b96505b60408b810151600090815260136020522080546001600160801b0319166001600160801b0389161790555b428a6040015111156132db578a604001518a6040015111156132db5760208801516132ae90876150a1565b60408b810151600090815260136020522080546001600160801b0319166001600160801b03831617905595505b60008c8152600f60205260408120546132f5906001614deb565b905080600f60008f815260200190815260200160002081905550428960400181815250504389606001818152505088601060008f815260200190815260200160002082633b9aca00811061334b5761334b614d69565b825160208401516001600160801b03908116600160801b0291161760039190910291909101908155604082015160018201556060909101516002909101557f8d83e324303a2f547eb8572fb6b42fb04620c4a95f09c9a1c8c6e5ac8f4624ed6133c98e6000908152600860205260409020546001600160a01b031690565b8e8b600001518c602001518d604001518e60600151604051613422969594939291906001600160a01b039690961686526020860194909452600f92830b6040860152910b6060840152608083015260a082015260c00190565b60405180910390a1505b505050505050505050505050565b6134443382612d29565b6134905760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401611004565b6000818152600860205260408120546001600160a01b0316906134b39083610e05565b6134c76134bf826119fd565b600084613f2b565b6134d18183613eaa565b60405182906000906001600160a01b0384169060008051602061523f833981519152908390a45050565b6000828152600f602052604081205480820361351b576000915050610dc6565b600084815260106020526040812082633b9aca00811061353d5761353d614d69565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820183905260020154606082015291506135899085615140565b8160200151613598919061500c565b815182906135a79083906150a1565b600f90810b90915282516000910b121590506135c257600081525b51600f0b9150610dc69050565b60006001600160a01b0383166135e7576135e7614d7f565b6135f56000612cdd856119fd565b6135ff838361428d565b60405182906001600160a01b0385169060009060008051602061523f833981519152908290a450600192915050565b601454829061363d8682614deb565b601455604080516060810182526000808252602080830182815283850192835286519187015194870151909252929052600f9190910b81528251879084906136869083906150f1565b600f0b905250851561369a57604083018690525b82602001516000036136ad574260208401525b600088815260116020908152604091829020855181546001600160801b0319166001600160801b03909116178155908501516001820155908401516002909101556136f9888285612d8c565b33871580159061371b575060048560058111156137185761371861517f565b14155b8015613739575060058560058111156137365761373661517f565b14155b156137e3576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018a90527f00000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf16906323b872dd906064016020604051808303816000875af11580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d79190614dce565b6137e3576137e3614d7f565b8360400151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516138279493929190615195565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8361385b8a82614deb565b6040805192835260208301919091520160405180910390a1505050505050505050565b6000613889836119fd565b6001600160a01b0384811660008181526017602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610f82838284614323565b600080610e10806139028642614deb565b61390c9190614eb8565b6139169190614e99565b90506000851161392557600080fd5b4281116139445760405162461bcd60e51b815260040161100490614e1c565b6139526303c2670042614deb565b8111156139715760405162461bcd60e51b815260040161100490614e62565b60066000815461398090614e03565b9091555060065461399184826135cf565b5060008181526011602090815260409182902082516060810184528154600f0b815260018083015493820193909352600290910154928101929092526139dc9183918991869161362e565b95945050505050565b6000808390506000610e10808360400151613a009190614eb8565b613a0a9190614e99565b905060005b60ff811015613abc57613a24610e1083614deb565b9150600085831115613a3857859250613a4c565b50600082815260136020526040902054600f0b5b6040840151613a5b9084614db7565b8460200151613a6a919061500c565b84518590613a799083906150a1565b600f0b905250858303613a8c5750613abc565b8084602001818151613a9e91906150f1565b600f0b9052505060408301829052613ab581614e03565b9050613a0f565b5060008260000151600f0b1215613ad257600082525b50516001600160801b03169392505050565b600043821115613af657613af6614d7f565b6000838152600f6020526040812054815b6080811015613b965781831015613b965760006002613b268486614deb565b613b31906001614deb565b613b3b9190614eb8565b6000888152601060205260409020909150869082633b9aca008110613b6257613b62614d69565b600302016002015411613b7757809350613b85565b613b82600182614db7565b92505b50613b8f81614e03565b9050613b07565b50600085815260106020526040812083633b9aca008110613bb957613bb9614d69565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282019290925260029091015460608201526012549091506000613c0e8783613dbd565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508084841015613ced576000600481613c72876001614deb565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052860151919250613ccf9190614db7565b925083604001518160400151613ce59190614db7565b915050613d11565b6060830151613cfc9043614db7565b9150826040015142613d0e9190614db7565b90505b60408301518215613d4e578284606001518c613d2d9190614db7565b613d379084614e99565b613d419190614eb8565b613d4b9082614deb565b90505b6040870151613d5d9082614db7565b8760200151613d6c919061500c565b87518890613d7b9083906150a1565b600f90810b90915288516000910b129050613dab57505093516001600160801b03169650610dc695505050505050565b60009950505050505050505050610dc6565b60008082815b6080811015613e395781831015613e395760006002613de28486614deb565b613ded906001614deb565b613df79190614eb8565b6000818152600460205260409020600201549091508710613e1a57809350613e28565b613e25600182614db7565b92505b50613e3281614e03565b9050613dc3565b5090949350505050565b6000818152600860205260409020546001600160a01b03838116911614613e6c57613e6c614d7f565b6000818152600a60205260409020546001600160a01b031615613ea6576000818152600a6020526040902080546001600160a01b03191690555b5050565b6000818152600860205260409020546001600160a01b03838116911614613ed357613ed3614d7f565b600081815260086020526040902080546001600160a01b0319169055613ef982826146df565b6001600160a01b0382166000908152600960205260408120805460019290613f22908490614db7565b90915550505050565b816001600160a01b0316836001600160a01b031614158015613f4d5750600081115b15610f82576001600160a01b038316156140ce576001600160a01b03831660009081526019602052604081205463ffffffff169081613fb1576001600160a01b03851660009081526018602090815260408083208380529091529020600101613ff3565b6001600160a01b038516600090815260186020526040812090613fd5600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006140008661479e565b6001600160a01b038716600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561408d57600084828154811061405057614050614d69565b9060005260206000200154905086811461407a578254600181018455600084815260209020018190555b508061408581614e03565b915050614033565b506140998460016151d3565b6001600160a01b0388166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610f82576001600160a01b03821660009081526019602052604081205463ffffffff16908161412d576001600160a01b0384166000908152601860209081526040808320838052909152902060010161416f565b6001600160a01b038416600090815260186020526040812090614151600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061417c8561479e565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915290208354919250600190810191610400916141be9190614deb565b11156141dc5760405162461bcd60e51b8152600401611004906151fb565b60005b835481101561422e5760008482815481106141fc576141fc614d69565b60009182526020808320909101548554600181018755868452919092200155508061422681614e03565b9150506141df565b508054600181810183556000838152602090209091018690556142529085906151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600860205260409020546001600160a01b0316156142b2576142b2614d7f565b600081815260086020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260098084528285208054600d86528487208188528652848720889055878752600e865293862093909355908452909152805460019290613f22908490614deb565b806001600160a01b0316826001600160a01b031614610f82576001600160a01b038216156144d6576001600160a01b03821660009081526019602052604081205463ffffffff16908161439b576001600160a01b038416600090815260186020908152604080832083805290915290206001016143dd565b6001600160a01b0384166000908152601860205260408120906143bf600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006143ea8561479e565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561449557600084828154811061443a5761443a614d69565b600091825260208083209091015480835260089091526040909120549091506001600160a01b03908116908a1614614482578254600181018455600084815260209020018190555b508061448d81614e03565b91505061441d565b506144a18460016151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610f82576001600160a01b03811660009081526019602052604081205463ffffffff169081614535576001600160a01b03831660009081526018602090815260408083208380529091529020600101614577565b6001600160a01b038316600090815260186020526040812090614559600185614d0b565b63ffffffff1663ffffffff1681526020019081526020016000206001015b905060006145848461479e565b6001600160a01b03808616600090815260186020908152604080832063ffffffff861684528252808320938b16835260099091529020548454929350600190910191610400906145d5908390614deb565b11156145f35760405162461bcd60e51b8152600401611004906151fb565b60005b845481101561464557600085828154811061461357614613614d69565b60009182526020808320909101548654600181018855878452919092200155508061463d81614e03565b9150506145f6565b5060005b81811015614697576001600160a01b0389166000908152600d60209081526040808320848452825282205485546001810187558684529190922001558061468f81614e03565b915050614649565b506146a38560016151d3565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b6001600160a01b03821660009081526009602052604081205461470490600190614db7565b6000838152600e6020526040902054909150808203614753576001600160a01b0384166000908152600d602090815260408083208584528252808320839055858352600e909152812055612338565b6001600160a01b03939093166000908152600d6020908152604080832093835292815282822080548684528484208190558352600e9091528282209490945592839055908252812055565b6001600160a01b038116600090815260196020526040812054429063ffffffff16801580159061480757506001600160a01b038416600090815260186020526040812083916147ee600185614d0b565b63ffffffff168152602081019190915260400160002054145b1561136657611b15600182614d0b565b6001600160e01b031981168114611a4857600080fd5b60006020828403121561483f57600080fd5b813561136681614817565b60005b8381101561486557818101518382015260200161484d565b838111156123385750506000910152565b6000815180845261488e81602086016020860161484a565b601f01601f19169290920160200192915050565b6020815260006113666020830184614876565b80356001600160a01b03811681146148cc57600080fd5b919050565b600080604083850312156148e457600080fd5b6148ed836148b5565b946020939093013593505050565b60006020828403121561490d57600080fd5b5035919050565b60006020828403121561492657600080fd5b611366826148b5565b6000806040838503121561494257600080fd5b50508035926020909101359150565b60008060006060848603121561496657600080fd5b61496f846148b5565b925061497d602085016148b5565b9150604084013590509250925092565b600080604083850312156149a057600080fd5b6149a9836148b5565b91506149b7602084016148b5565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149ff576149ff6149c0565b604052919050565b60008060408385031215614a1a57600080fd5b823567ffffffffffffffff80821115614a3257600080fd5b818501915085601f830112614a4657600080fd5b8135602082821115614a5a57614a5a6149c0565b8160051b9250614a6b8184016149d6565b8281529284018101928181019089851115614a8557600080fd5b948201945b84861015614aa357853582529482019490820190614a8a565b9997909101359750505050505050565b600081518084526020808501945080840160005b83811015614ae357815187529582019590820190600101614ac7565b509495945050505050565b604081526000614b016040830185614ab3565b82810360208401526139dc8185614ab3565b8015158114611a4857600080fd5b60008060408385031215614b3457600080fd5b614b3d836148b5565b91506020830135614b4d81614b13565b809150509250929050565b600067ffffffffffffffff821115614b7257614b726149c0565b50601f01601f191660200190565b60008060008060808587031215614b9657600080fd5b614b9f856148b5565b9350614bad602086016148b5565b925060408501359150606085013567ffffffffffffffff811115614bd057600080fd5b8501601f81018713614be157600080fd5b8035614bf4614bef82614b58565b6149d6565b818152886020838501011115614c0957600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c08789031215614c4457600080fd5b614c4d876148b5565b95506020870135945060408701359350606087013560ff81168114614c7157600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614ca057600080fd5b8335925060208401359150614cb7604085016148b5565b90509250925092565b60008060408385031215614cd357600080fd5b614cdc836148b5565b9150602083013563ffffffff81168114614b4d57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614d2857614d28614cf5565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff80841680614d5d57614d5d614d30565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b600082821015614dc957614dc9614cf5565b500390565b600060208284031215614de057600080fd5b815161136681614b13565b60008219821115614dfe57614dfe614cf5565b500190565b600060018201614e1557614e15614cf5565b5060010190565b60208082526026908201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060408201526566757475726560d01b606082015260800190565b6020808252601e908201527f566f74696e67206c6f636b2063616e2062652032207965617273206d61780000604082015260600190565b6000816000190483118215151615614eb357614eb3614cf5565b500290565b600082614ec757614ec7614d30565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611d0590830184614876565b600060208284031215614f5557600080fd5b815161136681614817565b600060208284031215614f7257600080fd5b815167ffffffffffffffff811115614f8957600080fd5b8201601f81018413614f9a57600080fd5b8051614fa8614bef82614b58565b818152856020838501011115614fbd57600080fd5b6139dc82602083016020860161484a565b600081600f0b83600f0b80614fe557614fe5614d30565b60016001607f1b031982146000198214161561500357615003614cf5565b90059392505050565b600081600f0b83600f0b60016001607f1b0360008213600084138383048511828216161561503c5761503c614cf5565b60016001607f1b0319600085128281168783058712161561505f5761505f614cf5565b6000871292508582058712848416161561507b5761507b614cf5565b8585058712818416161561509157615091614cf5565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156150cc576150cc614cf5565b8160016001607f1b030183138116156150e7576150e7614cf5565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561511b5761511b614cf5565b8260016001607f1b031903821281161561513757615137614cf5565b50019392505050565b60008083128015600160ff1b85018412161561515e5761515e614cf5565b6001600160ff1b038401831381161561517957615179614cf5565b50500390565b634e487b7160e01b600052602160045260246000fd5b8481526020810184905260808101600684106151c157634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff8083168185168083038211156151f2576151f2614cf5565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ab3f9995a4d29008ce65cb5296e414f66fe543304d8d1fe03fa30e9a507fadbc64736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf
-----Decoded View---------------
Arg [0] : token_addr (address): 0x90C44218E202995F1c06CB0f0E452dd3b6d8eBDf
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000090c44218e202995f1c06cb0f0e452dd3b6d8ebdf
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.