Contract
0xa4eb2e1284d9e30fb656fe6b34c1680ef5d4cbfc
5
Contract Overview
Balance:
0 MATIC
Token:
My Name Tag:
Not Available
TokenTracker:
[ Download CSV Export ]
Contract Name:
Ve
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "../../lib/Base64.sol"; import "../../interface/IERC20.sol"; import "../../interface/IERC721.sol"; import "../../interface/IERC721Metadata.sol"; import "../../interface/IVe.sol"; import "../../interface/IERC721Receiver.sol"; import "../../interface/IController.sol"; import "../Reentrancy.sol"; import "../../lib/SafeERC20.sol"; import "../../lib/Math.sol"; contract Ve is IERC721, IERC721Metadata, IVe, Reentrancy { using SafeERC20 for IERC20; uint internal constant WEEK = 1 weeks; uint internal constant MAX_TIME = 4 * 365 * 86400; int128 internal constant I_MAX_TIME = 4 * 365 * 86400; uint internal constant MULTIPLIER = 1 ether; address immutable public override token; uint public supply; mapping(uint => LockedBalance) public locked; mapping(uint => uint) public ownershipChange; uint public override epoch; /// @dev epoch -> unsigned point mapping(uint => Point) internal _pointHistory; /// @dev user -> Point[userEpoch] mapping(uint => Point[1000000000]) internal _userPointHistory; mapping(uint => uint) public override userPointEpoch; mapping(uint => int128) public slopeChanges; // time -> signed slope change mapping(uint => uint) public attachments; mapping(uint => bool) public voted; address public controller; string constant public override name = "veDYST"; string constant public override symbol = "veDYST"; string constant public version = "1.0.0"; uint8 constant public decimals = 18; /// @dev Current count of token uint internal tokenId; /// @dev Mapping from NFT ID to the address that owns it. mapping(uint => address) internal idToOwner; /// @dev Mapping from NFT ID to approved address. mapping(uint => address) internal idToApprovals; /// @dev Mapping from owner address to count of his tokens. mapping(address => uint) internal ownerToNFTokenCount; /// @dev Mapping from owner address to mapping of index to tokenIds mapping(address => mapping(uint => uint)) internal ownerToNFTokenIdList; /// @dev Mapping from NFT ID to index of owner mapping(uint => uint) internal tokenToOwnerIndex; /// @dev Mapping from owner address to mapping of operator addresses. mapping(address => mapping(address => bool)) internal ownerToOperators; /// @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; event Deposit( address indexed provider, uint tokenId, uint value, uint indexed locktime, DepositType depositType, uint ts ); event Withdraw(address indexed provider, uint tokenId, uint value, uint ts); event Supply(uint prevSupply, uint supply); /// @notice Contract constructor /// @param token_ `ERC20CRV` token address constructor(address token_, address controller_) { token = token_; controller = controller_; _pointHistory[0].blk = block.number; _pointHistory[0].ts = block.timestamp; supportedInterfaces[ERC165_INTERFACE_ID] = true; supportedInterfaces[ERC721_INTERFACE_ID] = true; supportedInterfaces[ERC721_METADATA_INTERFACE_ID] = true; // mint-ish emit Transfer(address(0), address(this), tokenId); // burn-ish emit Transfer(address(this), address(0), tokenId); } function _voter() internal view returns (address) { return IController(controller).voter(); } /// @dev Interface identification is specified in ERC-165. /// @param _interfaceID Id of the interface function supportsInterface(bytes4 _interfaceID) external view override returns (bool) { return supportedInterfaces[_interfaceID]; } /// @notice Get the most recently recorded rate of voting power decrease for `_tokenId` /// @param _tokenId token of the NFT /// @return Value of the slope function getLastUserSlope(uint _tokenId) external view returns (int128) { uint uEpoch = userPointEpoch[_tokenId]; return _userPointHistory[_tokenId][uEpoch].slope; } /// @notice Get the timestamp for checkpoint `_idx` for `_tokenId` /// @param _tokenId token of the NFT /// @param _idx User epoch number /// @return Epoch time of the checkpoint function userPointHistoryTs(uint _tokenId, uint _idx) external view returns (uint) { return _userPointHistory[_tokenId][_idx].ts; } /// @notice Get timestamp when `_tokenId`'s lock finishes /// @param _tokenId User NFT /// @return Epoch time of the lock end function lockedEnd(uint _tokenId) external view returns (uint) { return locked[_tokenId].end; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function _balance(address _owner) internal view returns (uint) { return ownerToNFTokenCount[_owner]; } /// @dev Returns the number of NFTs owned by `_owner`. /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. /// @param _owner Address for whom to query the balance. function balanceOf(address _owner) external view override returns (uint) { return _balance(_owner); } /// @dev Returns the address of the owner of the NFT. /// @param _tokenId The identifier for an NFT. function ownerOf(uint _tokenId) public view override returns (address) { return idToOwner[_tokenId]; } /// @dev Get the approved address for a single NFT. /// @param _tokenId ID of the NFT to query the approval of. function getApproved(uint _tokenId) external view override 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 override returns (bool) { return (ownerToOperators[_owner])[_operator]; } /// @dev Get token by index function tokenOfOwnerByIndex(address _owner, uint _tokenIndex) external view returns (uint) { return ownerToNFTokenIdList[_owner][_tokenIndex]; } /// @dev Returns whether the given spender can transfer a given token ID /// @param _spender address of the spender to query /// @param _tokenId uint ID of the token to be transferred /// @return bool whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token function _isApprovedOrOwner(address _spender, uint _tokenId) internal view returns (bool) { address owner = idToOwner[_tokenId]; bool spenderIsOwner = owner == _spender; bool spenderIsApproved = _spender == idToApprovals[_tokenId]; bool spenderIsApprovedForAll = (ownerToOperators[owner])[_spender]; return spenderIsOwner || spenderIsApproved || spenderIsApprovedForAll; } function isApprovedOrOwner(address _spender, uint _tokenId) external view override returns (bool) { return _isApprovedOrOwner(_spender, _tokenId); } /// @dev Add a NFT to an index mapping to a given address /// @param _to address of the receiver /// @param _tokenId uint ID Of the token to be added function _addTokenToOwnerList(address _to, uint _tokenId) internal { uint currentCount = _balance(_to); ownerToNFTokenIdList[_to][currentCount] = _tokenId; tokenToOwnerIndex[_tokenId] = currentCount; } /// @dev Remove a NFT from an index mapping to a given address /// @param _from address of the sender /// @param _tokenId uint ID Of the token to be removed function _removeTokenFromOwnerList(address _from, uint _tokenId) internal { // Delete uint currentCount = _balance(_from) - 1; uint currentIndex = tokenToOwnerIndex[_tokenId]; if (currentCount == currentIndex) { // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentCount] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } else { uint lastTokenId = ownerToNFTokenIdList[_from][currentCount]; // Add // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentIndex] = lastTokenId; // update tokenToOwnerIndex tokenToOwnerIndex[lastTokenId] = currentIndex; // Delete // update ownerToNFTokenIdList ownerToNFTokenIdList[_from][currentCount] = 0; // update tokenToOwnerIndex tokenToOwnerIndex[_tokenId] = 0; } } /// @dev Add a NFT to a given address /// Throws if `_tokenId` is owned by someone. function _addTokenTo(address _to, uint _tokenId) internal { // assume always call on new tokenId or after _removeTokenFrom() call // Change the owner idToOwner[_tokenId] = _to; // Update owner token index tracking _addTokenToOwnerList(_to, _tokenId); // Change count tracking ownerToNFTokenCount[_to] += 1; } /// @dev Remove a NFT from a given address /// Throws if `_from` is not the current owner. function _removeTokenFrom(address _from, uint _tokenId) internal { require(idToOwner[_tokenId] == _from, "!owner remove"); // Change the owner idToOwner[_tokenId] = address(0); // Update owner token index tracking _removeTokenFromOwnerList(_from, _tokenId); // Change count tracking ownerToNFTokenCount[_from] -= 1; } /// @dev Execute transfer of a NFT. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the approved /// address for this NFT. (NOTE: `msg.sender` not allowed in internal function so pass `_sender`.) /// Throws if `_to` is the zero address. /// Throws if `_from` is not the current owner. /// Throws if `_tokenId` is not a valid NFT. function _transferFrom( address _from, address _to, uint _tokenId, address _sender ) internal { require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached"); require(_isApprovedOrOwner(_sender, _tokenId), "!owner sender"); require(_to != address(0), "dst is zero"); // from address will be checked in _removeTokenFrom() if (idToApprovals[_tokenId] != address(0)) { // Reset approvals idToApprovals[_tokenId] = address(0); } _removeTokenFrom(_from, _tokenId); _addTokenTo(_to, _tokenId); // Set the block of ownership transfer (for Flash NFT protection) ownershipChange[_tokenId] = block.number; // Log the transfer emit Transfer(_from, _to, _tokenId); } /* TRANSFER FUNCTIONS */ /// @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else /// they maybe be permanently lost. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. function transferFrom( address _from, address _to, uint _tokenId ) external override { _transferFrom(_from, _to, _tokenId, msg.sender); } function _isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint size; assembly { size := extcodesize(account) } return size > 0; } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. /// @param _data Additional data with no specified format, sent in call to `_to`. function safeTransferFrom( address _from, address _to, uint _tokenId, bytes memory _data ) public override { _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) {} catch ( bytes memory reason ) { if (reason.length == 0) { revert('ERC721: transfer to non ERC721Receiver implementer'); } else { assembly { revert(add(32, reason), mload(reason)) } } } } } /// @dev Transfers the ownership of an NFT from one address to another address. /// Throws unless `msg.sender` is the current owner, an authorized operator, or the /// approved address for this NFT. /// Throws if `_from` is not the current owner. /// Throws if `_to` is the zero address. /// Throws if `_tokenId` is not a valid NFT. /// If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if /// the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`. /// @param _from The current owner of the NFT. /// @param _to The new owner. /// @param _tokenId The NFT to transfer. function safeTransferFrom( address _from, address _to, uint _tokenId ) external override { safeTransferFrom(_from, _to, _tokenId, ''); } /// @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address. /// Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. /// Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP) /// Throws if `_approved` is the current owner. (NOTE: This is not written the EIP) /// @param _approved Address to be approved for the given NFT ID. /// @param _tokenId ID of the token to be approved. function approve(address _approved, uint _tokenId) public override { address owner = idToOwner[_tokenId]; // Throws if `_tokenId` is not a valid NFT require(owner != address(0), "invalid id"); // Throws if `_approved` is the current owner require(_approved != owner, "self approve"); // Check requirements bool senderIsOwner = (idToOwner[_tokenId] == msg.sender); bool senderIsApprovedForAll = (ownerToOperators[owner])[msg.sender]; require(senderIsOwner || senderIsApprovedForAll, "!owner"); // 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 override { // Throws if `_operator` is the `msg.sender` require(_operator != msg.sender, "operator is sender"); ownerToOperators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /// @dev Function to mint tokens /// Throws if `_to` is zero address. /// Throws if `_tokenId` is owned by someone. /// @param _to The address that will receive the minted tokens. /// @param _tokenId The token id to mint. /// @return A boolean that indicates if the operation was successful. function _mint(address _to, uint _tokenId) internal returns (bool) { // Throws if `_to` is zero address require(_to != address(0), "zero dst"); // Add NFT. Throws if `_tokenId` is owned by someone _addTokenTo(_to, _tokenId); emit Transfer(address(0), _to, _tokenId); return true; } /// @notice Record global and per-user data to checkpoint /// @param _tokenId NFT token ID. No user checkpoint if 0 /// @param oldLocked Pevious locked amount / end lock time for the user /// @param newLocked New locked amount / end lock time for the user function _checkpoint( uint _tokenId, LockedBalance memory oldLocked, LockedBalance memory newLocked ) internal { Point memory uOld; Point memory uNew; int128 oldDSlope = 0; int128 newDSlope = 0; uint _epoch = epoch; if (_tokenId != 0) { // Calculate slopes and biases // Kept at zero when they have to if (oldLocked.end > block.timestamp && oldLocked.amount > 0) { uOld.slope = oldLocked.amount / I_MAX_TIME; uOld.bias = uOld.slope * int128(int256(oldLocked.end - block.timestamp)); } if (newLocked.end > block.timestamp && newLocked.amount > 0) { uNew.slope = newLocked.amount / I_MAX_TIME; uNew.bias = uNew.slope * int128(int256(newLocked.end - block.timestamp)); } // Read values of scheduled changes in the slope // oldLocked.end can be in the past and in the future // newLocked.end can ONLY by in the FUTURE unless everything expired: than zeros oldDSlope = slopeChanges[oldLocked.end]; if (newLocked.end != 0) { if (newLocked.end == oldLocked.end) { newDSlope = oldDSlope; } else { newDSlope = slopeChanges[newLocked.end]; } } } Point memory lastPoint = Point({bias : 0, slope : 0, ts : block.timestamp, blk : block.number}); if (_epoch > 0) { lastPoint = _pointHistory[_epoch]; } uint lastCheckpoint = lastPoint.ts; // initialLastPoint is used for extrapolation to calculate block number // (approximately, for *At methods) and save them // as we cannot figure that out exactly from inside the contract Point memory initialLastPoint = lastPoint; uint blockSlope = 0; // dblock/dt if (block.timestamp > lastPoint.ts) { blockSlope = (MULTIPLIER * (block.number - lastPoint.blk)) / (block.timestamp - lastPoint.ts); } // If last point is already recorded in this block, slope=0 // But that's ok b/c we know the block in such case // Go over weeks to fill history and calculate what the current point is { uint ti = (lastCheckpoint / WEEK) * WEEK; // 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 for (uint i = 0; i < 255; ++i) { ti += WEEK; int128 dSlope = 0; if (ti > block.timestamp) { ti = block.timestamp; } else { dSlope = slopeChanges[ti]; } lastPoint.bias = Math.positiveInt128(lastPoint.bias - lastPoint.slope * int128(int256(ti - lastCheckpoint))); lastPoint.slope = Math.positiveInt128(lastPoint.slope + dSlope); lastCheckpoint = ti; lastPoint.ts = ti; lastPoint.blk = initialLastPoint.blk + (blockSlope * (ti - initialLastPoint.ts)) / MULTIPLIER; _epoch += 1; if (ti == block.timestamp) { lastPoint.blk = block.number; break; } else { _pointHistory[_epoch] = lastPoint; } } } epoch = _epoch; // Now pointHistory is filled until t=now if (_tokenId != 0) { // If last point was in this block, the slope change has been applied already // But in such case we have 0 slope(s) lastPoint.slope = Math.positiveInt128(lastPoint.slope + (uNew.slope - uOld.slope)); lastPoint.bias = Math.positiveInt128(lastPoint.bias + (uNew.bias - uOld.bias)); } // Record the changed point into history _pointHistory[_epoch] = lastPoint; if (_tokenId != 0) { // Schedule the slope changes (slope is going down) // We subtract newUserSlope from [newLocked.end] // and add old_user_slope to [old_locked.end] if (oldLocked.end > block.timestamp) { // old_dslope was <something> - u_old.slope, so we cancel that oldDSlope += uOld.slope; if (newLocked.end == oldLocked.end) { oldDSlope -= uNew.slope; // It was a new deposit, not extension } slopeChanges[oldLocked.end] = oldDSlope; } if (newLocked.end > block.timestamp) { if (newLocked.end > oldLocked.end) { newDSlope -= uNew.slope; // old slope disappeared at this point slopeChanges[newLocked.end] = newDSlope; } // else: we recorded it already in oldDSlope } // Now handle user history uint userEpoch = userPointEpoch[_tokenId] + 1; userPointEpoch[_tokenId] = userEpoch; uNew.ts = block.timestamp; uNew.blk = block.number; _userPointHistory[_tokenId][userEpoch] = uNew; } } /// @notice Deposit and lock tokens for a user /// @param _tokenId NFT that holds lock /// @param _value Amount to deposit /// @param unlockTime New time when to unlock the tokens, or 0 if unchanged /// @param lockedBalance Previous locked amount / timestamp /// @param depositType The type of deposit function _depositFor( uint _tokenId, uint _value, uint unlockTime, LockedBalance memory lockedBalance, DepositType depositType ) internal { LockedBalance memory _locked = lockedBalance; uint supplyBefore = supply; supply = supplyBefore + _value; LockedBalance memory oldLocked; (oldLocked.amount, oldLocked.end) = (_locked.amount, _locked.end); // Adding to existing lock, or if a lock is expired - creating a new one _locked.amount += int128(int256(_value)); if (unlockTime != 0) { _locked.end = unlockTime; } locked[_tokenId] = _locked; // Possibilities: // Both old_locked.end could be current or expired (>/< block.timestamp) // value == 0 (extend lock) or value > 0 (add to lock or extend lock) // _locked.end > block.timestamp (always) _checkpoint(_tokenId, oldLocked, _locked); address from = msg.sender; if (_value != 0 && depositType != DepositType.MERGE_TYPE) { IERC20(token).safeTransferFrom(from, address(this), _value); } emit Deposit(from, _tokenId, _value, _locked.end, depositType, block.timestamp); emit Supply(supplyBefore, supplyBefore + _value); } function voting(uint _tokenId) external override { require(msg.sender == _voter(), "!voter"); voted[_tokenId] = true; } function abstain(uint _tokenId) external override { require(msg.sender == _voter(), "!voter"); voted[_tokenId] = false; } function attachToken(uint _tokenId) external override { require(msg.sender == _voter(), "!voter"); attachments[_tokenId] = attachments[_tokenId] + 1; } function detachToken(uint _tokenId) external override { require(msg.sender == _voter(), "!voter"); attachments[_tokenId] = attachments[_tokenId] - 1; } function merge(uint _from, uint _to) external { require(attachments[_from] == 0 && !voted[_from], "attached"); require(_from != _to, "the same"); require(_isApprovedOrOwner(msg.sender, _from), "!owner from"); require(_isApprovedOrOwner(msg.sender, _to), "!owner to"); LockedBalance memory _locked0 = locked[_from]; LockedBalance memory _locked1 = locked[_to]; uint value0 = uint(int256(_locked0.amount)); uint end = _locked0.end >= _locked1.end ? _locked0.end : _locked1.end; locked[_from] = LockedBalance(0, 0); _checkpoint(_from, _locked0, LockedBalance(0, 0)); _burn(_from); _depositFor(_to, value0, end, _locked1, DepositType.MERGE_TYPE); } function block_number() external view returns (uint) { return block.number; } /// @notice Record global data to checkpoint function checkpoint() external override { _checkpoint(0, LockedBalance(0, 0), LockedBalance(0, 0)); } /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock /// @dev Anyone (even a smart contract) can deposit for someone else, but /// cannot extend their locktime and deposit for a brand new user /// @param _tokenId lock NFT /// @param _value Amount to add to user's lock function depositFor(uint _tokenId, uint _value) external lock override { require(_value > 0, "zero value"); LockedBalance memory _locked = locked[_tokenId]; require(_locked.amount > 0, 'No existing lock found'); require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw'); _depositFor(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE); } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function _createLock(uint _value, uint _lockDuration, address _to) internal returns (uint) { require(_value > 0, "zero value"); // Lock time is rounded down to weeks uint unlockTime = (block.timestamp + _lockDuration) / WEEK * WEEK; require(unlockTime > block.timestamp, 'Can only lock until time in the future'); require(unlockTime <= block.timestamp + MAX_TIME, 'Voting lock can be 4 years max'); ++tokenId; uint _tokenId = tokenId; _mint(_to, _tokenId); _depositFor(_tokenId, _value, unlockTime, locked[_tokenId], DepositType.CREATE_LOCK_TYPE); return _tokenId; } /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit function createLockFor(uint _value, uint _lockDuration, address _to) external lock override returns (uint) { return _createLock(_value, _lockDuration, _to); } /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lock_duration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) function createLock(uint _value, uint _lockDuration) external lock returns (uint) { return _createLock(_value, _lockDuration, msg.sender); } /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time /// @param _value Amount of tokens to deposit and add to the lock function increaseAmount(uint _tokenId, uint _value) external lock { LockedBalance memory _locked = locked[_tokenId]; require(_locked.amount > 0, 'No existing lock found'); require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw'); require(_isApprovedOrOwner(msg.sender, _tokenId), "!owner"); require(_value > 0, "zero value"); _depositFor(_tokenId, _value, 0, _locked, DepositType.INCREASE_LOCK_AMOUNT); } /// @notice Extend the unlock time for `_tokenId` /// @param _lockDuration New number of seconds until tokens unlock function increaseUnlockTime(uint _tokenId, uint _lockDuration) external lock { LockedBalance memory _locked = locked[_tokenId]; // Lock time is rounded down to weeks uint unlockTime = (block.timestamp + _lockDuration) / WEEK * WEEK; require(_locked.amount > 0, 'Nothing is locked'); require(_locked.end > block.timestamp, 'Lock expired'); require(unlockTime > _locked.end, 'Can only increase lock duration'); require(unlockTime <= block.timestamp + MAX_TIME, 'Voting lock can be 4 years max'); require(_isApprovedOrOwner(msg.sender, _tokenId), "!owner"); _depositFor(_tokenId, 0, unlockTime, _locked, DepositType.INCREASE_UNLOCK_TIME); } /// @notice Withdraw all tokens for `_tokenId` /// @dev Only possible if the lock has expired function withdraw(uint _tokenId) external lock { require(_isApprovedOrOwner(msg.sender, _tokenId), "!owner"); require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached"); LockedBalance memory _locked = locked[_tokenId]; require(block.timestamp >= _locked.end, "The lock did not expire"); uint value = uint(int256(_locked.amount)); locked[_tokenId] = LockedBalance(0, 0); uint supplyBefore = supply; supply = supplyBefore - 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)); IERC20(token).safeTransfer(msg.sender, value); // Burn the NFT _burn(_tokenId); emit Withdraw(msg.sender, _tokenId, value, block.timestamp); emit Supply(supplyBefore, supplyBefore - value); } // The following ERC20/minime-compatible methods are not real balanceOf and supply! // They measure the weights for the purpose of voting, so they don't represent // real coins. /// @notice Binary search to estimate timestamp for block number /// @param _block Block to find /// @param maxEpoch Don't go beyond this epoch /// @return Approximate timestamp for block function _findBlockEpoch(uint _block, uint maxEpoch) internal view returns (uint) { // Binary search uint _min = 0; uint _max = maxEpoch; for (uint i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint _mid = (_min + _max + 1) / 2; if (_pointHistory[_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } return _min; } /// @notice Get the current voting power for `_tokenId` /// @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility /// @param _tokenId NFT for lock /// @param _t Epoch time to return voting power at /// @return User voting power function _balanceOfNFT(uint _tokenId, uint _t) internal view returns (uint) { uint _epoch = userPointEpoch[_tokenId]; if (_epoch == 0) { return 0; } else { Point memory lastPoint = _userPointHistory[_tokenId][_epoch]; lastPoint.bias -= lastPoint.slope * int128(int256(_t) - int256(lastPoint.ts)); if (lastPoint.bias < 0) { lastPoint.bias = 0; } return uint(int256(lastPoint.bias)); } } /// @dev Returns current token URI metadata /// @param _tokenId Token ID to fetch URI for. function tokenURI(uint _tokenId) external view override returns (string memory) { require(idToOwner[_tokenId] != address(0), "Query for nonexistent token"); LockedBalance memory _locked = locked[_tokenId]; return _tokenURI( _tokenId, _balanceOfNFT(_tokenId, block.timestamp), _locked.end, uint(int256(_locked.amount)) ); } function balanceOfNFT(uint _tokenId) external view override returns (uint) { // flash NFT protection if (ownershipChange[_tokenId] == block.number) { return 0; } return _balanceOfNFT(_tokenId, block.timestamp); } function balanceOfNFTAt(uint _tokenId, uint _t) external view returns (uint) { return _balanceOfNFT(_tokenId, _t); } /// @notice Measure voting power of `_tokenId` at block height `_block` /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime /// @param _tokenId User's wallet NFT /// @param _block Block to calculate the voting power at /// @return Voting power function _balanceOfAtNFT(uint _tokenId, uint _block) internal view returns (uint) { // Copying and pasting totalSupply code because Vyper cannot pass by // reference yet require(_block <= block.number, "only old block"); // Binary search uint _min = 0; uint _max = userPointEpoch[_tokenId]; for (uint i = 0; i < 128; ++i) { // Will be always enough for 128-bit numbers if (_min >= _max) { break; } uint _mid = (_min + _max + 1) / 2; if (_userPointHistory[_tokenId][_mid].blk <= _block) { _min = _mid; } else { _max = _mid - 1; } } Point memory uPoint = _userPointHistory[_tokenId][_min]; uint maxEpoch = epoch; uint _epoch = _findBlockEpoch(_block, maxEpoch); Point memory point0 = _pointHistory[_epoch]; uint dBlock = 0; uint dt = 0; if (_epoch < maxEpoch) { Point memory point1 = _pointHistory[_epoch + 1]; dBlock = point1.blk - point0.blk; dt = point1.ts - point0.ts; } else { dBlock = block.number - point0.blk; dt = block.timestamp - point0.ts; } uint blockTime = point0.ts; if (dBlock != 0 && _block > point0.blk) { blockTime += (dt * (_block - point0.blk)) / dBlock; } uPoint.bias -= uPoint.slope * int128(int256(blockTime - uPoint.ts)); return uint(uint128(Math.positiveInt128(uPoint.bias))); } function balanceOfAtNFT(uint _tokenId, uint _block) external view returns (uint) { return _balanceOfAtNFT(_tokenId, _block); } /// @notice Calculate total voting power at some point in the past /// @param point The point (bias/slope) to start search from /// @param t Time to calculate the total voting power at /// @return Total voting power at that time function _supplyAt(Point memory point, uint t) internal view returns (uint) { Point memory lastPoint = point; uint ti = (lastPoint.ts / WEEK) * WEEK; for (uint i = 0; i < 255; ++i) { ti += WEEK; int128 dSlope = 0; if (ti > t) { ti = t; } else { dSlope = slopeChanges[ti]; } lastPoint.bias -= lastPoint.slope * int128(int256(ti - lastPoint.ts)); if (ti == t) { break; } lastPoint.slope += dSlope; lastPoint.ts = ti; } return uint(uint128(Math.positiveInt128(lastPoint.bias))); } /// @notice Calculate total voting power /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility /// @return Total voting power function totalSupplyAtT(uint t) public view returns (uint) { uint _epoch = epoch; Point memory lastPoint = _pointHistory[_epoch]; return _supplyAt(lastPoint, t); } function totalSupply() external view returns (uint) { return totalSupplyAtT(block.timestamp); } /// @notice Calculate total voting power at some point in the past /// @param _block Block to calculate the total voting power at /// @return Total voting power at `_block` function totalSupplyAt(uint _block) external view returns (uint) { require(_block <= block.number, "only old blocks"); uint _epoch = epoch; uint targetEpoch = _findBlockEpoch(_block, _epoch); Point memory point = _pointHistory[targetEpoch]; // it is possible only for a block before the launch // return 0 as more clear answer than revert if (point.blk > _block) { return 0; } uint dt = 0; if (targetEpoch < _epoch) { Point memory point_next = _pointHistory[targetEpoch + 1]; // next point block can not be the same or lower 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 _supplyAt(point, point.ts + dt); } function _tokenURI(uint _tokenId, uint _balanceOf, uint _locked_end, uint _value) internal pure returns (string memory output) { output = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: black; font-family: Impact; font-size: 50px; }</style><rect width="100%" height="100%" fill="#aaaaff" /><text x="10" y="60" class="base">'; output = string(abi.encodePacked(output, "token ", _toString(_tokenId), '</text><text x="10" y="150" class="base">')); output = string(abi.encodePacked(output, "balanceOf ", _toString(_balanceOf), '</text><text x="10" y="230" class="base">')); output = string(abi.encodePacked(output, "locked_end ", _toString(_locked_end), '</text><text x="10" y="310" class="base">')); output = string(abi.encodePacked(output, "value ", _toString(_value), '</text></svg>')); string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "lock #', _toString(_tokenId), '", "description": "Dystopia locks, can be used to boost gauge yields, vote on token emission, and receive bribes", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}')))); output = string(abi.encodePacked('data:application/json;base64,', json)); } function _toString(uint value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT license // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint temp = value; uint digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint(value % 10))); value /= 10; } return string(buffer); } function _burn(uint _tokenId) internal { address owner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // Remove token _removeTokenFrom(msg.sender, _tokenId); emit Transfer(owner, address(0), _tokenId); } function userPointHistory(uint _tokenId, uint _loc) external view override returns (Point memory) { return _userPointHistory[_tokenId][_loc]; } function pointHistory(uint _loc) external view override returns (Point memory) { return _pointHistory[_loc]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /// @title Base64 /// @notice Provides a function for encoding some bytes in base64 /// @author Brecht Devos <[email protected]> library Base64 { bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /// @notice Encodes some bytes to the base64 representation function encode(bytes memory data) internal pure returns (string memory) { uint len = data.length; if (len == 0) return ""; // multiply by 4/3 rounded up uint encodedLen = 4 * ((len + 2) / 3); // Add some extra buffer at the end bytes memory result = new bytes(encodedLen + 32); bytes memory table = TABLE; assembly { let tablePtr := add(table, 1) let resultPtr := add(result, 32) for { let i := 0 } lt(i, len) { } { i := add(i, 3) let input := and(mload(add(data, i)), 0xffffff) let out := mload(add(tablePtr, and(shr(18, input), 0x3F))) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)) out := shl(224, out) mstore(resultPtr, out) resultPtr := add(resultPtr, 4) } switch mod(len, 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } mstore(result, encodedLen) } return string(result); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "./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`, 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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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 Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @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 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); /** * @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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; 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(uint tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IVe { enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME, MERGE_TYPE } struct Point { int128 bias; int128 slope; // # -dweight / dt uint ts; uint blk; // block } /* We cannot really do block numbers per se b/c slope is per time, not per block * and per block could be fairly bad b/c Ethereum changes blocktimes. * What we can do is to extrapolate ***At functions */ struct LockedBalance { int128 amount; uint end; } function token() external view returns (address); function balanceOfNFT(uint) external view returns (uint); function isApprovedOrOwner(address, uint) external view returns (bool); function createLockFor(uint, uint, address) external returns (uint); function userPointEpoch(uint tokenId) external view returns (uint); function epoch() external view returns (uint); function userPointHistory(uint tokenId, uint loc) external view returns (Point memory); function pointHistory(uint loc) external view returns (Point memory); function checkpoint() external; function depositFor(uint tokenId, uint value) external; function attachToken(uint tokenId) external; function detachToken(uint tokenId) external; function voting(uint tokenId) external; function abstain(uint tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @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 `IERC721.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 IController { function veDist() external view returns (address); function voter() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; abstract contract Reentrancy { /// @dev simple re-entrancy check uint internal _unlocked = 1; modifier lock() { require(_unlocked == 1, "Reentrant call"); _unlocked = 2; _; _unlocked = 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.13; import "../interface/IERC20.sol"; import "./Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint value ) internal { uint newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; library Math { function max(uint a, uint b) internal pure returns (uint) { return a >= b ? a : b; } function min(uint a, uint b) internal pure returns (uint) { return a < b ? a : b; } function positiveInt128(int128 value) internal pure returns (int128) { return value < 0 ? int128(0) : value; } function closeTo(uint a, uint b, uint target) internal pure returns (bool) { if (a > b) { if (a - b <= target) { return true; } } else { if (b - a <= target) { return true; } } return false; } function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.13; /** * @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; } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"controller_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"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 IVe.DepositType","name":"depositType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Deposit","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":[{"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":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"attachToken","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":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"}],"name":"createLock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"createLockFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"detachToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getLastUserSlope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"increaseAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"}],"name":"increaseUnlockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_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":"end","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"lockedEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownershipChange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_loc","type":"uint256"}],"name":"pointHistory","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"}],"internalType":"struct IVe.Point","name":"","type":"tuple"}],"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":"uint256","name":"","type":"uint256"}],"name":"slopeChanges","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","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":"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":"userPointEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_loc","type":"uint256"}],"name":"userPointHistory","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"}],"internalType":"struct IVe.Point","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"userPointHistoryTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"voted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"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
60a060405260016000553480156200001657600080fd5b50604051620042a3380380620042a383398101604081905262000039916200019d565b6001600160a01b03828116608052600b80546001600160a01b031916918316919091179055437f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746be55427f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bd5560136020527f317681100331673b27c2499894e78912f138ae85f2dd790e454ff96a89cf2d77805460ff1990811660019081179092557f5829b1f18259a9cdcd4268c3b072804d2f8e3dedbb1b883db1fa2055bb26d84f8054821683179055635b5e139f60e01b60009081527f65cb089fa41783e5af12e88573d882f263c09532a373334f0b809825d5a904ab80549092169092179055600c546040519091309160008051602062004283833981519152908290a4600c54604051600090309060008051602062004283833981519152908390a45050620001d5565b80516001600160a01b03811681146200019857600080fd5b919050565b60008060408385031215620001b157600080fd5b620001bc8362000180565b9150620001cc6020840162000180565b90509250929050565b608051614084620001ff6000396000818161083701528181610caf0152611bc801526140846000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80638ad4c4471161019d578063c1f0fb9f116100e9578063e7e242d4116100a2578063f52a36f71161007c578063f52a36f7146107fc578063f77c47911461081f578063fc0c546a14610832578063fd4a77f11461085957600080fd5b8063e7e242d41461079a578063e985e9c5146107ad578063ec32e6df146107e957600080fd5b8063c1f0fb9f14610726578063c2c4c5c114610739578063c87b56dd14610741578063d1c2babb14610754578063e0514aba14610767578063e58f59471461077a57600080fd5b806398782b4e11610156578063b2383e5511610130578063b2383e55146106a5578063b45a3c0e146106b8578063b52c05fe14610700578063b88d4fde1461071357600080fd5b806398782b4e1461066c5780639d507b8b1461067f578063a22cb4651461069257600080fd5b80638ad4c447146106075780638c2c9baf1461061a5780638fbb38ff1461062d578063900cf0cf1461065057806395d89b4114610362578063981b24d01461065957600080fd5b80632e1a7d4d1161025c57806346b3bd0011610215578063626944df116101ef578063626944df146105955780636352211e146105b857806370a08231146105e15780637116c60c146105f457600080fd5b806346b3bd001461053857806354fd4d501461054b5780635633e0a61461056f57600080fd5b80632e1a7d4d1461045e5780632f745c5914610471578063313ce567146104a757806342842e0e146104c1578063430c2081146104d457806344acb42a146104e757600080fd5b80630d6a2033116102ae5780630d6a2033146103ea5780630ec84dda1461040a57806318160ddd1461041d57806323857d511461042557806323b872dd1461044557806325a58b561461045857600080fd5b806301ffc9a7146102f6578063047fc9aa1461033857806305ae4f8c1461034f57806306fdde0314610362578063081812fc14610394578063095ea7b3146103d5575b600080fd5b61032361030436600461345e565b6001600160e01b03191660009081526013602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61034160015481565b60405190815260200161032f565b61034161035d36600461347b565b61086c565b610387604051806040016040528060068152602001651d99511654d560d21b81525081565b60405161032f91906134f5565b6103bd6103a2366004613508565b6000908152600e60205260409020546001600160a01b031690565b6040516001600160a01b03909116815260200161032f565b6103e86103e3366004613536565b61089f565b005b6103416103f8366004613508565b60096020526000908152604090205481565b6103e861041836600461347b565b610a01565b610341610af6565b610341610433366004613508565b60036020526000908152604090205481565b6103e8610453366004613562565b610b06565b43610341565b6103e861046c366004613508565b610b17565b61034161047f366004613536565b6001600160a01b03919091166000908152601060209081526040808320938352929052205490565b6104af601281565b60405160ff909116815260200161032f565b6103e86104cf366004613562565b610d70565b6103236104e2366004613536565b610d8b565b6104fa6104f536600461347b565b610d9e565b60405161032f919060006080820190508251600f0b82526020830151600f0b6020830152604083015160408301526060830151606083015292915050565b6103e8610546366004613508565b610e12565b610387604051806040016040528060058152602001640312e302e360dc1b81525081565b61058261057d366004613508565b610e76565b604051600f9190910b815260200161032f565b6103416105a3366004613508565b60009081526002602052604090206001015490565b6103bd6105c6366004613508565b6000908152600d60205260409020546001600160a01b031690565b6103416105ef3660046135a3565b610eb9565b610341610602366004613508565b610ed7565b6104fa610615366004613508565b610f37565b61034161062836600461347b565b610f8e565b61032361063b366004613508565b600a6020526000908152604090205460ff1681565b61034160045481565b610341610667366004613508565b610f9a565b6103e861067a366004613508565b611178565b6103e861068d36600461347b565b6111cb565b6103e86106a03660046135ce565b6113bd565b6103e86106b336600461347b565b611476565b6106e66106c6366004613508565b60026020526000908152604090208054600190910154600f9190910b9082565b60408051600f9390930b835260208301919091520161032f565b61034161070e36600461347b565b611588565b6103e861072136600461361d565b6115c7565b6103e8610734366004613508565b6116f7565b6103e8611747565b61038761074f366004613508565b611787565b6103e861076236600461347b565b611834565b61034161077536600461347b565b611a2f565b610341610788366004613508565b60076020526000908152604090205481565b6103416107a8366004613508565b611a3b565b6103236107bb3660046136fd565b6001600160a01b03918216600090815260126020908152604080832093909416825291909152205460ff1690565b6103416107f736600461372b565b611a63565b61058261080a366004613508565b600860205260009081526040902054600f0b81565b600b546103bd906001600160a01b031681565b6103bd7f000000000000000000000000000000000000000000000000000000000000000081565b6103e8610867366004613508565b611aa3565b600082815260066020526040812082633b9aca00811061088e5761088e613764565b600302016001015490505b92915050565b6000818152600d60205260409020546001600160a01b0316806108f65760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b60448201526064015b60405180910390fd5b806001600160a01b0316836001600160a01b0316036109465760405162461bcd60e51b815260206004820152600c60248201526b73656c6620617070726f766560a01b60448201526064016108ed565b6000828152600d60209081526040808320546001600160a01b0385811685526012845282852033808752945291909320549216149060ff1681806109875750805b6109a35760405162461bcd60e51b81526004016108ed9061377a565b6000848152600e602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b600054600114610a235760405162461bcd60e51b81526004016108ed9061379a565b600260005580610a455760405162461bcd60e51b81526004016108ed906137c2565b600082815260026020908152604080832081518083019092528054600f0b808352600190910154928201929092529112610aba5760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b60448201526064016108ed565b42816020015111610add5760405162461bcd60e51b81526004016108ed906137e6565b610aec83836000846000611af6565b5050600160005550565b6000610b0142610ed7565b905090565b610b1283838333611c8b565b505050565b600054600114610b395760405162461bcd60e51b81526004016108ed9061379a565b6002600055610b483382611df8565b610b645760405162461bcd60e51b81526004016108ed9061377a565b600081815260096020526040902054158015610b8f57506000818152600a602052604090205460ff16155b610bab5760405162461bcd60e51b81526004016108ed9061382a565b60008181526002602090815260409182902082518084019093528054600f0b835260010154908201819052421015610c255760405162461bcd60e51b815260206004820152601760248201527f546865206c6f636b20646964206e6f742065787069726500000000000000000060448201526064016108ed565b8051604080518082018252600080825260208083018281528783526002909152929020905181546001600160801b0319166001600160801b03909116178155905160019182015554600f9190910b90610c7e8282613862565b6001556040805180820190915260008082526020820152610ca29085908590611e5e565b610cd66001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633846123ee565b610cdf84612451565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c81610d4d8482613862565b6040805192835260208301919091520160405180910390a1505060016000555050565b610b12838383604051806020016040528060008152506115c7565b6000610d978383611df8565b9392505050565b610da6613417565b600083815260066020526040902082633b9aca008110610dc857610dc8613764565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282019290925260029091015460608201529392505050565b610e1a6124ba565b6001600160a01b0316336001600160a01b031614610e4a5760405162461bcd60e51b81526004016108ed90613879565b600081815260096020526040902054610e64906001613899565b60009182526009602052604090912055565b6000818152600760209081526040808320546006909252822081633b9aca008110610ea357610ea3613764565b6003020154600160801b9004600f0b9392505050565b6001600160a01b0381166000908152600f6020526040812054610899565b600454600081815260056020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152909190610f2f8185612528565b949350505050565b610f3f613417565b5060009081526005602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015290565b6000610d97838361261f565b600043821115610fde5760405162461bcd60e51b815260206004820152600f60248201526e6f6e6c79206f6c6420626c6f636b7360881b60448201526064016108ed565b6004546000610fed8483612922565b60008181526005602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082018190529192509085101561105057506000949350505050565b60008383101561110657600060058161106a866001613899565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528501519192506110c79190613862565b836040015182604001516110db9190613862565b60608501516110ea908a613862565b6110f491906138b1565b6110fe91906138e6565b915050611155565b438260600151146111555760608201516111209043613862565b604083015161112f9042613862565b606084015161113e9089613862565b61114891906138b1565b61115291906138e6565b90505b61116e828284604001516111699190613899565b612528565b9695505050505050565b6111806124ba565b6001600160a01b0316336001600160a01b0316146111b05760405162461bcd60e51b81526004016108ed90613879565b600081815260096020526040902054610e6490600190613862565b6000546001146111ed5760405162461bcd60e51b81526004016108ed9061379a565b600260008181558381526020918252604080822081518083019092528054600f0b8252600101549281019290925262093a808061122a8542613899565b61123491906138e6565b61123e91906138b1565b905060008260000151600f0b1361128b5760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b60448201526064016108ed565b428260200151116112cd5760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b60448201526064016108ed565b816020015181116113205760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e0060448201526064016108ed565b61132e630784ce0042613899565b81111561137d5760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d6178000060448201526064016108ed565b6113873385611df8565b6113a35760405162461bcd60e51b81526004016108ed9061377a565b6113b284600083856003611af6565b505060016000555050565b336001600160a01b0383160361140a5760405162461bcd60e51b815260206004820152601260248201527137b832b930ba37b91034b99039b2b73232b960711b60448201526064016108ed565b3360008181526012602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6000546001146114985760405162461bcd60e51b81526004016108ed9061379a565b600260008181558381526020918252604080822081518083019092528054600f0b8083526001909101549382019390935291136115105760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b60448201526064016108ed565b428160200151116115335760405162461bcd60e51b81526004016108ed906137e6565b61153d3384611df8565b6115595760405162461bcd60e51b81526004016108ed9061377a565b600082116115795760405162461bcd60e51b81526004016108ed906137c2565b610aec83836000846002611af6565b600080546001146115ab5760405162461bcd60e51b81526004016108ed9061379a565b60026000556115bb8383336129a8565b60016000559392505050565b6115d384848433611c8b565b823b156116f157604051630a85bd0160e11b81526001600160a01b0384169063150b7a029061160c9033908890879087906004016138fa565b6020604051808303816000875af1925050508015611647575060408051601f3d908101601f191682019092526116449181019061392d565b60015b6116ef573d808015611675576040519150601f19603f3d011682016040523d82523d6000602084013e61167a565b606091505b5080516000036116e75760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60648201526084016108ed565b805181602001fd5b505b50505050565b6116ff6124ba565b6001600160a01b0316336001600160a01b03161461172f5760405162461bcd60e51b81526004016108ed90613879565b6000908152600a60205260409020805460ff19169055565b611785600060405180604001604052806000600f0b8152602001600081525060405180604001604052806000600f0b81526020016000815250611e5e565b565b6000818152600d60205260409020546060906001600160a01b03166117ee5760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e000000000060448201526064016108ed565b60008281526002602090815260409182902082518084019093528054600f0b83526001015490820152610d97836118258142612b12565b60208401518451600f0b612be6565b60008281526009602052604090205415801561185f57506000828152600a602052604090205460ff16155b61187b5760405162461bcd60e51b81526004016108ed9061382a565b8082036118b55760405162461bcd60e51b81526020600482015260086024820152677468652073616d6560c01b60448201526064016108ed565b6118bf3383611df8565b6118f95760405162461bcd60e51b815260206004820152600b60248201526a216f776e65722066726f6d60a81b60448201526064016108ed565b6119033382611df8565b61193b5760405162461bcd60e51b8152602060048201526009602482015268216f776e657220746f60b81b60448201526064016108ed565b6000828152600260208181526040808420815180830183528154600f90810b825260019283015482860190815288885295855283872084518086019095528054820b855290920154938301849052805194519095929490910b9211156119a55782602001516119ab565b83602001515b604080518082018252600080825260208083018281528b835260028252848320935184546001600160801b0319166001600160801b0390911617845551600190930192909255825180840190935280835290820152909150611a109087908690611e5e565b611a1986612451565b611a27858383866004611af6565b505050505050565b6000610d978383612b12565b600081815260036020526040812054439003611a5957506000919050565b6108998242612b12565b60008054600114611a865760405162461bcd60e51b81526004016108ed9061379a565b6002600055611a968484846129a8565b6001600055949350505050565b611aab6124ba565b6001600160a01b0316336001600160a01b031614611adb5760405162461bcd60e51b81526004016108ed90613879565b6000908152600a60205260409020805460ff19166001179055565b6001548290611b058682613899565b6001556040805180820190915260008082526020820152825160208085015190830152600f0b8152825187908490611b3e90839061394a565b600f0b9052508515611b5257602083018690525b6000888152600260209081526040909120845181546001600160801b0319166001600160801b0390911617815590840151600190910155611b94888285611e5e565b338715801590611bb657506004856004811115611bb357611bb3613999565b14155b15611bf057611bf06001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682308b612d1f565b8360200151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b8942604051611c3494939291906139af565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c83611c688a82613899565b6040805192835260208301919091520160405180910390a1505050505050505050565b600082815260096020526040902054158015611cb657506000828152600a602052604090205460ff16155b611cd25760405162461bcd60e51b81526004016108ed9061382a565b611cdc8183611df8565b611d185760405162461bcd60e51b815260206004820152600d60248201526c10b7bbb732b91039b2b73232b960991b60448201526064016108ed565b6001600160a01b038316611d5c5760405162461bcd60e51b815260206004820152600b60248201526a647374206973207a65726f60a81b60448201526064016108ed565b6000828152600e60205260409020546001600160a01b031615611d96576000828152600e6020526040902080546001600160a01b03191690555b611da08483612d57565b611daa8383612e08565b6000828152600360205260408082204390555183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b6000818152600d6020908152604080832054600e8352818420546001600160a01b039182168086526012855283862088841680885295529285205492938085149392909116149060ff168280611e4b5750815b80611e535750805b979650505050505050565b611e66613417565b611e6e613417565b60045460009081908715611f9157428760200151118015611e96575060008760000151600f0b135b15611edb578651611eac90630784ce00906139ed565b600f0b602080870191909152870151611ec6904290613862565b8560200151611ed59190613a2b565b600f0b85525b428660200151118015611ef5575060008660000151600f0b135b15611f3a578551611f0b90630784ce00906139ed565b600f0b602080860191909152860151611f25904290613862565b8460200151611f349190613a2b565b600f0b84525b602080880151600090815260088252604090205490870151600f9190910b935015611f91578660200151866020015103611f7657829150611f91565b602080870151600090815260089091526040902054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612006575060008181526005602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b6040810151816000428310156120535760408401516120259042613862565b60608501516120349043613862565b61204690670de0b6b3a76400006138b1565b61205091906138e6565b90505b600062093a8061206381866138e6565b61206d91906138b1565b905060005b60ff8110156121c05761208862093a8083613899565b915060004283111561209c574292506120b0565b50600082815260086020526040902054600f0b5b6120dd6120bd8785613862565b88602001516120cc9190613a2b565b88516120d89190613ac0565b612e79565b600f0b875260208701516120f6906120d890839061394a565b600f0b602088015260408088018490528501519295508592670de0b6b3a7640000906121229085613862565b61212c90866138b1565b61213691906138e6565b85606001516121459190613899565b6060880152612155600189613899565b975042830361216a57504360608701526121c0565b6000888152600560209081526040918290208951918a01516001600160801b03908116600160801b0292169190911781559088015160018201556060880151600290910155506121b981613b10565b9050612072565b505060048590558b1561221e576121f3896020015189602001516121e49190613ac0565b85602001516120d8919061394a565b600f0b6020850152885188516122189161220c91613ac0565b85516120d8919061394a565b600f0b84525b6000858152600560209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b156123e057428b6020015111156122d5576020890151612284908861394a565b96508a602001518a60200151036122a75760208801516122a49088613ac0565b96505b60208b810151600090815260089091526040902080546001600160801b0319166001600160801b0389161790555b428a602001511115612330578a602001518a6020015111156123305760208801516123009087613ac0565b60208b810151600090815260089091526040902080546001600160801b0319166001600160801b03831617905595505b60008c81526007602052604081205461234a906001613899565b905080600760008f815260200190815260200160002081905550428960400181815250504389606001818152505088600660008f815260200190815260200160002082633b9aca0081106123a0576123a0613764565b825160208401516001600160801b03908116600160801b029116176003919091029190910190815560408201516001820155606090910151600290910155505b505050505050505050505050565b6040516001600160a01b038316602482015260448101829052610b1290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612e93565b6000818152600d60205260408120546001600160a01b031690612474908361089f565b61247e3383612d57565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600b54604080516311b25aab60e21b815290516000926001600160a01b0316916346c96aac9160048083019260209291908290030181865afa158015612504573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b019190613b29565b600080839050600062093a8080836040015161254491906138e6565b61254e91906138b1565b905060005b60ff8110156126015761256962093a8083613899565b915060008583111561257d57859250612591565b50600082815260086020526040902054600f0b5b60408401516125a09084613862565b84602001516125af9190613a2b565b845185906125be908390613ac0565b600f0b9052508583036125d15750612601565b80846020018181516125e3919061394a565b600f0b90525050604083018290526125fa81613b10565b9050612553565b50815161260d90612e79565b6001600160801b031695945050505050565b6000438211156126625760405162461bcd60e51b815260206004820152600e60248201526d6f6e6c79206f6c6420626c6f636b60901b60448201526064016108ed565b600083815260076020526040812054815b6080811015612702578183101561270257600060026126928486613899565b61269d906001613899565b6126a791906138e6565b6000888152600660205260409020909150869082633b9aca0081106126ce576126ce613764565b6003020160020154116126e3578093506126f1565b6126ee600182613862565b92505b506126fb81613b10565b9050612673565b50600085815260066020526040812083633b9aca00811061272557612725613764565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b60208301526001810154928201929092526002909101546060820152600454909150600061277a8783612922565b600081815260056020908152604080832081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606082015291925080848410156128595760006005816127de876001613899565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606080830182905286015191925061283b9190613862565b9250836040015181604001516128519190613862565b91505061287d565b60608301516128689043613862565b915082604001514261287a9190613862565b90505b60408301518215801590612894575083606001518b115b156128cb578284606001518c6128aa9190613862565b6128b490846138b1565b6128be91906138e6565b6128c89082613899565b90505b60408701516128da9082613862565b87602001516128e99190613a2b565b875188906128f8908390613ac0565b600f0b905250865161290990612e79565b6001600160801b03169c9b505050505050505050505050565b60008082815b608081101561299e578183101561299e57600060026129478486613899565b612952906001613899565b61295c91906138e6565b600081815260056020526040902060020154909150871061297f5780935061298d565b61298a600182613862565b92505b5061299781613b10565b9050612928565b5090949350505050565b60008084116129c95760405162461bcd60e51b81526004016108ed906137c2565b600062093a80806129da8642613899565b6129e491906138e6565b6129ee91906138b1565b9050428111612a4e5760405162461bcd60e51b815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201526566757475726560d01b60648201526084016108ed565b612a5c630784ce0042613899565b811115612aab5760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d6178000060448201526064016108ed565b600c60008154612aba90613b10565b90915550600c54612acb8482612f65565b5060008181526002602090815260409182902082518084019093528054600f0b835260019081015491830191909152612b0991839189918691611af6565b95945050505050565b600082815260076020526040812054808203612b32576000915050610899565b600084815260066020526040812082633b9aca008110612b5457612b54613764565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282018390526002015460608201529150612ba09085613b46565b8160200151612baf9190613a2b565b81518290612bbe908390613ac0565b600f90810b90915282516000910b12159050612bd957600081525b51600f0b91506108999050565b60606040518061012001604052806101008152602001613f4f6101009139905080612c1086612ff3565b604051602001612c21929190613b85565b604051602081830303815290604052905080612c3c85612ff3565b604051602001612c4d929190613c02565b604051602081830303815290604052905080612c6884612ff3565b604051602001612c79929190613c83565b604051602081830303815290604052905080612c9483612ff3565b604051602001612ca5929190613d05565b60405160208183030381529060405290506000612cf2612cc487612ff3565b612ccd846130f4565b604051602001612cde929190613d60565b6040516020818303038152906040526130f4565b905080604051602001612d059190613e7c565b604051602081830303815290604052915050949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526116f19085906323b872dd60e01b9060840161241a565b6000818152600d60205260409020546001600160a01b03838116911614612db05760405162461bcd60e51b815260206004820152600d60248201526c216f776e65722072656d6f766560981b60448201526064016108ed565b6000818152600d6020526040902080546001600160a01b0319169055612dd6828261325e565b6001600160a01b0382166000908152600f60205260408120805460019290612dff908490613862565b90915550505050565b6000818152600d6020908152604080832080546001600160a01b0319166001600160a01b038716908117909155808452600f80845282852080546010865284872081885286528487208890558787526011865293862093909355908452909152805460019290612dff908490613899565b60008082600f0b12612e8b5781610899565b600092915050565b6000612ee8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661331d9092919063ffffffff16565b805190915015610b125780806020019051810190612f069190613ec1565b610b125760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108ed565b60006001600160a01b038316612fa85760405162461bcd60e51b81526020600482015260086024820152671e995c9bc8191cdd60c21b60448201526064016108ed565b612fb28383612e08565b60405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b60608160000361301a5750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613044578061302e81613b10565b915061303d9050600a836138e6565b915061301e565b60008167ffffffffffffffff81111561305f5761305f613607565b6040519080825280601f01601f191660200182016040528015613089576020820181803683370190505b5090505b8415610f2f5761309e600183613862565b91506130ab600a86613ede565b6130b6906030613899565b60f81b8183815181106130cb576130cb613764565b60200101906001600160f81b031916908160001a9053506130ed600a866138e6565b945061308d565b80516060906000819003613118575050604080516020810190915260008152919050565b60006003613127836002613899565b61313191906138e6565b61313c9060046138b1565b9050600061314b826020613899565b67ffffffffffffffff81111561316357613163613607565b6040519080825280601f01601f19166020018201604052801561318d576020820181803683370190505b5090506000604051806060016040528060408152602001613f0f604091399050600181016020830160005b86811015613219576003818a01810151603f601282901c8116860151600c83901c8216870151600684901c831688015192909316870151600891821b60ff94851601821b92841692909201901b91160160e01b8352600490920191016131b8565b506003860660018114613233576002811461324457613250565b613d3d60f01b600119830152613250565b603d60f81b6000198301525b505050918152949350505050565b6001600160a01b0382166000908152600f602052604081205461328390600190613862565b6000838152601160205260409020549091508082036132d2576001600160a01b0384166000908152601060209081526040808320858452825280832083905585835260119091528120556116f1565b6001600160a01b039390931660009081526010602090815260408083209383529281528282208054868452848420819055835260119091528282209490945592839055908252812055565b60606001600160a01b0384163b6133765760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108ed565b600080856001600160a01b0316856040516133919190613ef2565b6000604051808303816000865af19150503d80600081146133ce576040519150601f19603f3d011682016040523d82523d6000602084013e6133d3565b606091505b509150915061116e828286606083156133ed575081610d97565b8251156133fd5782518084602001fd5b8160405162461bcd60e51b81526004016108ed91906134f5565b60405180608001604052806000600f0b81526020016000600f0b815260200160008152602001600081525090565b6001600160e01b03198116811461345b57600080fd5b50565b60006020828403121561347057600080fd5b8135610d9781613445565b6000806040838503121561348e57600080fd5b50508035926020909101359150565b60005b838110156134b85781810151838201526020016134a0565b838111156116f15750506000910152565b600081518084526134e181602086016020860161349d565b601f01601f19169290920160200192915050565b602081526000610d9760208301846134c9565b60006020828403121561351a57600080fd5b5035919050565b6001600160a01b038116811461345b57600080fd5b6000806040838503121561354957600080fd5b823561355481613521565b946020939093013593505050565b60008060006060848603121561357757600080fd5b833561358281613521565b9250602084013561359281613521565b929592945050506040919091013590565b6000602082840312156135b557600080fd5b8135610d9781613521565b801515811461345b57600080fd5b600080604083850312156135e157600080fd5b82356135ec81613521565b915060208301356135fc816135c0565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561363357600080fd5b843561363e81613521565b9350602085013561364e81613521565b925060408501359150606085013567ffffffffffffffff8082111561367257600080fd5b818701915087601f83011261368657600080fd5b81358181111561369857613698613607565b604051601f8201601f19908116603f011681019083821181831017156136c0576136c0613607565b816040528281528a60208487010111156136d957600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561371057600080fd5b823561371b81613521565b915060208301356135fc81613521565b60008060006060848603121561374057600080fd5b8335925060208401359150604084013561375981613521565b809150509250925092565b634e487b7160e01b600052603260045260246000fd5b60208082526006908201526510b7bbb732b960d11b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252600a90820152697a65726f2076616c756560b01b604082015260600190565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b602080825260089082015267185d1d1858da195960c21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156138745761387461384c565b500390565b60208082526006908201526510bb37ba32b960d11b604082015260600190565b600082198211156138ac576138ac61384c565b500190565b60008160001904831182151516156138cb576138cb61384c565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826138f5576138f56138d0565b500490565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061116e908301846134c9565b60006020828403121561393f57600080fd5b8151610d9781613445565b600081600f0b83600f0b600082128260016001607f1b03038213811516156139745761397461384c565b8260016001607f1b03190382128116156139905761399061384c565b50019392505050565b634e487b7160e01b600052602160045260246000fd5b8481526020810184905260808101600584106139db57634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600081600f0b83600f0b80613a0457613a046138d0565b60016001607f1b0319821460001982141615613a2257613a2261384c565b90059392505050565b600081600f0b83600f0b60016001607f1b03600082136000841383830485118282161615613a5b57613a5b61384c565b60016001607f1b03196000851282811687830587121615613a7e57613a7e61384c565b60008712925085820587128484161615613a9a57613a9a61384c565b85850587128184161615613ab057613ab061384c565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b031901831281151615613aeb57613aeb61384c565b8160016001607f1b03018313811615613b0657613b0661384c565b5090039392505050565b600060018201613b2257613b2261384c565b5060010190565b600060208284031215613b3b57600080fd5b8151610d9781613521565b60008083128015600160ff1b850184121615613b6457613b6461384c565b6001600160ff1b0384018313811615613b7f57613b7f61384c565b50500390565b60008351613b9781846020880161349d565b6503a37b5b2b7160d51b9083019081528351613bba81600684016020880161349d565b7f3c2f746578743e3c7465787420783d2231302220793d223135302220636c61736006929091019182015268399e913130b9b2911f60b91b6026820152602f01949350505050565b60008351613c1481846020880161349d565b6903130b630b731b2a7b3160b51b9083019081528351613c3b81600a84016020880161349d565b7f3c2f746578743e3c7465787420783d2231302220793d223233302220636c6173600a929091019182015268399e913130b9b2911f60b91b602a820152603301949350505050565b60008351613c9581846020880161349d565b6a03637b1b5b2b22fb2b732160ad1b9083019081528351613cbd81600b84016020880161349d565b7f3c2f746578743e3c7465787420783d2231302220793d223331302220636c6173600b929091019182015268399e913130b9b2911f60b91b602b820152603401949350505050565b60008351613d1781846020880161349d565b6503b30b63ab2960d51b9083019081528351613d3a81600684016020880161349d565b6c1e17ba32bc3a1f1e17b9bb339f60991b60069290910191820152601301949350505050565b6f7b226e616d65223a20226c6f636b202360801b81528251600090613d8c81601085016020880161349d565b7f222c20226465736372697074696f6e223a2022447973746f706961206c6f636b6010918401918201527f732c2063616e206265207573656420746f20626f6f737420676175676520796960308201527f656c64732c20766f7465206f6e20746f6b656e20656d697373696f6e2c20616e60508201527f64207265636569766520627269626573222c2022696d616765223a202264617460708201527f613a696d6167652f7376672b786d6c3b6261736536342c00000000000000000060908201528351613e618160a784016020880161349d565b61227d60f01b60a7929091019182015260a901949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251613eb481601d85016020870161349d565b91909101601d0192915050565b600060208284031215613ed357600080fd5b8151610d97816135c0565b600082613eed57613eed6138d0565b500690565b60008251613f0481846020870161349d565b919091019291505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f73766722207072657365727665417370656374526174696f3d22784d696e594d696e206d656574222076696577426f783d223020302033353020333530223e3c7374796c653e2e62617365207b2066696c6c3a20626c61636b3b20666f6e742d66616d696c793a20496d706163743b20666f6e742d73697a653a20353070783b207d3c2f7374796c653e3c726563742077696474683d223130302522206865696768743d2231303025222066696c6c3d222361616161666622202f3e3c7465787420783d2231302220793d2236302220636c6173733d2262617365223ea2646970667358221220001e123b68262d2c4c86e513431aa5b208bdad60dcb0c670be75993d14b3c1cb64736f6c634300080d0033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000d8a4054d63fcb0030bc73e2323344ae59a19e92b000000000000000000000000c363f3d4e1c005bf5321040653a088f71bb974ab
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d8a4054d63fcb0030bc73e2323344ae59a19e92b000000000000000000000000c363f3d4e1c005bf5321040653a088f71bb974ab
-----Decoded View---------------
Arg [0] : token_ (address): 0xd8a4054d63fcb0030bc73e2323344ae59a19e92b
Arg [1] : controller_ (address): 0xc363f3d4e1c005bf5321040653a088f71bb974ab
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d8a4054d63fcb0030bc73e2323344ae59a19e92b
Arg [1] : 000000000000000000000000c363f3d4e1c005bf5321040653a088f71bb974ab
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|