More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create_lock | 12183634 | 21 days ago | IN | 0 S | 0.0276001 |
Loading...
Loading
Contract Name:
VotingEscrowV1_1
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
london 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 "contracts/interfaces/IERC20.sol"; import {IVeArtProxyV1_1} from "contracts/interfaces/VeArt/IVeArtProxyV1_1.sol"; import {IVotingEscrow} from "contracts/interfaces/IVotingEscrow.sol"; import {Constants} from "contracts/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 VotingEscrowV1_1 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; uint256 start; uint256 end; } struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } /* We cannot really do block numbers per se b/c slope is per time, not per block * and per block could be fairly bad b/c Ethereum changes blocktimes. * What we can do is to extrapolate ***At functions */ /// @notice A checkpoint for marking delegated tokenIds from a given timestamp struct Checkpoint { uint256 timestamp; uint256[] tokenIds; } /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit( address indexed provider, uint256 tokenId, uint256 value, uint256 indexed locktime, DepositType deposit_type, uint256 ts ); event Withdraw(address indexed provider, uint256 tokenId, uint256 value, uint256 ts); event Supply(uint256 prevSupply, uint256 supply); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ address public constant token = 0xA04BC7140c26fc9BB1F36B1A604C7A5a88fb0E70; address public voter; address public team; address public artProxy; address public distributor; mapping(uint256 => 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 uint256 internal 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 public constant name = "veSwapX"; string public constant symbol = "veSWPx"; string public constant version = "1.0.0"; uint8 public constant 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(uint256 _tokenId) external view returns (string memory) { require(idToOwner[_tokenId] != address(0), "Query for nonexistent token"); LockedBalance memory _locked = locked[_tokenId]; bool isListable = attachments[_tokenId] == 0 && !voted[_tokenId]; return IVeArtProxyV1_1(artProxy)._tokenURI( _tokenId, _balanceOfNFT(_tokenId, block.timestamp), _locked.end, uint256(int256(_locked.amount)), isListable ); } /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from NFT ID to the address that owns it. mapping(uint256 => address) internal idToOwner; /// @dev Mapping from owner address to count of his tokens. mapping(address => uint256) internal ownerToNFTokenCount; /// @dev Returns the address of the owner of the NFT. /// @param _tokenId The identifier for an NFT. function ownerOf(uint256 _tokenId) public view returns (address) { return idToOwner[_tokenId]; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function _balance(address _owner) internal view returns (uint256) { return ownerToNFTokenCount[_owner]; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function balanceOf(address _owner) external view returns (uint256) { return _balance(_owner); } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from NFT ID to approved address. mapping(uint256 => address) internal idToApprovals; /// @dev Mapping from owner address to mapping of operator addresses. mapping(address => mapping(address => bool)) internal ownerToOperators; mapping(uint256 => uint256) public ownership_change; /// @dev Get the approved address for a single NFT. /// @param _tokenId ID of the NFT to query the approval of. function getApproved(uint256 _tokenId) external view returns (address) { return idToApprovals[_tokenId]; } /// @dev Checks if `_operator` is an approved operator for `_owner`. /// @param _owner The address that owns the NFTs. /// @param _operator The address that acts on behalf of the owner. function isApprovedForAll(address _owner, address _operator) external view returns (bool) { return (ownerToOperators[_owner])[_operator]; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ /// @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address. /// Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. /// Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP) /// Throws if `_approved` is the current owner. (NOTE: This is not written the EIP) /// @param _approved Address to be approved for the given NFT ID. /// @param _tokenId ID of the token to be approved. function approve(address _approved, uint256 _tokenId) public { address owner = idToOwner[_tokenId]; // Throws if `_tokenId` is not a valid NFT require(owner != address(0)); // Throws if `_approved` is the current owner require(_approved != owner); // Check requirements bool senderIsOwner = (idToOwner[_tokenId] == msg.sender); bool senderIsApprovedForAll = (ownerToOperators[owner])[msg.sender]; require(senderIsOwner || senderIsApprovedForAll); // Set the approval idToApprovals[_tokenId] = _approved; emit Approval(owner, _approved, _tokenId); } /// @dev Enables or disables approval for a third party ("operator") to manage all of /// `msg.sender`'s assets. It also emits the ApprovalForAll event. /// Throws if `_operator` is the `msg.sender`. (NOTE: This is not written the EIP) /// @notice This works even if sender doesn't own any tokens at the time. /// @param _operator Address to add to the set of authorized operators. /// @param _approved True if the operators is approved, false to revoke approval. function setApprovalForAll(address _operator, bool _approved) external { // Throws if `_operator` is the `msg.sender` assert(_operator != msg.sender); ownerToOperators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /* TRANSFER FUNCTIONS */ /// @dev Clear an approval of a given address /// Throws if `_owner` is not the current owner. function _clearApproval(address _owner, uint256 _tokenId) internal { // Throws if `_owner` is not the current owner assert(idToOwner[_tokenId] == _owner); if (idToApprovals[_tokenId] != address(0)) { // Reset approvals idToApprovals[_tokenId] = address(0); } } /// @dev Returns whether the given spender can transfer a given token ID /// @param _spender address of the spender to query /// @param _tokenId uint ID of the token to be transferred /// @return bool whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token function _isApprovedOrOwner(address _spender, uint256 _tokenId) internal view returns (bool) { address owner = idToOwner[_tokenId]; bool spenderIsOwner = owner == _spender; bool spenderIsApproved = _spender == idToApprovals[_tokenId]; bool spenderIsApprovedForAll = (ownerToOperators[owner])[_spender]; return spenderIsOwner || spenderIsApproved || spenderIsApprovedForAll; } function isApprovedOrOwner(address _spender, uint256 _tokenId) external view returns (bool) { return _isApprovedOrOwner(_spender, _tokenId); } /// @dev Exeute transfer of a NFT. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the approved /// address for this NFT. (NOTE: `msg.sender` not allowed in internal function so pass `_sender`.) /// Throws if `_to` is the zero address. /// Throws if `_from` is not the current owner. /// Throws if `_tokenId` is not a valid NFT. function _transferFrom(address _from, address _to, uint256 _tokenId, address _sender) internal { 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, uint256 _tokenId) external { _transferFrom(_from, _to, _tokenId, msg.sender); } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. function safeTransferFrom(address _from, address _to, uint256 _tokenId) external { safeTransferFrom(_from, _to, _tokenId, ""); } function _isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. /// @param _data Additional data with no specified format, sent in call to `_to`. function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public { _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(uint256 => uint256)) internal ownerToNFTokenIdList; /// @dev Mapping from NFT ID to index of owner mapping(uint256 => uint256) internal tokenToOwnerIndex; /// @dev Get token by index function tokenOfOwnerByIndex(address _owner, uint256 _tokenIndex) external view returns (uint256) { return ownerToNFTokenIdList[_owner][_tokenIndex]; } /// @dev Add a NFT to an index mapping to a given address /// @param _to address of the receiver /// @param _tokenId uint ID Of the token to be added function _addTokenToOwnerList(address _to, uint256 _tokenId) internal { uint256 current_count = _balance(_to); ownerToNFTokenIdList[_to][current_count] = _tokenId; tokenToOwnerIndex[_tokenId] = current_count; } /// @dev Add a NFT to a given address /// Throws if `_tokenId` is owned by someone. function _addTokenTo(address _to, uint256 _tokenId) internal { // Throws if `_tokenId` is owned by someone assert(idToOwner[_tokenId] == address(0)); // Change the owner idToOwner[_tokenId] = _to; // Update owner token index tracking _addTokenToOwnerList(_to, _tokenId); // Change count tracking ownerToNFTokenCount[_to] += 1; } /// @dev Function to mint tokens /// Throws if `_to` is zero address. /// Throws if `_tokenId` is owned by someone. /// @param _to The address that will receive the minted tokens. /// @param _tokenId The token id to mint. /// @return A boolean that indicates if the operation was successful. function _mint(address _to, uint256 _tokenId) internal returns (bool) { // Throws if `_to` is zero address assert(_to != address(0)); // 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, uint256 _tokenId) internal { // Delete uint256 current_count = _balance(_from) - 1; uint256 current_index = tokenToOwnerIndex[_tokenId]; if (current_count == current_index) { // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][current_count] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } else { uint256 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, uint256 _tokenId) internal { // Throws if `_from` is not the current owner assert(idToOwner[_tokenId] == _from); // Change the owner idToOwner[_tokenId] = address(0); // Update owner token index tracking _removeTokenFromOwnerList(_from, _tokenId); // Change count tracking ownerToNFTokenCount[_from] -= 1; } function _burn(uint256 _tokenId) internal { require(_isApprovedOrOwner(msg.sender, _tokenId), "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(uint256 => uint256) public user_point_epoch; mapping(uint256 => Point[1000000000]) public user_point_history; // user -> Point[user_epoch] mapping(uint256 => LockedBalance) public locked; uint256 public epoch; mapping(uint256 => int128) public slope_changes; // time -> signed slope change uint256 public supply; uint256 internal constant MAXTIME = 2 * 365 * 86400; int128 internal constant iMAXTIME = 2 * 365 * 86400; uint256 internal constant MULTIPLIER = 1 ether; event DepositCheckpoint(address user, uint256 tokenId, int128 bias, int128 slope, uint256 ts, uint256 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(uint256 _tokenId) external view returns (int128) { uint256 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(uint256 _tokenId, uint256 _idx) external view returns (uint256) { 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(uint256 _tokenId) external view returns (uint256) { 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(uint256 _tokenId) external view returns (uint256) { return locked[_tokenId].end; } /// @notice Record global and per-user data to checkpoint /// @param _tokenId NFT token ID. No user checkpoint if 0 /// @param 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(uint256 _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; uint256 _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]; } uint256 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; uint256 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 { uint256 t_i = (last_checkpoint / Constants.EPOCH_LENGTH) * Constants.EPOCH_LENGTH; for (uint256 i = 0; i < 255; ++i) { // Hopefully it won't happen that this won't get used in 5 years! // If it does, users will be able to withdraw but vote weight will be broken 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 uint256 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( uint256 _tokenId, uint256 _value, uint256 unlock_time, LockedBalance memory locked_balance, DepositType deposit_type ) internal { LockedBalance memory _locked = locked_balance; uint256 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 (uint256) { 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(uint256 _tokenId, uint256 _value) external nonreentrant returns (uint256 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(uint256 _value, uint256 _lock_duration, address _to) internal returns (uint256) { uint256 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; uint256 _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(uint256 _value, uint256 _lock_duration) external nonreentrant returns (uint256 newTokenId, uint256 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(uint256 _value, uint256 _lock_duration, address _to) external nonreentrant returns (uint256 newTokenId, uint256 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(uint256 _tokenId, uint256 _value) external nonreentrant returns (uint256 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(uint256 _tokenId, uint256 _lock_duration) external nonreentrant returns (uint256 votingPower) { assert(_isApprovedOrOwner(msg.sender, _tokenId)); LockedBalance memory _locked = locked[_tokenId]; uint256 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(uint256 _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"); uint256 value = uint256(int256(_locked.amount)); locked[_tokenId] = LockedBalance(0, 0, 0); uint256 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(uint256 _block, uint256 max_epoch) internal view returns (uint256) { // Binary search uint256 _min = 0; uint256 _max = max_epoch; for (uint256 i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint256 _mid = (_min + _max + 1) / 2; if (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(uint256 _tokenId, uint256 _t) internal view returns (uint256) { uint256 _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 uint256(int256(last_point.bias)); } } function balanceOfNFT(uint256 _tokenId) external view returns (uint256) { if (ownership_change[_tokenId] == block.number) return 0; return _balanceOfNFT(_tokenId, block.timestamp); } function balanceOfNFTAt(uint256 _tokenId, uint256 _t) external view returns (uint256) { return _balanceOfNFT(_tokenId, _t); } /// @notice Measure voting power of `_tokenId` at block height `_block` /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime /// @param _tokenId User's wallet NFT /// @param _block Block to calculate the voting power at /// @return Voting power function _balanceOfAtNFT(uint256 _tokenId, uint256 _block) internal view returns (uint256) { // Copying and pasting totalSupply code because Vyper cannot pass by // reference yet assert(_block <= block.number); // Binary search uint256 _min = 0; uint256 _max = user_point_epoch[_tokenId]; for (uint256 i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint256 _mid = (_min + _max + 1) / 2; if (user_point_history[_tokenId][_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } Point memory upoint = user_point_history[_tokenId][_min]; uint256 max_epoch = epoch; uint256 _epoch = _find_block_epoch(_block, max_epoch); Point memory point_0 = point_history[_epoch]; uint256 d_block = 0; uint256 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; } uint256 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 uint256(uint128(upoint.bias)); } else { return 0; } } function balanceOfAtNFT(uint256 _tokenId, uint256 _block) external view returns (uint256) { return _balanceOfAtNFT(_tokenId, _block); } /// @notice Calculate total voting power at some point in the past /// @param _block Block to calculate the total voting power at /// @return Total voting power at `_block` function totalSupplyAt(uint256 _block) external view returns (uint256) { assert(_block <= block.number); uint256 _epoch = epoch; uint256 target_epoch = _find_block_epoch(_block, _epoch); Point memory point = point_history[target_epoch]; uint256 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, uint256 t) internal view returns (uint256) { Point memory last_point = point; uint256 t_i = (last_point.ts / Constants.EPOCH_LENGTH) * Constants.EPOCH_LENGTH; for (uint256 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 uint256(uint128(last_point.bias)); } function totalSupply() external view returns (uint256) { return totalSupplyAtT(block.timestamp); } /// @notice Calculate total voting power /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility /// @return Total voting power function totalSupplyAtT(uint256 t) public view returns (uint256) { uint256 _epoch = epoch; Point memory last_point = point_history[_epoch]; return _supply_at(last_point, t); } /*/////////////////////////////////////////////////////////////// GAUGE VOTING LOGIC //////////////////////////////////////////////////////////////*/ mapping(uint256 => uint256) public attachments; mapping(uint256 => bool) public voted; function setVoter(address _voter) external { require(msg.sender == team); voter = _voter; } function voting(uint256 _tokenId) external { require(msg.sender == voter); voted[_tokenId] = true; } function abstain(uint256 _tokenId) external { require(msg.sender == voter); voted[_tokenId] = false; } function attach(uint256 _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] + 1; } function detach(uint256 _tokenId) external { require(msg.sender == voter); attachments[_tokenId] = attachments[_tokenId] - 1; } function merge(uint256 _from, uint256 _to) external returns (uint256 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); uint256 value0 = uint256(int256(_locked0.amount)); uint256 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(uint256[] memory amounts, uint256 _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); uint256 i; uint256 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 uint256 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 uint256 _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; uint256 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 => uint256) 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 (uint256) { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } uint256[] storage _tokenIds = checkpoints[account][nCheckpoints - 1].tokenIds; uint256 votes = 0; for (uint256 i = 0; i < _tokenIds.length; i++) { uint256 tId = _tokenIds[i]; votes = votes + _balanceOfNFT(tId, block.timestamp); } return votes; } function getPastVotesIndex(address account, uint256 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, uint256 timestamp) public view returns (uint256) { uint32 _checkIndex = getPastVotesIndex(account, timestamp); // Sum votes uint256[] storage _tokenIds = checkpoints[account][_checkIndex].tokenIds; uint256 votes = 0; for (uint256 i = 0; i < _tokenIds.length; i++) { uint256 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 (uint256) { return totalSupplyAtT(timestamp); } /*/////////////////////////////////////////////////////////////// DAO VOTING LOGIC //////////////////////////////////////////////////////////////*/ function _moveTokenDelegates(address srcRep, address dstRep, uint256 _tokenId) internal { if (srcRep != dstRep && _tokenId > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint256[] storage srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].tokenIds : checkpoints[srcRep][0].tokenIds; uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep); uint256[] storage srcRepNew = checkpoints[srcRep][nextSrcRepNum].tokenIds; // All the same except _tokenId for (uint256 i = 0; i < srcRepOld.length; i++) { uint256 tId = srcRepOld[i]; if (tId != _tokenId) { srcRepNew.push(tId); } } numCheckpoints[srcRep] = srcRepNum + 1; } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint256[] storage dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].tokenIds : checkpoints[dstRep][0].tokenIds; uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep); uint256[] storage dstRepNew = checkpoints[dstRep][nextDstRepNum].tokenIds; // All the same plus _tokenId require(dstRepOld.length + 1 <= MAX_DELEGATES, "dstRep would have too many tokenIds"); for (uint256 i = 0; i < dstRepOld.length; i++) { uint256 tId = dstRepOld[i]; dstRepNew.push(tId); } dstRepNew.push(_tokenId); numCheckpoints[dstRep] = dstRepNum + 1; } } } function _findWhatCheckpointToWrite(address account) internal view returns (uint32) { uint256 _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]; uint256[] storage srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].tokenIds : checkpoints[srcRep][0].tokenIds; uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep); uint256[] storage srcRepNew = checkpoints[srcRep][nextSrcRepNum].tokenIds; // All the same except what owner owns for (uint256 i = 0; i < srcRepOld.length; i++) { uint256 tId = srcRepOld[i]; if (idToOwner[tId] != owner) { srcRepNew.push(tId); } } numCheckpoints[srcRep] = srcRepNum + 1; } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint256[] storage dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].tokenIds : checkpoints[dstRep][0].tokenIds; uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep); uint256[] storage dstRepNew = checkpoints[dstRep][nextDstRepNum].tokenIds; uint256 ownerTokenCount = ownerToNFTokenCount[owner]; require(dstRepOld.length + ownerTokenCount <= MAX_DELEGATES, "dstRep would have too many tokenIds"); // All the same for (uint256 i = 0; i < dstRepOld.length; i++) { uint256 tId = dstRepOld[i]; dstRepNew.push(tId); } // Plus all that's owned for (uint256 i = 0; i < ownerTokenCount; i++) { uint256 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, uint256 nonce, uint256 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 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.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 (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 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 IVeArtProxyV1_1 { function _tokenURI(uint256 _tokenId, uint256 _balanceOf, uint256 _locked_end, uint256 _value) external view returns (string memory output); function _tokenURI(uint256 _tokenId, uint256 _balanceOf, uint256 _locked_end, uint256 _value, bool _isListable) external view 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 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 = 7 days; }
// 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.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); }
{ "remappings": [ "@cryptoalgebra/=node_modules/@cryptoalgebra/", "@ensdomains/=node_modules/@ensdomains/", "@openzeppelin/=node_modules/@openzeppelin/", "@uniswap/=node_modules/@uniswap/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "forge-std/=node_modules/forge-std/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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 VotingEscrowV1_1.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":"_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
608060405234801561001057600080fd5b50615019806100206000396000f3fe608060405234801561001057600080fd5b50600436106104335760003560e01c80637116c60c11610236578063bfe109281161013b578063e441135c116100c3578063f1127ed811610087578063f1127ed814610ba0578063f8a0576314610bcb578063fbd3a29d14610bee578063fc0c546a14610c01578063fd4a77f114610c1c57600080fd5b8063e441135c14610af7578063e7a324dc14610b17578063e7e242d414610b3e578063e985e9c514610b51578063ee99fe2814610b8d57600080fd5b8063c87b56dd1161010a578063c87b56dd14610a6d578063d1c2babb14610a80578063d1febfb914610a93578063d4e54c3b14610ad1578063e0514aba14610ae457600080fd5b8063bfe1092814610a2c578063c1f0fb9f14610a3f578063c2c4c5c114610a52578063c3cda52014610a5a57600080fd5b806395d89b41116101be578063a183af521161018d578063a183af521461098c578063a22cb4651461099f578063a4d855df146109b2578063b45a3c0e146109c5578063b88d4fde14610a1957600080fd5b806395d89b411461092e578063981b24d014610953578063986b7d8a146109665780639ab24eb01461097957600080fd5b806385f2aef21161020557806385f2aef2146108c95780638c2c9baf146108dc5780638e539e8c146108ef5780638fbb38ff14610902578063900cf0cf1461092557600080fd5b80637116c60c14610860578063711974841461087357806375619ab5146108965780637ecebe00146108a957600080fd5b806335cf668a1161033c57806356afe744116102c45780636352211e116102935780636352211e146107b657806365fc3873146107df5780636f548837146108075780636fcfff451461082757806370a082311461084d57600080fd5b806356afe74414610766578063587cde1e146107875780635c19a95c1461079a5780635f5b0c32146107ad57600080fd5b8063461f711c1161030b578063461f711c146106dd57806346c96aac146107035780634bc2a6571461071c57806354fd4d501461072f5780635594a0451461075357600080fd5b806335cf668a146106815780633a46b1a8146106a457806342842e0e146106b7578063430c2081146106ca57600080fd5b806318160ddd116103bf57806325a58b561161038e57806325a58b56146106055780632e1a7d4d1461060b5780632e720f7d1461061e5780632f745c5914610631578063313ce5671461066757600080fd5b806318160ddd146105b05780631c984bc3146105b857806320606b70146105cb57806323b872dd146105f257600080fd5b8063081812fc11610406578063081812fc146104ec578063095cf5c61461052d578063095ea7b3146105425780630d6a2033146105555780631376f3da1461057557600080fd5b806301ffc9a714610438578063047fc9aa1461047a57806306fdde03146104915780630758c7d8146104c4575b600080fd5b6104656104463660046145d2565b6001600160e01b03191660009081526005602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61048360145481565b604051908152602001610471565b6104b7604051806040016040528060078152602001660eccaa6eec2e0b60cb1b81525081565b6040516104719190614647565b6104d76104d2366004614676565b610c2f565b60405163ffffffff9091168152602001610471565b6105156104fa3660046146a0565b6000908152600a60205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001610471565b61054061053b3660046146b9565b610da2565b005b610540610550366004614676565b610ddb565b6104836105633660046146a0565b60156020526000908152604090205481565b6105886105833660046146d4565b610ec3565b60408051600f95860b81529390940b6020840152928201526060810191909152608001610471565b610483610f0a565b6104836105c63660046146d4565b610f1a565b6104837f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6105406106003660046146f6565b610f4c565b43610483565b6105406106193660046146a0565b610f5d565b61054061062c3660046146b9565b611228565b61048361063f366004614676565b6001600160a01b03919091166000908152600d60209081526040808320938352929052205490565b61066f601281565b60405160ff9091168152602001610471565b61048361068f3660046146a0565b60009081526011602052604090206001015490565b6104836106b2366004614676565b611261565b6105406106c53660046146f6565b611300565b6104656106d8366004614676565b61131b565b6106f06106eb3660046146a0565b61132e565b604051600f9190910b8152602001610471565b600054610515906201000090046001600160a01b031681565b61054061072a3660046146b9565b611371565b6104b7604051806040016040528060058152602001640312e302e360dc1b81525081565b600254610515906001600160a01b031681565b610779610774366004614779565b6113b2565b604051610471929190614860565b6105156107953660046146b9565b61174a565b6105406107a83660046146b9565b61177a565b61048361040081565b6105156107c43660046146a0565b6000908152600860205260409020546001600160a01b031690565b6107f26107ed3660046146d4565b611798565b60408051928352602083019190915201610471565b6104836108153660046146a0565b600c6020526000908152604090205481565b6104d76108353660046146b9565b60196020526000908152604090205463ffffffff1681565b61048361085b3660046146b9565b6117ec565b61048361086e3660046146a0565b61180a565b6106f06108813660046146a0565b601360205260009081526040902054600f0b81565b6105406108a43660046146b9565b61186a565b6104836108b73660046146b9565b601a6020526000908152604090205481565b600154610515906001600160a01b031681565b6104836108ea3660046146d4565b6118a3565b6104836108fd3660046146a0565b6118af565b6104656109103660046146a0565b60166020526000908152604090205460ff1681565b61048360125481565b6104b7604051806040016040528060068152602001650eccaa6aea0f60d31b81525081565b6104836109613660046146a0565b6118ba565b6105406109743660046146a0565b611a5c565b6104836109873660046146b9565b611aa6565b61048361099a3660046146d4565b611b79565b6105406109ad366004614893565b611c99565b6104836109c03660046146d4565b611d1d565b6109f96109d33660046146a0565b601160205260009081526040902080546001820154600290920154600f9190910b919083565b60408051600f9490940b8452602084019290925290820152606001610471565b610540610a273660046148f2565b611eed565b600354610515906001600160a01b031681565b610540610a4d3660046146a0565b61208c565b6105406120c1565b610540610a6836600461499d565b61210f565b6104b7610a7b3660046146a0565b612478565b610483610a8e3660046146d4565b6125e6565b610588610aa13660046146a0565b600460205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6107f2610adf3660046149fd565b6127f3565b610483610af23660046146d4565b612848565b610483610b053660046146a0565b600f6020526000908152604090205481565b6104837fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b610483610b4c3660046146a0565b612854565b610465610b5f366004614a32565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205460ff1690565b610483610b9b3660046146d4565b61287c565b610483610bae366004614a65565b601860209081526000928352604080842090915290825290205481565b610483610bd93660046146a0565b60009081526011602052604090206002015490565b610540610bfc3660046146a0565b612963565b61051573a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e7081565b610540610c2a3660046146a0565b61299a565b6001600160a01b03821660009081526019602052604081205463ffffffff16808203610c5f576000915050610d9c565b6001600160a01b03841660009081526018602052604081208491610c84600185614ab0565b63ffffffff16815260208101919091526040016000205411610cb357610cab600182614ab0565b915050610d9c565b6001600160a01b0384166000908152601860209081526040808320838052909152902054831015610ce8576000915050610d9c565b600080610cf6600184614ab0565b90505b8163ffffffff168163ffffffff161115610d975760006002610d1b8484614ab0565b610d259190614aeb565b610d2f9083614ab0565b6001600160a01b038816600090815260186020908152604080832063ffffffff851684529091529020805491925090879003610d7157509350610d9c92505050565b8054871115610d8257819350610d90565b610d8d600183614ab0565b92505b5050610cf9565b509150505b92915050565b6001546001600160a01b03163314610db957600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600860205260409020546001600160a01b031680610dfd57600080fd5b806001600160a01b0316836001600160a01b031603610e1b57600080fd5b6000828152600860209081526040808320546001600160a01b038581168552600b845282852033808752945291909320549216149060ff168180610e5c5750805b610e6557600080fd5b6000848152600a602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b601060205281600052604060002081633b9aca008110610ee257600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610f154261180a565b905090565b600082815260106020526040812082633b9aca008110610f3c57610f3c614b0e565b6003020160010154905092915050565b610f58838383336129d2565b505050565b60075460ff1660011901610f7057600080fd5b6007805460ff19166002179055610f873382612ab3565b610f9357610f93614b24565b600081815260156020526040902054158015610fbe575060008181526016602052604090205460ff16155b610fe35760405162461bcd60e51b8152600401610fda90614b3a565b60405180910390fd5b60008181526011602090815260409182902082516060810184528154600f0b815260018201549281019290925260020154918101829052904210156110635760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401610fda565b80516040805160608101825260008082526020808301828152838501838152888452601190925293909120915182546001600160801b0319166001600160801b03909116178255915160018201559051600290910155601454600f9190910b906110cd8282614b5c565b6014819055506110fe848460405180606001604052806000600f0b8152602001600081526020016000815250612b16565b60405163a9059cbb60e01b81523360048201526024810183905273a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e709063a9059cbb906044016020604051808303816000875af1158015611156573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117a9190614b73565b61118657611186614b24565b61118f846131c6565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c816111fd8482614b5c565b6040805192835260208301919091520160405180910390a150506007805460ff191660011790555050565b6001546001600160a01b0316331461123f57600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b60008061126e8484610c2f565b6001600160a01b038516600090815260186020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156112f65760008382815481106112bf576112bf614b0e565b906000526020600020015490506112d68188613299565b6112e09084614b90565b92505080806112ee90614ba8565b9150506112a2565b5095945050505050565b610f5883838360405180602001604052806000815250611eed565b60006113278383612ab3565b9392505050565b6000818152600f60209081526040808320546010909252822081633b9aca00811061135b5761135b614b0e565b6003020154600160801b9004600f0b9392505050565b6001546001600160a01b0316331461138857600080fd5b600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b60008181526015602052604090205460609081901580156113e2575060008381526016602052604090205460ff16155b6113fe5760405162461bcd60e51b8152600401610fda90614b3a565b6114083384612ab3565b61141157600080fd5b6000838152600860209081526040808320546011835281842082516060810184528154600f0b808252600183015495820195909552600290910154928101929092526001600160a01b03169290911361146957600080fd5b8051601454611481916001600160801b031690614b5c565b6014556000805b87518210156114ca578782815181106114a3576114a3614b0e565b6020026020010151816114b69190614b90565b9050816114c281614ba8565b925050611488565b6040805160608082018352600080835260208084018281528486018381528d845260118352868420955186546001600160801b0319166001600160801b03909116178655905160018601555160029094019390935583519182018452808252918101829052918201526115409088908590612b16565b611549876131c6565b604083015142811161156d5760405162461bcd60e51b8152600401610fda90614bc1565b61157b6303c2670042614b90565b81111561159a5760405162461bcd60e51b8152600401610fda90614c07565b885167ffffffffffffffff8111156115b4576115b4614732565b6040519080825280602002602001820160405280156115dd578160200160208202803683370190505b509650885167ffffffffffffffff8111156115fa576115fa614732565b604051908082528060200260200182016040528015611623578160200160208202803683370190505b50955060008093505b895184101561173d5760066000815461164490614ba8565b909155506006549850611657868a61336d565b50828a858151811061166b5761166b614b0e565b602002602001015186600001516001600160801b031661168b9190614c3e565b6116959190614c5d565b60208087015160008c8152601183526040908190206001810183905581516060810183528154600f0b815293840192909252600290910154908201529091506116e5908a908390859060056133de565b888885815181106116f8576116f8614b0e565b60200260200101818152505061170e8942613299565b87858151811061172057611720614b0e565b60209081029190910101528361173581614ba8565b94505061162c565b5050505050509250929050565b6001600160a01b0380821660009081526017602052604081205490911680156117735780611327565b5090919050565b6001600160a01b03811661178b5750335b6117953382613620565b50565b600754600090819060ff16600119016117b057600080fd5b6007805460ff191660021790556117c8848433613693565b91506117d48242613299565b6007805460ff19166001179055919491935090915050565b6001600160a01b038116600090815260096020526040812054610d9c565b601254600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529091906118628185613788565b949350505050565b6001546001600160a01b0316331461188157600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006113278383613889565b6000610d9c8261180a565b6000438211156118cc576118cc614b24565b60125460006118db8483613b62565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250838310156119ea57600060048161193e866001614b90565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052850151919250146119e457826060015181606001516119aa9190614b5c565b836040015182604001516119be9190614b5c565b60608501516119cd908a614b5c565b6119d79190614c3e565b6119e19190614c5d565b91505b50611a39565b43826060015114611a39576060820151611a049043614b5c565b6040830151611a139042614b5c565b6060840151611a229089614b5c565b611a2c9190614c3e565b611a369190614c5d565b90505b611a5282828460400151611a4d9190614b90565b613788565b9695505050505050565b6000546201000090046001600160a01b03163314611a7957600080fd5b600081815260156020526040902054611a9490600190614b5c565b60009182526015602052604090912055565b6001600160a01b03811660009081526019602052604081205463ffffffff16808203611ad55750600092915050565b6001600160a01b038316600090815260186020526040812081611af9600185614ab0565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b8254811015611b70576000838281548110611b3957611b39614b0e565b90600052602060002001549050611b508142613299565b611b5a9084614b90565b9250508080611b6890614ba8565b915050611b1c565b50949350505050565b60075460009060ff1660011901611b8f57600080fd5b6007805460ff19166002179055611ba63384612ab3565b611bb257611bb2614b24565b60008381526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181019190915282611bf757611bf7614b24565b60008160000151600f0b13611c475760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610fda565b42816040015111611c6a5760405162461bcd60e51b8152600401610fda90614c71565b611c79848460008460026133de565b611c838442613299565b9150506007805460ff1916600117905592915050565b336001600160a01b03831603611cb157611cb1614b24565b336000818152600b602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60075460009060ff1660011901611d3357600080fd5b6007805460ff19166002179055611d4a3384612ab3565b611d5657611d56614b24565b600083815260116020908152604080832081516060810183528154600f0b815260018201549381019390935260020154908201529062093a8080611d9a8642614b90565b611da49190614c5d565b611dae9190614c3e565b905042826040015111611df25760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401610fda565b60008260000151600f0b13611e3d5760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401610fda565b81604001518111611e905760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401610fda565b611e9e6303c2670042614b90565b811115611ebd5760405162461bcd60e51b8152600401610fda90614c07565b611ecc856000838560036133de565b611ed68542613299565b925050506007805460ff1916600117905592915050565b611ef9848484336129d2565b823b1561208657604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611f32903390889087908790600401614cb5565b6020604051808303816000875af1925050508015611f6d575060408051601f3d908101601f19168201909252611f6a91810190614ce8565b60015b612015573d808015611f9b576040519150601f19603f3d011682016040523d82523d6000602084013e611fa0565b606091505b50805160000361200d5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610fda565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146120845760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401610fda565b505b50505050565b6000546201000090046001600160a01b031633146120a957600080fd5b6000908152601660205260409020805460ff19169055565b61210d600060405180606001604052806000600f0b815260200160008152602001600081525060405180606001604052806000600f0b8152602001600081526020016000815250612b16565b565b336001600160a01b0387160361212457600080fd5b6001600160a01b03861661213757600080fd5b60408051808201825260078152660eccaa6eec2e0b60cb1b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f1de6a1c189dcc4ee6a95fb1fdc3a550060accb8f042ce71a27c9dd46bee30732818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156122f8573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166123725760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401610fda565b6001600160a01b0381166000908152601a6020526040812080549161239683614ba8565b9190505589146123fb5760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401610fda565b874211156124625760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401610fda565b61246c818b613620565b50505050505050505050565b6000818152600860205260409020546060906001600160a01b03166124df5760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401610fda565b600082815260116020908152604080832081516060810183528154600f0b815260018201548185015260029091015481830152858452601590925282205490919015801561253c575060008481526016602052604090205460ff16155b6002549091506001600160a01b031663b6d11ba58561255b8142613299565b6040868101518751915160e086901b6001600160e01b0319168152600481019490945260248401929092526044830191909152600f0b6064820152831515608482015260a401600060405180830381865afa1580156125be573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118629190810190614d05565b600082815260156020526040812054158015612611575060008381526016602052604090205460ff16155b61262d5760405162461bcd60e51b8152600401610fda90614b3a565b81830361263957600080fd5b6126433384612ab3565b61264c57600080fd5b6126563383612ab3565b61265f57600080fd5b60008381526011602081815260408084208151606080820184528254600f90810b8352600180850154848801526002948501548487019081528b8a529787529785902085519283018652805490910b82529687015494810194909452940154908201529051421080156126d55750428160400151115b6126de57600080fd5b60008260000151600f0b9050600082604001518460400151101561270657826040015161270c565b83604001515b905082602001518460200151101561272857836020015161272e565b82602001515b6020848101919091526040805160608101825260008082528184018181528284018281528c83526011909552929020905181546001600160801b0319166001600160801b03909116178155905160018201559051600290910155601454612796908390614b5c565b6014819055506127c7878560405180606001604052806000600f0b8152602001600081526020016000815250612b16565b6127d0876131c6565b6127de8683838660046133de565b6127e88642613299565b979650505050505050565b600754600090819060ff166001190161280b57600080fd5b6007805460ff19166002179055612823858585613693565b915061282f8242613299565b6007805460ff1916600117905591959194509092505050565b60006113278383613299565b6000818152600c602052604081205443900361287257506000919050565b610d9c8242613299565b60075460009060ff166001190161289257600080fd5b6007805460ff1916600290811790915560008481526011602090815260409182902082516060810184528154600f0b81526001820154928101929092529092015490820152826128e157600080fd5b60008160000151600f0b136129315760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610fda565b428160400151116129545760405162461bcd60e51b8152600401610fda90614c71565b611c79848460008460006133de565b6000546201000090046001600160a01b0316331461298057600080fd5b600081815260156020526040902054611a94906001614b90565b6000546201000090046001600160a01b031633146129b757600080fd5b6000908152601660205260409020805460ff19166001179055565b6000828152601560205260409020541580156129fd575060008281526016602052604090205460ff16155b612a195760405162461bcd60e51b8152600401610fda90614b3a565b612a238183612ab3565b612a2c57600080fd5b612a368483613be8565b612a408483613c4f565b612a5b612a4c8561174a565b612a558561174a565b84613cd0565b612a658383614032565b6000828152600c60205260408082204390555183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b600081815260086020908152604080832054600a8352818420546001600160a01b03918216808652600b855283862088841680885295529285205492938085149392909116149060ff168280612b065750815b806127e857509695505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260408051608081018252600080825260208201819052918101829052606081019190915260125460009081908715612c7a57428760400151118015612b86575060008760000151600f0b135b15612bc9578651612b9c906303c2670090614d73565b600f0b60208601526040870151612bb4904290614b5c565b8560200151612bc39190614db1565b600f0b85525b428660400151118015612be3575060008660000151600f0b135b15612c26578551612bf9906303c2670090614d73565b600f0b60208501526040860151612c11904290614b5c565b8460200151612c209190614db1565b600f0b84525b604080880151600090815260136020528190205490870151600f9190910b935015612c7a578660400151866040015103612c6257829150612c7a565b604080870151600090815260136020522054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612cef575060008181526004602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b604081015181600042831015612d3c576040840151612d0e9042614b5c565b6060850151612d1d9043614b5c565b612d2f90670de0b6b3a7640000614c3e565b612d399190614c5d565b90505b600062093a80612d4c8186614c5d565b612d569190614c3e565b905060005b60ff811015612ed057612d7162093a8083614b90565b9150600042831115612d8557429250612d99565b50600082815260136020526040902054600f0b5b612da38684614b5c565b8760200151612db29190614db1565b87518890612dc1908390614e46565b600f0b905250602087018051829190612ddb908390614e96565b600f90810b90915288516000910b12159050612df657600087525b60008760200151600f0b1215612e0e57600060208801525b60408088018490528501519295508592670de0b6b3a764000090612e329085614b5c565b612e3c9086614c3e565b612e469190614c5d565b8560600151612e559190614b90565b6060880152612e65600189614b90565b9750428303612e7a5750436060870152612ed0565b6000888152600460209081526040918290208951918a01516001600160801b03908116600160801b029216919091178155908801516001820155606088015160029091015550612ec981614ba8565b9050612d5b565b505060128590558b15612f5b5788602001518860200151612ef19190614e46565b84602001818151612f029190614e96565b600f0b90525088518851612f169190614e46565b84518590612f25908390614e96565b600f90810b90915260208601516000910b12159050612f4657600060208501525b60008460000151600f0b1215612f5b57600084525b6000858152600460209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b156131b857428b60400151111561300f576020890151612fc19088614e96565b96508a604001518a6040015103612fe4576020880151612fe19088614e46565b96505b60408b810151600090815260136020522080546001600160801b0319166001600160801b0389161790555b428a604001511115613067578a604001518a60400151111561306757602088015161303a9087614e46565b60408b810151600090815260136020522080546001600160801b0319166001600160801b03831617905595505b60008c8152600f6020526040812054613081906001614b90565b905080600f60008f815260200190815260200160002081905550428960400181815250504389606001818152505088601060008f815260200190815260200160002082633b9aca0081106130d7576130d7614b0e565b825160208401516001600160801b03908116600160801b0291161760039190910291909101908155604082015160018201556060909101516002909101557f8d83e324303a2f547eb8572fb6b42fb04620c4a95f09c9a1c8c6e5ac8f4624ed6131558e6000908152600860205260409020546001600160a01b031690565b8e8b600001518c602001518d604001518e606001516040516131ae969594939291906001600160a01b039690961686526020860194909452600f92830b6040860152910b6060840152608083015260a082015260c00190565b60405180910390a1505b505050505050505050505050565b6131d03382612ab3565b61321c5760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401610fda565b6000818152600860205260408120546001600160a01b03169061323f9083610ddb565b61325361324b8261174a565b600084613cd0565b61325d8183613c4f565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000828152600f60205260408120548082036132b9576000915050610d9c565b600084815260106020526040812082633b9aca0081106132db576132db614b0e565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820183905260020154606082015291506133279085614ee5565b81602001516133369190614db1565b81518290613345908390614e46565b600f90810b90915282516000910b1215905061336057600081525b51600f0b9150610d9c9050565b60006001600160a01b03831661338557613385614b24565b6133936000612a558561174a565b61339d8383614032565b60405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b60145482906133ed8682614b90565b601455604080516060810182526000808252602080830182815283850192835286519187015194870151909252929052600f9190910b8152825187908490613436908390614e96565b600f0b905250851561344a57604083018690525b826020015160000361345d574260208401525b600088815260116020908152604091829020855181546001600160801b0319166001600160801b03909116178155908501516001820155908401516002909101556134a9888285612b16565b3387158015906134cb575060048560058111156134c8576134c8614f24565b14155b80156134e9575060058560058111156134e6576134e6614f24565b14155b15613585576040516323b872dd60e01b81526001600160a01b03821660048201523060248201526044810189905273a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e70906323b872dd906064016020604051808303816000875af1158015613555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135799190614b73565b61358557613585614b24565b8360400151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516135c99493929190614f3a565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c836135fd8a82614b90565b6040805192835260208301919091520160405180910390a1505050505050505050565b600061362b8361174a565b6001600160a01b0384811660008181526017602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610f588382846140c8565b60008062093a80806136a58642614b90565b6136af9190614c5d565b6136b99190614c3e565b9050600085116136c857600080fd5b4281116136e75760405162461bcd60e51b8152600401610fda90614bc1565b6136f56303c2670042614b90565b8111156137145760405162461bcd60e51b8152600401610fda90614c07565b60066000815461372390614ba8565b90915550600654613734848261336d565b5060008181526011602090815260409182902082516060810184528154600f0b8152600180830154938201939093526002909101549281019290925261377f918391899186916133de565b95945050505050565b600080839050600062093a808083604001516137a49190614c5d565b6137ae9190614c3e565b905060005b60ff811015613861576137c962093a8083614b90565b91506000858311156137dd578592506137f1565b50600082815260136020526040902054600f0b5b60408401516138009084614b5c565b846020015161380f9190614db1565b8451859061381e908390614e46565b600f0b9052508583036138315750613861565b80846020018181516138439190614e96565b600f0b905250506040830182905261385a81614ba8565b90506137b3565b5060008260000151600f0b121561387757600082525b50516001600160801b03169392505050565b60004382111561389b5761389b614b24565b6000838152600f6020526040812054815b608081101561393b578183101561393b57600060026138cb8486614b90565b6138d6906001614b90565b6138e09190614c5d565b6000888152601060205260409020909150869082633b9aca00811061390757613907614b0e565b60030201600201541161391c5780935061392a565b613927600182614b5c565b92505b5061393481614ba8565b90506138ac565b50600085815260106020526040812083633b9aca00811061395e5761395e614b0e565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820192909252600290910154606082015260125490915060006139b38783613b62565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508084841015613a92576000600481613a17876001614b90565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052860151919250613a749190614b5c565b925083604001518160400151613a8a9190614b5c565b915050613ab6565b6060830151613aa19043614b5c565b9150826040015142613ab39190614b5c565b90505b60408301518215613af3578284606001518c613ad29190614b5c565b613adc9084614c3e565b613ae69190614c5d565b613af09082614b90565b90505b6040870151613b029082614b5c565b8760200151613b119190614db1565b87518890613b20908390614e46565b600f90810b90915288516000910b129050613b5057505093516001600160801b03169650610d9c95505050505050565b60009950505050505050505050610d9c565b60008082815b6080811015613bde5781831015613bde5760006002613b878486614b90565b613b92906001614b90565b613b9c9190614c5d565b6000818152600460205260409020600201549091508710613bbf57809350613bcd565b613bca600182614b5c565b92505b50613bd781614ba8565b9050613b68565b5090949350505050565b6000818152600860205260409020546001600160a01b03838116911614613c1157613c11614b24565b6000818152600a60205260409020546001600160a01b031615613c4b576000818152600a6020526040902080546001600160a01b03191690555b5050565b6000818152600860205260409020546001600160a01b03838116911614613c7857613c78614b24565b600081815260086020526040902080546001600160a01b0319169055613c9e8282614484565b6001600160a01b0382166000908152600960205260408120805460019290613cc7908490614b5c565b90915550505050565b816001600160a01b0316836001600160a01b031614158015613cf25750600081115b15610f58576001600160a01b03831615613e73576001600160a01b03831660009081526019602052604081205463ffffffff169081613d56576001600160a01b03851660009081526018602090815260408083208380529091529020600101613d98565b6001600160a01b038516600090815260186020526040812090613d7a600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613da586614543565b6001600160a01b038716600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b8354811015613e32576000848281548110613df557613df5614b0e565b90600052602060002001549050868114613e1f578254600181018455600084815260209020018190555b5080613e2a81614ba8565b915050613dd8565b50613e3e846001614f78565b6001600160a01b0388166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610f58576001600160a01b03821660009081526019602052604081205463ffffffff169081613ed2576001600160a01b03841660009081526018602090815260408083208380529091529020600101613f14565b6001600160a01b038416600090815260186020526040812090613ef6600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613f2185614543565b6001600160a01b038616600090815260186020908152604080832063ffffffff851684529091529020835491925060019081019161040091613f639190614b90565b1115613f815760405162461bcd60e51b8152600401610fda90614fa0565b60005b8354811015613fd3576000848281548110613fa157613fa1614b0e565b600091825260208083209091015485546001810187558684529190922001555080613fcb81614ba8565b915050613f84565b50805460018181018355600083815260209020909101869055613ff7908590614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600860205260409020546001600160a01b03161561405757614057614b24565b600081815260086020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260098084528285208054600d86528487208188528652848720889055878752600e865293862093909355908452909152805460019290613cc7908490614b90565b806001600160a01b0316826001600160a01b031614610f58576001600160a01b0382161561427b576001600160a01b03821660009081526019602052604081205463ffffffff169081614140576001600160a01b03841660009081526018602090815260408083208380529091529020600101614182565b6001600160a01b038416600090815260186020526040812090614164600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061418f85614543565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561423a5760008482815481106141df576141df614b0e565b600091825260208083209091015480835260089091526040909120549091506001600160a01b03908116908a1614614227578254600181018455600084815260209020018190555b508061423281614ba8565b9150506141c2565b50614246846001614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610f58576001600160a01b03811660009081526019602052604081205463ffffffff1690816142da576001600160a01b0383166000908152601860209081526040808320838052909152902060010161431c565b6001600160a01b0383166000908152601860205260408120906142fe600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061432984614543565b6001600160a01b03808616600090815260186020908152604080832063ffffffff861684528252808320938b168352600990915290205484549293506001909101916104009061437a908390614b90565b11156143985760405162461bcd60e51b8152600401610fda90614fa0565b60005b84548110156143ea5760008582815481106143b8576143b8614b0e565b6000918252602080832090910154865460018101885587845291909220015550806143e281614ba8565b91505061439b565b5060005b8181101561443c576001600160a01b0389166000908152600d60209081526040808320848452825282205485546001810187558684529190922001558061443481614ba8565b9150506143ee565b50614448856001614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b6001600160a01b0382166000908152600960205260408120546144a990600190614b5c565b6000838152600e60205260409020549091508082036144f8576001600160a01b0384166000908152600d602090815260408083208584528252808320839055858352600e909152812055612086565b6001600160a01b03939093166000908152600d6020908152604080832093835292815282822080548684528484208190558352600e9091528282209490945592839055908252812055565b6001600160a01b038116600090815260196020526040812054429063ffffffff1680158015906145ac57506001600160a01b03841660009081526018602052604081208391614593600185614ab0565b63ffffffff168152602081019190915260400160002054145b1561132757611862600182614ab0565b6001600160e01b03198116811461179557600080fd5b6000602082840312156145e457600080fd5b8135611327816145bc565b60005b8381101561460a5781810151838201526020016145f2565b838111156120865750506000910152565b600081518084526146338160208601602086016145ef565b601f01601f19169290920160200192915050565b602081526000611327602083018461461b565b80356001600160a01b038116811461467157600080fd5b919050565b6000806040838503121561468957600080fd5b6146928361465a565b946020939093013593505050565b6000602082840312156146b257600080fd5b5035919050565b6000602082840312156146cb57600080fd5b6113278261465a565b600080604083850312156146e757600080fd5b50508035926020909101359150565b60008060006060848603121561470b57600080fd5b6147148461465a565b92506147226020850161465a565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561477157614771614732565b604052919050565b6000806040838503121561478c57600080fd5b823567ffffffffffffffff808211156147a457600080fd5b818501915085601f8301126147b857600080fd5b81356020828211156147cc576147cc614732565b8160051b92506147dd818401614748565b82815292840181019281810190898511156147f757600080fd5b948201945b84861015614815578535825294820194908201906147fc565b9997909101359750505050505050565b600081518084526020808501945080840160005b8381101561485557815187529582019590820190600101614839565b509495945050505050565b6040815260006148736040830185614825565b828103602084015261377f8185614825565b801515811461179557600080fd5b600080604083850312156148a657600080fd5b6148af8361465a565b915060208301356148bf81614885565b809150509250929050565b600067ffffffffffffffff8211156148e4576148e4614732565b50601f01601f191660200190565b6000806000806080858703121561490857600080fd5b6149118561465a565b935061491f6020860161465a565b925060408501359150606085013567ffffffffffffffff81111561494257600080fd5b8501601f8101871361495357600080fd5b8035614966614961826148ca565b614748565b81815288602083850101111561497b57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c087890312156149b657600080fd5b6149bf8761465a565b95506020870135945060408701359350606087013560ff811681146149e357600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614a1257600080fd5b8335925060208401359150614a296040850161465a565b90509250925092565b60008060408385031215614a4557600080fd5b614a4e8361465a565b9150614a5c6020840161465a565b90509250929050565b60008060408385031215614a7857600080fd5b614a818361465a565b9150602083013563ffffffff811681146148bf57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614acd57614acd614a9a565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff80841680614b0257614b02614ad5565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b600082821015614b6e57614b6e614a9a565b500390565b600060208284031215614b8557600080fd5b815161132781614885565b60008219821115614ba357614ba3614a9a565b500190565b600060018201614bba57614bba614a9a565b5060010190565b60208082526026908201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060408201526566757475726560d01b606082015260800190565b6020808252601e908201527f566f74696e67206c6f636b2063616e2062652032207965617273206d61780000604082015260600190565b6000816000190483118215151615614c5857614c58614a9a565b500290565b600082614c6c57614c6c614ad5565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611a529083018461461b565b600060208284031215614cfa57600080fd5b8151611327816145bc565b600060208284031215614d1757600080fd5b815167ffffffffffffffff811115614d2e57600080fd5b8201601f81018413614d3f57600080fd5b8051614d4d614961826148ca565b818152856020838501011115614d6257600080fd5b61377f8260208301602086016145ef565b600081600f0b83600f0b80614d8a57614d8a614ad5565b60016001607f1b0319821460001982141615614da857614da8614a9a565b90059392505050565b600081600f0b83600f0b60016001607f1b03600082136000841383830485118282161615614de157614de1614a9a565b60016001607f1b03196000851282811687830587121615614e0457614e04614a9a565b60008712925085820587128484161615614e2057614e20614a9a565b85850587128184161615614e3657614e36614a9a565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b031901831281151615614e7157614e71614a9a565b8160016001607f1b03018313811615614e8c57614e8c614a9a565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b0303821381151615614ec057614ec0614a9a565b8260016001607f1b0319038212811615614edc57614edc614a9a565b50019392505050565b60008083128015600160ff1b850184121615614f0357614f03614a9a565b6001600160ff1b0384018313811615614f1e57614f1e614a9a565b50500390565b634e487b7160e01b600052602160045260246000fd5b848152602081018490526080810160068410614f6657634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff808316818516808303821115614f9757614f97614a9a565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056fea26469706673582212206994db20806c3a8ca133573c08c91474138696f233c1f742aafc189ece7945ff64736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104335760003560e01c80637116c60c11610236578063bfe109281161013b578063e441135c116100c3578063f1127ed811610087578063f1127ed814610ba0578063f8a0576314610bcb578063fbd3a29d14610bee578063fc0c546a14610c01578063fd4a77f114610c1c57600080fd5b8063e441135c14610af7578063e7a324dc14610b17578063e7e242d414610b3e578063e985e9c514610b51578063ee99fe2814610b8d57600080fd5b8063c87b56dd1161010a578063c87b56dd14610a6d578063d1c2babb14610a80578063d1febfb914610a93578063d4e54c3b14610ad1578063e0514aba14610ae457600080fd5b8063bfe1092814610a2c578063c1f0fb9f14610a3f578063c2c4c5c114610a52578063c3cda52014610a5a57600080fd5b806395d89b41116101be578063a183af521161018d578063a183af521461098c578063a22cb4651461099f578063a4d855df146109b2578063b45a3c0e146109c5578063b88d4fde14610a1957600080fd5b806395d89b411461092e578063981b24d014610953578063986b7d8a146109665780639ab24eb01461097957600080fd5b806385f2aef21161020557806385f2aef2146108c95780638c2c9baf146108dc5780638e539e8c146108ef5780638fbb38ff14610902578063900cf0cf1461092557600080fd5b80637116c60c14610860578063711974841461087357806375619ab5146108965780637ecebe00146108a957600080fd5b806335cf668a1161033c57806356afe744116102c45780636352211e116102935780636352211e146107b657806365fc3873146107df5780636f548837146108075780636fcfff451461082757806370a082311461084d57600080fd5b806356afe74414610766578063587cde1e146107875780635c19a95c1461079a5780635f5b0c32146107ad57600080fd5b8063461f711c1161030b578063461f711c146106dd57806346c96aac146107035780634bc2a6571461071c57806354fd4d501461072f5780635594a0451461075357600080fd5b806335cf668a146106815780633a46b1a8146106a457806342842e0e146106b7578063430c2081146106ca57600080fd5b806318160ddd116103bf57806325a58b561161038e57806325a58b56146106055780632e1a7d4d1461060b5780632e720f7d1461061e5780632f745c5914610631578063313ce5671461066757600080fd5b806318160ddd146105b05780631c984bc3146105b857806320606b70146105cb57806323b872dd146105f257600080fd5b8063081812fc11610406578063081812fc146104ec578063095cf5c61461052d578063095ea7b3146105425780630d6a2033146105555780631376f3da1461057557600080fd5b806301ffc9a714610438578063047fc9aa1461047a57806306fdde03146104915780630758c7d8146104c4575b600080fd5b6104656104463660046145d2565b6001600160e01b03191660009081526005602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61048360145481565b604051908152602001610471565b6104b7604051806040016040528060078152602001660eccaa6eec2e0b60cb1b81525081565b6040516104719190614647565b6104d76104d2366004614676565b610c2f565b60405163ffffffff9091168152602001610471565b6105156104fa3660046146a0565b6000908152600a60205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001610471565b61054061053b3660046146b9565b610da2565b005b610540610550366004614676565b610ddb565b6104836105633660046146a0565b60156020526000908152604090205481565b6105886105833660046146d4565b610ec3565b60408051600f95860b81529390940b6020840152928201526060810191909152608001610471565b610483610f0a565b6104836105c63660046146d4565b610f1a565b6104837f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6105406106003660046146f6565b610f4c565b43610483565b6105406106193660046146a0565b610f5d565b61054061062c3660046146b9565b611228565b61048361063f366004614676565b6001600160a01b03919091166000908152600d60209081526040808320938352929052205490565b61066f601281565b60405160ff9091168152602001610471565b61048361068f3660046146a0565b60009081526011602052604090206001015490565b6104836106b2366004614676565b611261565b6105406106c53660046146f6565b611300565b6104656106d8366004614676565b61131b565b6106f06106eb3660046146a0565b61132e565b604051600f9190910b8152602001610471565b600054610515906201000090046001600160a01b031681565b61054061072a3660046146b9565b611371565b6104b7604051806040016040528060058152602001640312e302e360dc1b81525081565b600254610515906001600160a01b031681565b610779610774366004614779565b6113b2565b604051610471929190614860565b6105156107953660046146b9565b61174a565b6105406107a83660046146b9565b61177a565b61048361040081565b6105156107c43660046146a0565b6000908152600860205260409020546001600160a01b031690565b6107f26107ed3660046146d4565b611798565b60408051928352602083019190915201610471565b6104836108153660046146a0565b600c6020526000908152604090205481565b6104d76108353660046146b9565b60196020526000908152604090205463ffffffff1681565b61048361085b3660046146b9565b6117ec565b61048361086e3660046146a0565b61180a565b6106f06108813660046146a0565b601360205260009081526040902054600f0b81565b6105406108a43660046146b9565b61186a565b6104836108b73660046146b9565b601a6020526000908152604090205481565b600154610515906001600160a01b031681565b6104836108ea3660046146d4565b6118a3565b6104836108fd3660046146a0565b6118af565b6104656109103660046146a0565b60166020526000908152604090205460ff1681565b61048360125481565b6104b7604051806040016040528060068152602001650eccaa6aea0f60d31b81525081565b6104836109613660046146a0565b6118ba565b6105406109743660046146a0565b611a5c565b6104836109873660046146b9565b611aa6565b61048361099a3660046146d4565b611b79565b6105406109ad366004614893565b611c99565b6104836109c03660046146d4565b611d1d565b6109f96109d33660046146a0565b601160205260009081526040902080546001820154600290920154600f9190910b919083565b60408051600f9490940b8452602084019290925290820152606001610471565b610540610a273660046148f2565b611eed565b600354610515906001600160a01b031681565b610540610a4d3660046146a0565b61208c565b6105406120c1565b610540610a6836600461499d565b61210f565b6104b7610a7b3660046146a0565b612478565b610483610a8e3660046146d4565b6125e6565b610588610aa13660046146a0565b600460205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6107f2610adf3660046149fd565b6127f3565b610483610af23660046146d4565b612848565b610483610b053660046146a0565b600f6020526000908152604090205481565b6104837fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b610483610b4c3660046146a0565b612854565b610465610b5f366004614a32565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205460ff1690565b610483610b9b3660046146d4565b61287c565b610483610bae366004614a65565b601860209081526000928352604080842090915290825290205481565b610483610bd93660046146a0565b60009081526011602052604090206002015490565b610540610bfc3660046146a0565b612963565b61051573a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e7081565b610540610c2a3660046146a0565b61299a565b6001600160a01b03821660009081526019602052604081205463ffffffff16808203610c5f576000915050610d9c565b6001600160a01b03841660009081526018602052604081208491610c84600185614ab0565b63ffffffff16815260208101919091526040016000205411610cb357610cab600182614ab0565b915050610d9c565b6001600160a01b0384166000908152601860209081526040808320838052909152902054831015610ce8576000915050610d9c565b600080610cf6600184614ab0565b90505b8163ffffffff168163ffffffff161115610d975760006002610d1b8484614ab0565b610d259190614aeb565b610d2f9083614ab0565b6001600160a01b038816600090815260186020908152604080832063ffffffff851684529091529020805491925090879003610d7157509350610d9c92505050565b8054871115610d8257819350610d90565b610d8d600183614ab0565b92505b5050610cf9565b509150505b92915050565b6001546001600160a01b03163314610db957600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600860205260409020546001600160a01b031680610dfd57600080fd5b806001600160a01b0316836001600160a01b031603610e1b57600080fd5b6000828152600860209081526040808320546001600160a01b038581168552600b845282852033808752945291909320549216149060ff168180610e5c5750805b610e6557600080fd5b6000848152600a602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b601060205281600052604060002081633b9aca008110610ee257600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610f154261180a565b905090565b600082815260106020526040812082633b9aca008110610f3c57610f3c614b0e565b6003020160010154905092915050565b610f58838383336129d2565b505050565b60075460ff1660011901610f7057600080fd5b6007805460ff19166002179055610f873382612ab3565b610f9357610f93614b24565b600081815260156020526040902054158015610fbe575060008181526016602052604090205460ff16155b610fe35760405162461bcd60e51b8152600401610fda90614b3a565b60405180910390fd5b60008181526011602090815260409182902082516060810184528154600f0b815260018201549281019290925260020154918101829052904210156110635760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401610fda565b80516040805160608101825260008082526020808301828152838501838152888452601190925293909120915182546001600160801b0319166001600160801b03909116178255915160018201559051600290910155601454600f9190910b906110cd8282614b5c565b6014819055506110fe848460405180606001604052806000600f0b8152602001600081526020016000815250612b16565b60405163a9059cbb60e01b81523360048201526024810183905273a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e709063a9059cbb906044016020604051808303816000875af1158015611156573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117a9190614b73565b61118657611186614b24565b61118f846131c6565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c816111fd8482614b5c565b6040805192835260208301919091520160405180910390a150506007805460ff191660011790555050565b6001546001600160a01b0316331461123f57600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b60008061126e8484610c2f565b6001600160a01b038516600090815260186020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156112f65760008382815481106112bf576112bf614b0e565b906000526020600020015490506112d68188613299565b6112e09084614b90565b92505080806112ee90614ba8565b9150506112a2565b5095945050505050565b610f5883838360405180602001604052806000815250611eed565b60006113278383612ab3565b9392505050565b6000818152600f60209081526040808320546010909252822081633b9aca00811061135b5761135b614b0e565b6003020154600160801b9004600f0b9392505050565b6001546001600160a01b0316331461138857600080fd5b600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b60008181526015602052604090205460609081901580156113e2575060008381526016602052604090205460ff16155b6113fe5760405162461bcd60e51b8152600401610fda90614b3a565b6114083384612ab3565b61141157600080fd5b6000838152600860209081526040808320546011835281842082516060810184528154600f0b808252600183015495820195909552600290910154928101929092526001600160a01b03169290911361146957600080fd5b8051601454611481916001600160801b031690614b5c565b6014556000805b87518210156114ca578782815181106114a3576114a3614b0e565b6020026020010151816114b69190614b90565b9050816114c281614ba8565b925050611488565b6040805160608082018352600080835260208084018281528486018381528d845260118352868420955186546001600160801b0319166001600160801b03909116178655905160018601555160029094019390935583519182018452808252918101829052918201526115409088908590612b16565b611549876131c6565b604083015142811161156d5760405162461bcd60e51b8152600401610fda90614bc1565b61157b6303c2670042614b90565b81111561159a5760405162461bcd60e51b8152600401610fda90614c07565b885167ffffffffffffffff8111156115b4576115b4614732565b6040519080825280602002602001820160405280156115dd578160200160208202803683370190505b509650885167ffffffffffffffff8111156115fa576115fa614732565b604051908082528060200260200182016040528015611623578160200160208202803683370190505b50955060008093505b895184101561173d5760066000815461164490614ba8565b909155506006549850611657868a61336d565b50828a858151811061166b5761166b614b0e565b602002602001015186600001516001600160801b031661168b9190614c3e565b6116959190614c5d565b60208087015160008c8152601183526040908190206001810183905581516060810183528154600f0b815293840192909252600290910154908201529091506116e5908a908390859060056133de565b888885815181106116f8576116f8614b0e565b60200260200101818152505061170e8942613299565b87858151811061172057611720614b0e565b60209081029190910101528361173581614ba8565b94505061162c565b5050505050509250929050565b6001600160a01b0380821660009081526017602052604081205490911680156117735780611327565b5090919050565b6001600160a01b03811661178b5750335b6117953382613620565b50565b600754600090819060ff16600119016117b057600080fd5b6007805460ff191660021790556117c8848433613693565b91506117d48242613299565b6007805460ff19166001179055919491935090915050565b6001600160a01b038116600090815260096020526040812054610d9c565b601254600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529091906118628185613788565b949350505050565b6001546001600160a01b0316331461188157600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60006113278383613889565b6000610d9c8261180a565b6000438211156118cc576118cc614b24565b60125460006118db8483613b62565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250838310156119ea57600060048161193e866001614b90565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052850151919250146119e457826060015181606001516119aa9190614b5c565b836040015182604001516119be9190614b5c565b60608501516119cd908a614b5c565b6119d79190614c3e565b6119e19190614c5d565b91505b50611a39565b43826060015114611a39576060820151611a049043614b5c565b6040830151611a139042614b5c565b6060840151611a229089614b5c565b611a2c9190614c3e565b611a369190614c5d565b90505b611a5282828460400151611a4d9190614b90565b613788565b9695505050505050565b6000546201000090046001600160a01b03163314611a7957600080fd5b600081815260156020526040902054611a9490600190614b5c565b60009182526015602052604090912055565b6001600160a01b03811660009081526019602052604081205463ffffffff16808203611ad55750600092915050565b6001600160a01b038316600090815260186020526040812081611af9600185614ab0565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b8254811015611b70576000838281548110611b3957611b39614b0e565b90600052602060002001549050611b508142613299565b611b5a9084614b90565b9250508080611b6890614ba8565b915050611b1c565b50949350505050565b60075460009060ff1660011901611b8f57600080fd5b6007805460ff19166002179055611ba63384612ab3565b611bb257611bb2614b24565b60008381526011602090815260409182902082516060810184528154600f0b8152600182015492810192909252600201549181019190915282611bf757611bf7614b24565b60008160000151600f0b13611c475760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610fda565b42816040015111611c6a5760405162461bcd60e51b8152600401610fda90614c71565b611c79848460008460026133de565b611c838442613299565b9150506007805460ff1916600117905592915050565b336001600160a01b03831603611cb157611cb1614b24565b336000818152600b602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60075460009060ff1660011901611d3357600080fd5b6007805460ff19166002179055611d4a3384612ab3565b611d5657611d56614b24565b600083815260116020908152604080832081516060810183528154600f0b815260018201549381019390935260020154908201529062093a8080611d9a8642614b90565b611da49190614c5d565b611dae9190614c3e565b905042826040015111611df25760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401610fda565b60008260000151600f0b13611e3d5760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401610fda565b81604001518111611e905760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401610fda565b611e9e6303c2670042614b90565b811115611ebd5760405162461bcd60e51b8152600401610fda90614c07565b611ecc856000838560036133de565b611ed68542613299565b925050506007805460ff1916600117905592915050565b611ef9848484336129d2565b823b1561208657604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611f32903390889087908790600401614cb5565b6020604051808303816000875af1925050508015611f6d575060408051601f3d908101601f19168201909252611f6a91810190614ce8565b60015b612015573d808015611f9b576040519150601f19603f3d011682016040523d82523d6000602084013e611fa0565b606091505b50805160000361200d5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610fda565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146120845760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401610fda565b505b50505050565b6000546201000090046001600160a01b031633146120a957600080fd5b6000908152601660205260409020805460ff19169055565b61210d600060405180606001604052806000600f0b815260200160008152602001600081525060405180606001604052806000600f0b8152602001600081526020016000815250612b16565b565b336001600160a01b0387160361212457600080fd5b6001600160a01b03861661213757600080fd5b60408051808201825260078152660eccaa6eec2e0b60cb1b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f1de6a1c189dcc4ee6a95fb1fdc3a550060accb8f042ce71a27c9dd46bee30732818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156122f8573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166123725760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401610fda565b6001600160a01b0381166000908152601a6020526040812080549161239683614ba8565b9190505589146123fb5760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401610fda565b874211156124625760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401610fda565b61246c818b613620565b50505050505050505050565b6000818152600860205260409020546060906001600160a01b03166124df5760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401610fda565b600082815260116020908152604080832081516060810183528154600f0b815260018201548185015260029091015481830152858452601590925282205490919015801561253c575060008481526016602052604090205460ff16155b6002549091506001600160a01b031663b6d11ba58561255b8142613299565b6040868101518751915160e086901b6001600160e01b0319168152600481019490945260248401929092526044830191909152600f0b6064820152831515608482015260a401600060405180830381865afa1580156125be573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118629190810190614d05565b600082815260156020526040812054158015612611575060008381526016602052604090205460ff16155b61262d5760405162461bcd60e51b8152600401610fda90614b3a565b81830361263957600080fd5b6126433384612ab3565b61264c57600080fd5b6126563383612ab3565b61265f57600080fd5b60008381526011602081815260408084208151606080820184528254600f90810b8352600180850154848801526002948501548487019081528b8a529787529785902085519283018652805490910b82529687015494810194909452940154908201529051421080156126d55750428160400151115b6126de57600080fd5b60008260000151600f0b9050600082604001518460400151101561270657826040015161270c565b83604001515b905082602001518460200151101561272857836020015161272e565b82602001515b6020848101919091526040805160608101825260008082528184018181528284018281528c83526011909552929020905181546001600160801b0319166001600160801b03909116178155905160018201559051600290910155601454612796908390614b5c565b6014819055506127c7878560405180606001604052806000600f0b8152602001600081526020016000815250612b16565b6127d0876131c6565b6127de8683838660046133de565b6127e88642613299565b979650505050505050565b600754600090819060ff166001190161280b57600080fd5b6007805460ff19166002179055612823858585613693565b915061282f8242613299565b6007805460ff1916600117905591959194509092505050565b60006113278383613299565b6000818152600c602052604081205443900361287257506000919050565b610d9c8242613299565b60075460009060ff166001190161289257600080fd5b6007805460ff1916600290811790915560008481526011602090815260409182902082516060810184528154600f0b81526001820154928101929092529092015490820152826128e157600080fd5b60008160000151600f0b136129315760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610fda565b428160400151116129545760405162461bcd60e51b8152600401610fda90614c71565b611c79848460008460006133de565b6000546201000090046001600160a01b0316331461298057600080fd5b600081815260156020526040902054611a94906001614b90565b6000546201000090046001600160a01b031633146129b757600080fd5b6000908152601660205260409020805460ff19166001179055565b6000828152601560205260409020541580156129fd575060008281526016602052604090205460ff16155b612a195760405162461bcd60e51b8152600401610fda90614b3a565b612a238183612ab3565b612a2c57600080fd5b612a368483613be8565b612a408483613c4f565b612a5b612a4c8561174a565b612a558561174a565b84613cd0565b612a658383614032565b6000828152600c60205260408082204390555183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b600081815260086020908152604080832054600a8352818420546001600160a01b03918216808652600b855283862088841680885295529285205492938085149392909116149060ff168280612b065750815b806127e857509695505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260408051608081018252600080825260208201819052918101829052606081019190915260125460009081908715612c7a57428760400151118015612b86575060008760000151600f0b135b15612bc9578651612b9c906303c2670090614d73565b600f0b60208601526040870151612bb4904290614b5c565b8560200151612bc39190614db1565b600f0b85525b428660400151118015612be3575060008660000151600f0b135b15612c26578551612bf9906303c2670090614d73565b600f0b60208501526040860151612c11904290614b5c565b8460200151612c209190614db1565b600f0b84525b604080880151600090815260136020528190205490870151600f9190910b935015612c7a578660400151866040015103612c6257829150612c7a565b604080870151600090815260136020522054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612cef575060008181526004602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b604081015181600042831015612d3c576040840151612d0e9042614b5c565b6060850151612d1d9043614b5c565b612d2f90670de0b6b3a7640000614c3e565b612d399190614c5d565b90505b600062093a80612d4c8186614c5d565b612d569190614c3e565b905060005b60ff811015612ed057612d7162093a8083614b90565b9150600042831115612d8557429250612d99565b50600082815260136020526040902054600f0b5b612da38684614b5c565b8760200151612db29190614db1565b87518890612dc1908390614e46565b600f0b905250602087018051829190612ddb908390614e96565b600f90810b90915288516000910b12159050612df657600087525b60008760200151600f0b1215612e0e57600060208801525b60408088018490528501519295508592670de0b6b3a764000090612e329085614b5c565b612e3c9086614c3e565b612e469190614c5d565b8560600151612e559190614b90565b6060880152612e65600189614b90565b9750428303612e7a5750436060870152612ed0565b6000888152600460209081526040918290208951918a01516001600160801b03908116600160801b029216919091178155908801516001820155606088015160029091015550612ec981614ba8565b9050612d5b565b505060128590558b15612f5b5788602001518860200151612ef19190614e46565b84602001818151612f029190614e96565b600f0b90525088518851612f169190614e46565b84518590612f25908390614e96565b600f90810b90915260208601516000910b12159050612f4657600060208501525b60008460000151600f0b1215612f5b57600084525b6000858152600460209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b156131b857428b60400151111561300f576020890151612fc19088614e96565b96508a604001518a6040015103612fe4576020880151612fe19088614e46565b96505b60408b810151600090815260136020522080546001600160801b0319166001600160801b0389161790555b428a604001511115613067578a604001518a60400151111561306757602088015161303a9087614e46565b60408b810151600090815260136020522080546001600160801b0319166001600160801b03831617905595505b60008c8152600f6020526040812054613081906001614b90565b905080600f60008f815260200190815260200160002081905550428960400181815250504389606001818152505088601060008f815260200190815260200160002082633b9aca0081106130d7576130d7614b0e565b825160208401516001600160801b03908116600160801b0291161760039190910291909101908155604082015160018201556060909101516002909101557f8d83e324303a2f547eb8572fb6b42fb04620c4a95f09c9a1c8c6e5ac8f4624ed6131558e6000908152600860205260409020546001600160a01b031690565b8e8b600001518c602001518d604001518e606001516040516131ae969594939291906001600160a01b039690961686526020860194909452600f92830b6040860152910b6060840152608083015260a082015260c00190565b60405180910390a1505b505050505050505050505050565b6131d03382612ab3565b61321c5760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401610fda565b6000818152600860205260408120546001600160a01b03169061323f9083610ddb565b61325361324b8261174a565b600084613cd0565b61325d8183613c4f565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000828152600f60205260408120548082036132b9576000915050610d9c565b600084815260106020526040812082633b9aca0081106132db576132db614b0e565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820183905260020154606082015291506133279085614ee5565b81602001516133369190614db1565b81518290613345908390614e46565b600f90810b90915282516000910b1215905061336057600081525b51600f0b9150610d9c9050565b60006001600160a01b03831661338557613385614b24565b6133936000612a558561174a565b61339d8383614032565b60405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b60145482906133ed8682614b90565b601455604080516060810182526000808252602080830182815283850192835286519187015194870151909252929052600f9190910b8152825187908490613436908390614e96565b600f0b905250851561344a57604083018690525b826020015160000361345d574260208401525b600088815260116020908152604091829020855181546001600160801b0319166001600160801b03909116178155908501516001820155908401516002909101556134a9888285612b16565b3387158015906134cb575060048560058111156134c8576134c8614f24565b14155b80156134e9575060058560058111156134e6576134e6614f24565b14155b15613585576040516323b872dd60e01b81526001600160a01b03821660048201523060248201526044810189905273a04bc7140c26fc9bb1f36b1a604c7a5a88fb0e70906323b872dd906064016020604051808303816000875af1158015613555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135799190614b73565b61358557613585614b24565b8360400151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516135c99493929190614f3a565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c836135fd8a82614b90565b6040805192835260208301919091520160405180910390a1505050505050505050565b600061362b8361174a565b6001600160a01b0384811660008181526017602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610f588382846140c8565b60008062093a80806136a58642614b90565b6136af9190614c5d565b6136b99190614c3e565b9050600085116136c857600080fd5b4281116136e75760405162461bcd60e51b8152600401610fda90614bc1565b6136f56303c2670042614b90565b8111156137145760405162461bcd60e51b8152600401610fda90614c07565b60066000815461372390614ba8565b90915550600654613734848261336d565b5060008181526011602090815260409182902082516060810184528154600f0b8152600180830154938201939093526002909101549281019290925261377f918391899186916133de565b95945050505050565b600080839050600062093a808083604001516137a49190614c5d565b6137ae9190614c3e565b905060005b60ff811015613861576137c962093a8083614b90565b91506000858311156137dd578592506137f1565b50600082815260136020526040902054600f0b5b60408401516138009084614b5c565b846020015161380f9190614db1565b8451859061381e908390614e46565b600f0b9052508583036138315750613861565b80846020018181516138439190614e96565b600f0b905250506040830182905261385a81614ba8565b90506137b3565b5060008260000151600f0b121561387757600082525b50516001600160801b03169392505050565b60004382111561389b5761389b614b24565b6000838152600f6020526040812054815b608081101561393b578183101561393b57600060026138cb8486614b90565b6138d6906001614b90565b6138e09190614c5d565b6000888152601060205260409020909150869082633b9aca00811061390757613907614b0e565b60030201600201541161391c5780935061392a565b613927600182614b5c565b92505b5061393481614ba8565b90506138ac565b50600085815260106020526040812083633b9aca00811061395e5761395e614b0e565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b6020830152600181015492820192909252600290910154606082015260125490915060006139b38783613b62565b600081815260046020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508084841015613a92576000600481613a17876001614b90565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060808301829052860151919250613a749190614b5c565b925083604001518160400151613a8a9190614b5c565b915050613ab6565b6060830151613aa19043614b5c565b9150826040015142613ab39190614b5c565b90505b60408301518215613af3578284606001518c613ad29190614b5c565b613adc9084614c3e565b613ae69190614c5d565b613af09082614b90565b90505b6040870151613b029082614b5c565b8760200151613b119190614db1565b87518890613b20908390614e46565b600f90810b90915288516000910b129050613b5057505093516001600160801b03169650610d9c95505050505050565b60009950505050505050505050610d9c565b60008082815b6080811015613bde5781831015613bde5760006002613b878486614b90565b613b92906001614b90565b613b9c9190614c5d565b6000818152600460205260409020600201549091508710613bbf57809350613bcd565b613bca600182614b5c565b92505b50613bd781614ba8565b9050613b68565b5090949350505050565b6000818152600860205260409020546001600160a01b03838116911614613c1157613c11614b24565b6000818152600a60205260409020546001600160a01b031615613c4b576000818152600a6020526040902080546001600160a01b03191690555b5050565b6000818152600860205260409020546001600160a01b03838116911614613c7857613c78614b24565b600081815260086020526040902080546001600160a01b0319169055613c9e8282614484565b6001600160a01b0382166000908152600960205260408120805460019290613cc7908490614b5c565b90915550505050565b816001600160a01b0316836001600160a01b031614158015613cf25750600081115b15610f58576001600160a01b03831615613e73576001600160a01b03831660009081526019602052604081205463ffffffff169081613d56576001600160a01b03851660009081526018602090815260408083208380529091529020600101613d98565b6001600160a01b038516600090815260186020526040812090613d7a600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613da586614543565b6001600160a01b038716600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b8354811015613e32576000848281548110613df557613df5614b0e565b90600052602060002001549050868114613e1f578254600181018455600084815260209020018190555b5080613e2a81614ba8565b915050613dd8565b50613e3e846001614f78565b6001600160a01b0388166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610f58576001600160a01b03821660009081526019602052604081205463ffffffff169081613ed2576001600160a01b03841660009081526018602090815260408083208380529091529020600101613f14565b6001600160a01b038416600090815260186020526040812090613ef6600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613f2185614543565b6001600160a01b038616600090815260186020908152604080832063ffffffff851684529091529020835491925060019081019161040091613f639190614b90565b1115613f815760405162461bcd60e51b8152600401610fda90614fa0565b60005b8354811015613fd3576000848281548110613fa157613fa1614b0e565b600091825260208083209091015485546001810187558684529190922001555080613fcb81614ba8565b915050613f84565b50805460018181018355600083815260209020909101869055613ff7908590614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600860205260409020546001600160a01b03161561405757614057614b24565b600081815260086020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260098084528285208054600d86528487208188528652848720889055878752600e865293862093909355908452909152805460019290613cc7908490614b90565b806001600160a01b0316826001600160a01b031614610f58576001600160a01b0382161561427b576001600160a01b03821660009081526019602052604081205463ffffffff169081614140576001600160a01b03841660009081526018602090815260408083208380529091529020600101614182565b6001600160a01b038416600090815260186020526040812090614164600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061418f85614543565b6001600160a01b038616600090815260186020908152604080832063ffffffff8516845290915281209192506001909101905b835481101561423a5760008482815481106141df576141df614b0e565b600091825260208083209091015480835260089091526040909120549091506001600160a01b03908116908a1614614227578254600181018455600084815260209020018190555b508061423281614ba8565b9150506141c2565b50614246846001614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610f58576001600160a01b03811660009081526019602052604081205463ffffffff1690816142da576001600160a01b0383166000908152601860209081526040808320838052909152902060010161431c565b6001600160a01b0383166000908152601860205260408120906142fe600185614ab0565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061432984614543565b6001600160a01b03808616600090815260186020908152604080832063ffffffff861684528252808320938b168352600990915290205484549293506001909101916104009061437a908390614b90565b11156143985760405162461bcd60e51b8152600401610fda90614fa0565b60005b84548110156143ea5760008582815481106143b8576143b8614b0e565b6000918252602080832090910154865460018101885587845291909220015550806143e281614ba8565b91505061439b565b5060005b8181101561443c576001600160a01b0389166000908152600d60209081526040808320848452825282205485546001810187558684529190922001558061443481614ba8565b9150506143ee565b50614448856001614f78565b6001600160a01b0387166000908152601960205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b6001600160a01b0382166000908152600960205260408120546144a990600190614b5c565b6000838152600e60205260409020549091508082036144f8576001600160a01b0384166000908152600d602090815260408083208584528252808320839055858352600e909152812055612086565b6001600160a01b03939093166000908152600d6020908152604080832093835292815282822080548684528484208190558352600e9091528282209490945592839055908252812055565b6001600160a01b038116600090815260196020526040812054429063ffffffff1680158015906145ac57506001600160a01b03841660009081526018602052604081208391614593600185614ab0565b63ffffffff168152602081019190915260400160002054145b1561132757611862600182614ab0565b6001600160e01b03198116811461179557600080fd5b6000602082840312156145e457600080fd5b8135611327816145bc565b60005b8381101561460a5781810151838201526020016145f2565b838111156120865750506000910152565b600081518084526146338160208601602086016145ef565b601f01601f19169290920160200192915050565b602081526000611327602083018461461b565b80356001600160a01b038116811461467157600080fd5b919050565b6000806040838503121561468957600080fd5b6146928361465a565b946020939093013593505050565b6000602082840312156146b257600080fd5b5035919050565b6000602082840312156146cb57600080fd5b6113278261465a565b600080604083850312156146e757600080fd5b50508035926020909101359150565b60008060006060848603121561470b57600080fd5b6147148461465a565b92506147226020850161465a565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561477157614771614732565b604052919050565b6000806040838503121561478c57600080fd5b823567ffffffffffffffff808211156147a457600080fd5b818501915085601f8301126147b857600080fd5b81356020828211156147cc576147cc614732565b8160051b92506147dd818401614748565b82815292840181019281810190898511156147f757600080fd5b948201945b84861015614815578535825294820194908201906147fc565b9997909101359750505050505050565b600081518084526020808501945080840160005b8381101561485557815187529582019590820190600101614839565b509495945050505050565b6040815260006148736040830185614825565b828103602084015261377f8185614825565b801515811461179557600080fd5b600080604083850312156148a657600080fd5b6148af8361465a565b915060208301356148bf81614885565b809150509250929050565b600067ffffffffffffffff8211156148e4576148e4614732565b50601f01601f191660200190565b6000806000806080858703121561490857600080fd5b6149118561465a565b935061491f6020860161465a565b925060408501359150606085013567ffffffffffffffff81111561494257600080fd5b8501601f8101871361495357600080fd5b8035614966614961826148ca565b614748565b81815288602083850101111561497b57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c087890312156149b657600080fd5b6149bf8761465a565b95506020870135945060408701359350606087013560ff811681146149e357600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614a1257600080fd5b8335925060208401359150614a296040850161465a565b90509250925092565b60008060408385031215614a4557600080fd5b614a4e8361465a565b9150614a5c6020840161465a565b90509250929050565b60008060408385031215614a7857600080fd5b614a818361465a565b9150602083013563ffffffff811681146148bf57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614acd57614acd614a9a565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff80841680614b0257614b02614ad5565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b600082821015614b6e57614b6e614a9a565b500390565b600060208284031215614b8557600080fd5b815161132781614885565b60008219821115614ba357614ba3614a9a565b500190565b600060018201614bba57614bba614a9a565b5060010190565b60208082526026908201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060408201526566757475726560d01b606082015260800190565b6020808252601e908201527f566f74696e67206c6f636b2063616e2062652032207965617273206d61780000604082015260600190565b6000816000190483118215151615614c5857614c58614a9a565b500290565b600082614c6c57614c6c614ad5565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611a529083018461461b565b600060208284031215614cfa57600080fd5b8151611327816145bc565b600060208284031215614d1757600080fd5b815167ffffffffffffffff811115614d2e57600080fd5b8201601f81018413614d3f57600080fd5b8051614d4d614961826148ca565b818152856020838501011115614d6257600080fd5b61377f8260208301602086016145ef565b600081600f0b83600f0b80614d8a57614d8a614ad5565b60016001607f1b0319821460001982141615614da857614da8614a9a565b90059392505050565b600081600f0b83600f0b60016001607f1b03600082136000841383830485118282161615614de157614de1614a9a565b60016001607f1b03196000851282811687830587121615614e0457614e04614a9a565b60008712925085820587128484161615614e2057614e20614a9a565b85850587128184161615614e3657614e36614a9a565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b031901831281151615614e7157614e71614a9a565b8160016001607f1b03018313811615614e8c57614e8c614a9a565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b0303821381151615614ec057614ec0614a9a565b8260016001607f1b0319038212811615614edc57614edc614a9a565b50019392505050565b60008083128015600160ff1b850184121615614f0357614f03614a9a565b6001600160ff1b0384018313811615614f1e57614f1e614a9a565b50500390565b634e487b7160e01b600052602160045260246000fd5b848152602081018490526080810160068410614f6657634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff808316818516808303821115614f9757614f97614a9a565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056fea26469706673582212206994db20806c3a8ca133573c08c91474138696f233c1f742aafc189ece7945ff64736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.