Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12871213 | 140 days ago | 0 ETH | ||||
12871184 | 140 days ago | 0 ETH | ||||
12870966 | 140 days ago | 0 ETH | ||||
12870909 | 140 days ago | 0 ETH | ||||
12870907 | 140 days ago | 0 ETH | ||||
12870292 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
VotingEscrowV2Upgradeable
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {IERC721EnumerableUpgradeable, ERC721EnumerableUpgradeable, IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {ERC5725Upgradeable} from "./erc5725/ERC5725Upgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IVotingEscrowV2Upgradeable, IVotes} from "./interfaces/IVotingEscrowV2Upgradeable.sol"; import {IVeArtProxy} from "../../interfaces/IVeArtProxy.sol"; import {SafeCastLibrary} from "./libraries/SafeCastLibrary.sol"; import {EscrowDelegateCheckpoints, Checkpoints} from "./libraries/EscrowDelegateCheckpoints.sol"; import {EscrowDelegateStorage} from "./libraries/EscrowDelegateStorage.sol"; /** * @title VotingEscrow * @dev This contract is used for locking tokens and voting. * * - tokenIds always have a delegatee, with the owner being the default (see createLock) * - On transfers, delegation is reset. (See _update) * - */ contract VotingEscrowV2Upgradeable is Initializable, IVotingEscrowV2Upgradeable, ERC5725Upgradeable, EscrowDelegateStorage, EIP712Upgradeable, ReentrancyGuard { using SafeERC20Upgradeable for IERC20Upgradeable; using SafeCastLibrary for uint256; using EscrowDelegateCheckpoints for EscrowDelegateCheckpoints.EscrowDelegateStore; enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME, MERGE_TYPE, SPLIT_TYPE } /// @notice The token being locked IERC20Upgradeable public _token; /// @notice Total locked supply uint256 public supply; uint8 public constant decimals = 18; address public artProxy; /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice A record of states for signing / validating signatures mapping(address => uint256) public nonces; /// @dev OpenZeppelin v5 IVotes error error VotesExpiredSignature(uint256 expiry); /** * @notice The constructor is disabled for this upgradeable contract. */ constructor() { /// @dev Disable the initializers for implementation contracts to ensure that the contract is not left uninitialized. _disableInitializers(); } /** * @dev Initializes the contract with the given parameters. * @param _name The name to set for the token. * @param _symbol The symbol to set for the token. * @param version The version of the contract. * @param mainToken The main token address that will be locked in the escrow. * @param _artProxy The address of the art proxy contract. */ function initialize( string memory _name, string memory _symbol, string memory version, IERC20Upgradeable mainToken, address _artProxy ) public initializer { __ERC5725_init(_name, _symbol); __EIP712_init(_name, version); _token = mainToken; artProxy = _artProxy; // Reset MAX_TIME in proxy storage MAX_TIME = uint256(uint128(EscrowDelegateCheckpoints.MAX_TIME)); } modifier checkAuthorized(uint256 _tokenId) { address owner = _ownerOf(_tokenId); if (owner == address(0)) { revert ERC721NonexistentToken(_tokenId); } address sender = _msgSender(); if (!_isAuthorized(owner, sender, _tokenId)) { revert ERC721InsufficientApproval(sender, _tokenId); } _; } /// @dev Returns current token URI metadata /// @param _tokenId Token ID to fetch URI for. function tokenURI(uint _tokenId) public view override validToken(_tokenId) returns (string memory) { LockDetails memory _locked = _lockDetails[_tokenId]; return IVeArtProxy(artProxy)._tokenURI( _tokenId, balanceOfNFT(_tokenId), _locked.endTime, uint(int256(_locked.amount)) ); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC5725Upgradeable, IERC165Upgradeable) returns (bool supported) { return interfaceId == type(IVotingEscrowV2Upgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-_beforeTokenTransfer}. * Clears the approval of a given `tokenId` when the token is transferred or burned. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); for (uint256 i = 0; i < batchSize; i++) { uint256 tokenId = firstTokenId + i; if (from != to) { /// @dev Sets delegatee to new owner on transfers (address oldDelegatee, address newDelegatee) = edStore.delegate( tokenId, to, _lockDetails[tokenId].endTime ); emit DelegateChanged(to, oldDelegatee, newDelegatee); emit LockDelegateChanged(tokenId, to, oldDelegatee, newDelegatee); } } } /** * ERC-5725 and token-locking logic */ /// @notice maps the vesting data with tokenIds mapping(uint256 => LockDetails) public _lockDetails; /// @notice tracker of current NFT id uint256 public totalNftsMinted = 0; /** * @notice Creates a new vesting NFT and mints it * @dev Token amount should be approved to be transferred by this contract before executing create * @param value The total assets to be locked over time * @param duration Duration in seconds of the lock * @param to The receiver of the lock */ function _createLock( uint256 value, uint256 duration, address to, address delegatee, bool permanent, DepositType depositType ) internal virtual returns (uint256) { if (value == 0) revert ZeroAmount(); uint256 unlockTime; totalNftsMinted++; uint256 newTokenId = totalNftsMinted; if (!permanent) { unlockTime = toGlobalClock(block.timestamp + duration); // Locktime is rounded down to global clock (days) if (unlockTime <= block.timestamp) revert LockDurationNotInFuture(); if (unlockTime > block.timestamp + MAX_TIME) revert LockDurationTooLong(); } _safeMint(to, newTokenId); _lockDetails[newTokenId].startTime = block.timestamp; /// @dev Checkpoint created in _updateLock _updateLock(newTokenId, value, unlockTime, _lockDetails[newTokenId], permanent, depositType); edStore.delegate(newTokenId, delegatee, unlockTime); emit LockCreated(newTokenId, delegatee, value, unlockTime, permanent); emit DelegateChanged(to, address(0), delegatee); emit LockDelegateChanged(newTokenId, to, address(0), delegatee); return newTokenId; } /** * @notice Creates a lock for the sender * @param _value The total assets to be locked over time * @param _lockDuration Duration in seconds of the lock * @param _permanent Whether the lock is permanent or not * @return The id of the newly created token */ function createLock( uint256 _value, uint256 _lockDuration, bool _permanent ) external nonReentrant returns (uint256) { return _createLock(_value, _lockDuration, _msgSender(), _msgSender(), _permanent, DepositType.CREATE_LOCK_TYPE); } /** * @notice Creates a lock for a specified address * @param _value The total assets to be locked over time * @param _lockDuration Duration in seconds of the lock * @param _to The receiver of the lock * @param _permanent Whether the lock is permanent or not * @return The id of the newly created token */ function createLockFor( uint256 _value, uint256 _lockDuration, address _to, bool _permanent ) external nonReentrant returns (uint256) { return _createLock(_value, _lockDuration, _to, _to, _permanent, DepositType.CREATE_LOCK_TYPE); } /** * @notice Creates a lock for a specified address * @param _value The total assets to be locked over time * @param _lockDuration Duration in seconds of the lock * @param _to The receiver of the lock * @param _delegatee The receiver of the lock * @param _permanent Whether the lock is permanent or not * @return The id of the newly created token */ function createDelegatedLockFor( uint256 _value, uint256 _lockDuration, address _to, address _delegatee, bool _permanent ) external nonReentrant returns (uint256) { return _createLock(_value, _lockDuration, _to, _delegatee, _permanent, DepositType.CREATE_LOCK_TYPE); } /** * @notice Updates the global checkpoint */ function globalCheckpoint() public nonReentrant { return edStore.globalCheckpoint(); } function checkpoint() external override { globalCheckpoint(); } /** * @notice Updates the checkpoint for a delegatee * @param _delegateeAddress The address of the delegatee */ function checkpointDelegatee(address _delegateeAddress) external nonReentrant { edStore.baseCheckpointDelegatee(_delegateeAddress); } /// @notice Deposit & update lock tokens for a user /// @dev The supply is increased by the _value amount /// @param _tokenId NFT that holds lock /// @param _increasedValue Amount to deposit /// @param _unlockTime New time when to unlock the tokens, or 0 if unchanged /// @param _oldLocked Previous locked amount / timestamp function _updateLock( uint256 _tokenId, uint256 _increasedValue, uint256 _unlockTime, LockDetails memory _oldLocked, bool isPermanent, DepositType depositType ) internal { uint256 supplyBefore = supply; supply += _increasedValue; // Set newLocked to _oldLocked without mangling memory LockDetails memory newLocked; (newLocked.amount, newLocked.startTime, newLocked.endTime, newLocked.isPermanent) = ( _oldLocked.amount, _oldLocked.startTime, _oldLocked.endTime, _oldLocked.isPermanent ); // Adding to existing lock, or if a lock is expired - creating a new one newLocked.amount += _increasedValue; if (_unlockTime != 0 && !isPermanent) { newLocked.endTime = _unlockTime; } if (isPermanent) { newLocked.endTime = 0; newLocked.isPermanent = true; } _lockDetails[_tokenId] = newLocked; emit LockUpdated(_tokenId, _increasedValue, _unlockTime, isPermanent); // Possibilities: // Both _oldLocked.end could be current or expired (>/< block.timestamp) // or if the lock is a permanent lock, then _oldLocked.end == 0 // value == 0 (extend lock) or value > 0 (add to lock or extend lock) // newLocked.end > block.timestamp (always) _checkpointLock(_tokenId, _oldLocked, newLocked); if (_increasedValue != 0 && depositType != DepositType.SPLIT_TYPE) { _token.safeTransferFrom(_msgSender(), address(this), _increasedValue); } emit SupplyUpdated(supply, supplyBefore + _increasedValue); } /// @notice Record global and per-user data to checkpoints. Used by VotingEscrow system. /// @param _tokenId NFT token ID. No user checkpoint if 0 /// @param _oldLocked Previous locked amount / end lock time for the user /// @param _newLocked New locked amount / end lock time for the user function _checkpointLock( uint256 _tokenId, IVotingEscrowV2Upgradeable.LockDetails memory _oldLocked, IVotingEscrowV2Upgradeable.LockDetails memory _newLocked ) internal { edStore.checkpoint( _tokenId, _oldLocked.amount.toInt128(), _newLocked.amount.toInt128(), _oldLocked.endTime, _newLocked.endTime ); } /// @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 increaseAmount(uint256 _tokenId, uint256 _value) external nonReentrant { if (_value == 0) revert ZeroAmount(); IVotingEscrowV2Upgradeable.LockDetails memory oldLocked = _lockDetails[_tokenId]; if (_ownerOf(_tokenId) == address(0)) revert NoLockFound(); if (oldLocked.endTime <= block.timestamp && !oldLocked.isPermanent) revert LockExpired(); _updateLock(_tokenId, _value, 0, oldLocked, oldLocked.isPermanent, DepositType.INCREASE_LOCK_AMOUNT); } /** * @notice Increases the unlock time of a lock * @param _tokenId The id of the token to increase the unlock time for * @param _lockDuration The new duration of the lock * @param _permanent Whether the lock is permanent or not */ function increaseUnlockTime( uint256 _tokenId, uint256 _lockDuration, bool _permanent ) external nonReentrant checkAuthorized(_tokenId) { LockDetails memory oldLocked = _lockDetails[_tokenId]; if (oldLocked.isPermanent) revert PermanentLock(); uint256 unlockTime; if (!_permanent) { unlockTime = toGlobalClock(block.timestamp + _lockDuration); // Locktime is rounded down to global clock (days) if (oldLocked.endTime <= block.timestamp) revert LockExpired(); if (unlockTime <= oldLocked.endTime) revert LockDurationNotInFuture(); if (unlockTime > block.timestamp + MAX_TIME) revert LockDurationTooLong(); } _updateLock(_tokenId, 0, unlockTime, oldLocked, _permanent, DepositType.INCREASE_UNLOCK_TIME); emit LockDurationExtended(_tokenId, unlockTime, _permanent); } /** * @notice Unlocks a permanent lock * @param _tokenId The id of the token to unlock */ function unlockPermanent(uint256 _tokenId) external nonReentrant checkAuthorized(_tokenId) { LockDetails memory newLocked = _lockDetails[_tokenId]; if (!newLocked.isPermanent) revert NotPermanentLock(); // Set the end time to the maximum possible time newLocked.endTime = toGlobalClock(block.timestamp + MAX_TIME); // Set the lock to not be permanent newLocked.isPermanent = false; // Update the lock details _checkpointLock(_tokenId, _lockDetails[_tokenId], newLocked); _lockDetails[_tokenId] = newLocked; emit UnlockPermanent(_tokenId, _msgSender(), newLocked.endTime); } /** * @notice Claims the payout for a token * @param _tokenId The id of the token to claim the payout for */ function _claim(uint256 _tokenId) internal validToken(_tokenId) nonReentrant checkAuthorized(_tokenId) { IVotingEscrowV2Upgradeable.LockDetails memory oldLocked = _lockDetails[_tokenId]; if (oldLocked.isPermanent) revert PermanentLock(); uint256 amountClaimed = claimablePayout(_tokenId); if (amountClaimed == 0) revert LockNotExpired(); // Reset the lock details _lockDetails[_tokenId] = IVotingEscrowV2Upgradeable.LockDetails(0, 0, 0, false); // Update the total supply uint256 supplyBefore = supply; supply -= amountClaimed; // Update the lock details _checkpointLock(_tokenId, oldLocked, _lockDetails[_tokenId]); /// @notice ERC-5725 event emit PayoutClaimed(_tokenId, msg.sender, amountClaimed); // IERC5725 - Update the total amount claimed _payoutClaimed[_tokenId] += amountClaimed; // Transfer the claimed amount to the sender IERC20Upgradeable(_payoutToken(_tokenId)).safeTransfer(msg.sender, amountClaimed); emit SupplyUpdated(supplyBefore, supply); } /** * @notice Claims the payout for a token * @param _tokenId The id of the token to claim the payout for */ function claim(uint256 _tokenId) external override(ERC5725Upgradeable) { _claim(_tokenId); } /** * @notice Merges two tokens together * @param _from The id of the token to merge from * @param _to The id of the token to merge to */ function merge(uint256 _from, uint256 _to) external nonReentrant checkAuthorized(_from) checkAuthorized(_to) { if (_from == _to) revert SameNFT(); IVotingEscrowV2Upgradeable.LockDetails memory oldLockedTo = _lockDetails[_to]; if (oldLockedTo.amount == 0) revert ZeroAmount(); if (oldLockedTo.endTime <= block.timestamp && !oldLockedTo.isPermanent) revert LockExpired(); IVotingEscrowV2Upgradeable.LockDetails memory oldLockedFrom = _lockDetails[_from]; if (oldLockedFrom.amount == 0) revert ZeroAmount(); if (oldLockedFrom.isPermanent == true && oldLockedFrom.isPermanent != oldLockedTo.isPermanent) revert PermanentLockMismatch(); // Calculate the new end time uint256 end = oldLockedFrom.endTime >= oldLockedTo.endTime ? oldLockedFrom.endTime : oldLockedTo.endTime; // Set lock amount to 0 _lockDetails[_from].amount = 0; // Update the lock details _checkpointLock(_from, oldLockedFrom, _lockDetails[_from]); // Calculate the new lock details LockDetails memory newLockedTo; newLockedTo.amount = oldLockedTo.amount + oldLockedFrom.amount; newLockedTo.isPermanent = oldLockedTo.isPermanent; if (!newLockedTo.isPermanent) { newLockedTo.endTime = end; } // Update the lock details _checkpointLock(_to, oldLockedTo, newLockedTo); _lockDetails[_to] = newLockedTo; emit LockMerged(_from, _to, newLockedTo.amount, end, newLockedTo.isPermanent); } /** * @notice Splits a token into multiple tokens * @param _weights The percentages to split the token into * @param _tokenId The id of the token to split */ function split(uint256[] memory _weights, uint256 _tokenId) external nonReentrant checkAuthorized(_tokenId) { LockDetails memory locked = _lockDetails[_tokenId]; LockDetails storage lockedStorage = _lockDetails[_tokenId]; uint256 currentTime = block.timestamp; /// @dev Pulling directly from locked struct to avoid stack-too-deep if (locked.endTime <= currentTime && !locked.isPermanent) revert LockExpired(); if (locked.amount == 0 || _weights.length < 2) revert ZeroAmount(); // reset supply, _deposit_for increase it supply -= uint256(int256(locked.amount)); // Capture owner for split address owner = _ownerOf(_tokenId); uint256 totalWeight = 0; for (uint256 i = 0; i < _weights.length; i++) { totalWeight += _weights[i]; } if (totalWeight == 0) revert InvalidWeights(); uint256 duration = locked.isPermanent ? 0 : locked.endTime > currentTime ? locked.endTime - currentTime : 0; uint256 amountLeftToSplit = locked.amount; for (uint256 i = 0; i < _weights.length; i++) { uint256 value = (uint256(int256(locked.amount)) * _weights[i]) / totalWeight; if(i == _weights.length - 1) { /// @dev Ensure no rounding errors occur by passing the remainder to the last split value = amountLeftToSplit; } amountLeftToSplit -= value; if (i == 0) { lockedStorage.amount = value; supply += value; _checkpointLock(_tokenId, locked, lockedStorage); } else { _createLock(value, duration, owner, owner, locked.isPermanent, DepositType.SPLIT_TYPE); } } emit LockSplit(_weights, _tokenId); } /** * @notice Burns a token * @param _tokenId The ids of the tokens to burn */ function burn(uint256 _tokenId) external { if (_ownerOf(_tokenId) != _msgSender()) revert NotLockOwner(); if(_lockDetails[_tokenId].amount > 0) revert LockHoldsValue(); _burn(_tokenId); } /*/////////////////////////////////////////////////////////////// GAUGE REWARDS LOGIC //////////////////////////////////////////////////////////////*/ function balanceOfNFT(uint256 _tokenId) public view returns (uint256) { return edStore.getAdjustedEscrowBias(_tokenId, block.timestamp); } function balanceOfNFTAt(uint256 _tokenId, uint256 _timestamp) external view returns (uint256) { return edStore.getAdjustedEscrowBias(_tokenId, _timestamp); } function getPastEscrowPoint( uint256 _tokenId, uint256 _timestamp ) external view override returns (Checkpoints.Point memory, uint48) { return edStore.getAdjustedEscrow(_tokenId, _timestamp); } function getFirstEscrowPoint(uint256 _tokenId) external view override returns (Checkpoints.Point memory, uint48) { return edStore.getFirstEscrowPoint(_tokenId); } function totalSupply() public view override(ERC721EnumerableUpgradeable, IERC721EnumerableUpgradeable) returns (uint256) { return edStore.getAdjustedGlobalVotes(block.timestamp.toUint48()); } /*/////////////////////////////////////////////////////////////// @dev See {IVotes}. //////////////////////////////////////////////////////////////*/ /** * @notice Gets the votes for a delegatee * @param account The address of the delegatee * @return The number of votes the delegatee has */ function getVotes(address account) external view override(IVotes) returns (uint256) { return edStore.getAdjustedVotes(account, block.timestamp.toUint48()); } /** * @notice Gets the past votes for a delegatee at a specific time point * @param account The address of the delegatee * @param timepoint The time point to get the votes at * @return The number of votes the delegatee had at the time point */ function getPastVotes(address account, uint256 timepoint) external view override(IVotes) returns (uint256) { return edStore.getAdjustedVotes(account, timepoint.toUint48()); } /** * @notice Gets the total supply at a specific time point * @param _timePoint The time point to get the total supply at * @return The total supply at the time point */ function getPastTotalSupply(uint256 _timePoint) external view override(IVotes) returns (uint256) { return edStore.getAdjustedGlobalVotes(_timePoint.toUint48()); } /** * @notice Delegates votes to a delegatee * @param delegatee The account to delegate votes to */ function delegate(address delegatee) external override(IVotes) { _delegate(_msgSender(), delegatee); } /** * @notice Gets the delegate of a delegatee * @dev This function implements IVotes interface. * An account can have multiple delegates in this contract. If multiple * different delegates are found, this function returns address(1) to * indicate that there is not a single unique delegate. * @param account The delegatee to get the delegate of * @return The delegate of the delegatee, or address(1) if multiple different delegates are found */ function delegates(address account) external view override(IVotes) returns (address) { address delegatee = address(0); uint256 balance = balanceOf(account); /// @dev out-of-gas protection uint256 runs = 50 > balance ? balance : 50; for (uint256 i = 0; i < runs; i++) { uint256 tokenId = tokenOfOwnerByIndex(account, i); address currentDelegatee = edStore.getEscrowDelegatee(tokenId); /// @dev Hacky way to check if the delegatee is the same for all locks if (delegatee == address(0)) { delegatee = currentDelegatee; } else if (delegatee != currentDelegatee) { return address(1); } } return delegatee; } /** * @notice Delegates votes from a specific lock to a delegatee * @param _tokenId The ID of the lock token delegating the votes * @param delegatee The address to which the votes are being delegated */ function delegate(uint256 _tokenId, address delegatee) external checkAuthorized(_tokenId) { (address fromDelegatee, address toDelegatee) = edStore.delegate( _tokenId, delegatee, _lockDetails[_tokenId].endTime ); emit LockDelegateChanged(_tokenId, _msgSender(), fromDelegatee, toDelegatee); } /** * @notice Gets the delegatee of a given lock * @param tokenId The ID of the lock token * @return The address of the delegatee for the specified token */ function getLockDelegatee(uint256 tokenId) external view returns (address) { return edStore.getEscrowDelegatee(tokenId); } /** * @notice Gets all delegates of a delegatee * @param account The delegatee to get the delegates of * @return An array of all delegates of the delegatee */ function getAccountDelegates(address account) external view returns (address[] memory) { uint256 balance = balanceOf(account); address[] memory allDelegates = new address[](balance); for (uint256 i = 0; i < balance; i++) { uint256 tokenId = tokenOfOwnerByIndex(account, i); allDelegates[i] = edStore.getEscrowDelegatee(tokenId); } return allDelegates; } /** * @notice Public function to get the delegatee of a lock * @param tokenId The ID of the token * @param timestamp The timestamp to get the delegate at * @return The address of the delegate */ function delegates(uint256 tokenId, uint48 timestamp) external view returns (address) { return edStore.getEscrowDelegateeAtTime(tokenId, timestamp); } /** * @notice Delegates votes by signature * @param delegatee The delegatee to delegate votes to * @param nonce The nonce for the signature * @param expiry The expiry time for the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external override(IVotes) { // Removed for gas considerations. The code below uncommented adds 1.289 kbs to the contract size. revert("delegateBySig: size cut"); /* if (delegatee == msg.sender || delegatee == address(0)) revert InvalidDelegatee(); bytes32 domainSeparator = _domainSeparatorV4(); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ECDSA.recover(digest, v, r, s); if (signatory == address(0)) revert InvalidSignature(); if (nonce != nonces[signatory]++) revert InvalidNonce(); if (block.timestamp > expiry) revert VotesExpiredSignature(expiry); return _delegate(signatory, delegatee); */ } /** * @notice Delegates votes from an owner to an delegatee * @param delegator The owner of the tokenId delegating votes * @param delegatee The account to delegate votes to */ function _delegate(address delegator, address delegatee) internal nonReentrant { uint256 balance = balanceOf(delegator); address fromDelegate = address(0); for (uint256 i = 0; i < balance; i++) { uint256 tokenId = tokenOfOwnerByIndex(delegator, i); (address oldDelegate, address newDelegate) = edStore.delegate( tokenId, delegatee, _lockDetails[tokenId].endTime ); emit LockDelegateChanged(tokenId, delegator, oldDelegate, newDelegate); /// @dev Hacky way to check if the delegatee is the same for all locks if (fromDelegate == address(0)) { fromDelegate = oldDelegate; } else if (fromDelegate != address(1)) { if (fromDelegate != oldDelegate) { fromDelegate = address(1); } } } emit DelegateChanged(delegator, fromDelegate, delegatee); } /*/////////////////////////////////////////////////////////////// @dev See {IERC5725}. //////////////////////////////////////////////////////////////*/ /** * @dev See {ERC5725Upgradeable}. */ function vestedPayoutAtTime( uint256 tokenId, uint256 timestamp ) public view override(ERC5725Upgradeable) validToken(tokenId) returns (uint256 payout) { if (timestamp >= _endTime(tokenId)) { return _payout(tokenId); } return 0; } /** * @dev See {ERC5725Upgradeable}. */ function _payoutToken(uint256 /*tokenId*/) internal view override returns (address) { return address(_token); } /** * @dev See {ERC5725Upgradeable}. */ function _payout(uint256 tokenId) internal view override returns (uint256) { return _lockDetails[tokenId].amount; } /** * @dev See {ERC5725Upgradeable}. */ function _startTime(uint256 tokenId) internal view override returns (uint256) { return _lockDetails[tokenId].startTime; } /** * @dev See {ERC5725Upgradeable}. */ function _endTime(uint256 tokenId) internal view override returns (uint256) { return _lockDetails[tokenId].endTime; } function token() external view returns (IERC20Upgradeable) { return _token; } function lockDetails(uint256 _tokenId) external view returns (LockDetails memory) { return _lockDetails[_tokenId]; } function isApprovedOrOwner(address user, uint tokenId) external view returns (bool) { return _isAuthorized(ownerOf(tokenId), user, tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267Upgradeable { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721Upgradeable.sol"; import "./IERC721ReceiverUpgradeable.sol"; import "./extensions/IERC721MetadataUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../utils/StringsUpgradeable.sol"; import "../../utils/introspection/ERC165Upgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable { using AddressUpgradeable for address; using StringsUpgradeable for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC721_init_unchained(name_, symbol_); } function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { return interfaceId == type(IERC721Upgradeable).interfaceId || interfaceId == type(IERC721MetadataUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721Upgradeable.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @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. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721Upgradeable.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721Upgradeable.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721Upgradeable.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721ReceiverUpgradeable.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[44] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721Upgradeable.sol"; import "./IERC721EnumerableUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721EnumerableUpgradeable is Initializable, ERC721Upgradeable, IERC721EnumerableUpgradeable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; function __ERC721Enumerable_init() internal onlyInitializing { } function __ERC721Enumerable_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, ERC721Upgradeable) returns (bool) { return interfaceId == type(IERC721EnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721Upgradeable.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721EnumerableUpgradeable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev See {ERC721-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); if (batchSize > 1) { // Will only trigger during construction. Batch transferring (minting) is not available afterwards. revert("ERC721Enumerable: consecutive transfers not supported"); } uint256 tokenId = firstTokenId; if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721Upgradeable.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721Upgradeable.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[46] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721EnumerableUpgradeable is IERC721Upgradeable { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721MetadataUpgradeable is IERC721Upgradeable { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSAUpgradeable.sol"; import "../../interfaces/IERC5267Upgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:oz-renamed-from _HASHED_NAME bytes32 private _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 private _hashedVersion; string private _name; string private _version; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { _name = name; _version = version; // Reset prior values in storage if upgrading _hashedName = 0; _hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal virtual view returns (string memory) { return _name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal virtual view returns (string memory) { return _version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = _hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = _hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @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.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (governance/utils/IVotes.sol) pragma solidity ^0.8.0; /** * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. * * _Available since v4.5._ */ interface IVotes { /** * @dev Emitted when an account changes their delegate. */ event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /** * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. */ event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); /** * @dev Returns the current amount of votes that `account` has. */ function getVotes(address account) external view returns (uint256); /** * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. */ function getPastVotes(address account, uint256 timepoint) external view returns (uint256); /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ function getPastTotalSupply(uint256 timepoint) external view returns (uint256); /** * @dev Returns the delegate that `account` has chosen. */ function delegates(address account) external view returns (address); /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(address delegatee) external; /** * @dev Delegates votes from signer to `delegatee`. */ function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; interface IVeArtProxy { function _tokenURI(uint _tokenId, uint _balanceOf, uint _locked_end, uint _value) external pure returns (string memory output); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.13; import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; /// @dev Official ERC-5725 interface import {IERC5725Upgradeable, IERC165Upgradeable} from "./IERC5725Upgradeable.sol"; import {IERC721Errors} from "../interfaces/IERC721Errors.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; abstract contract ERC5725Upgradeable is Initializable, IERC5725Upgradeable, ERC721EnumerableUpgradeable, IERC721Errors { using SafeERC20Upgradeable for IERC20Upgradeable; /// @dev mapping for claimed payouts mapping(uint256 => uint256) /*tokenId*/ /*claimed*/ internal _payoutClaimed; /// @dev Mapping from token ID to approved tokenId operator mapping(uint256 => address) private _tokenIdApprovals; /// @dev Mapping from owner to operator approvals mapping(address => mapping(address => bool)) /* owner */ /*(operator, isApproved)*/ internal _operatorApprovals; /// @dev Reserved storage space to allow for layout changes in the future. uint256[50] private __gap; constructor() { /// @dev Disable the initializers for implementation contracts to ensure that the contract is not left uninitialized. _disableInitializers(); } function __ERC5725_init(string memory name_, string memory symbol_) internal initializer { __ERC721_init(name_, symbol_); /// @dev Currently this call does nothing, but it is left here for future compatibility. __ERC721Enumerable_init(); } /** * @notice Checks if the tokenId exists and its valid * @param tokenId The NFT token id */ modifier validToken(uint256 tokenId) { address owner = _ownerOf(tokenId); if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } _; } /** * @dev See {IERC5725Upgradeable}. */ function claim(uint256 tokenId) external virtual override(IERC5725Upgradeable); /** * @dev See {IERC5725Upgradeable}. */ function setClaimApprovalForAll(address operator, bool approved) external override(IERC5725Upgradeable) { _setClaimApprovalForAll(operator, approved); emit ClaimApprovalForAll(msg.sender, operator, approved); } /** * @dev See {IERC5725Upgradeable}. */ function setClaimApproval( address operator, bool approved, uint256 tokenId ) external override(IERC5725Upgradeable) validToken(tokenId) { _setClaimApproval(operator, tokenId); emit ClaimApproval(msg.sender, operator, tokenId, approved); } /** * @dev See {IERC5725Upgradeable}. */ function vestedPayout(uint256 tokenId) public view override(IERC5725Upgradeable) returns (uint256 payout) { return vestedPayoutAtTime(tokenId, block.timestamp); } /** * @dev See {IERC5725Upgradeable}. */ function vestedPayoutAtTime( uint256 tokenId, uint256 timestamp ) public view virtual override(IERC5725Upgradeable) returns (uint256 payout); /** * @dev See {IERC5725Upgradeable}. */ function vestingPayout( uint256 tokenId ) public view override(IERC5725Upgradeable) validToken(tokenId) returns (uint256 payout) { return _payout(tokenId) - vestedPayout(tokenId); } /** * @dev See {IERC5725Upgradeable}. */ function claimablePayout( uint256 tokenId ) public view override(IERC5725Upgradeable) validToken(tokenId) returns (uint256 payout) { return vestedPayout(tokenId) - _payoutClaimed[tokenId]; } /** * @dev See {IERC5725Upgradeable}. */ function claimedPayout( uint256 tokenId ) public view override(IERC5725Upgradeable) validToken(tokenId) returns (uint256 payout) { return _payoutClaimed[tokenId]; } /** * @dev See {IERC5725Upgradeable}. */ function vestingPeriod( uint256 tokenId ) public view override(IERC5725Upgradeable) validToken(tokenId) returns (uint256 vestingStart, uint256 vestingEnd) { return (_startTime(tokenId), _endTime(tokenId)); } /** * @dev See {IERC5725Upgradeable}. */ function payoutToken(uint256 tokenId) public view override(IERC5725Upgradeable) validToken(tokenId) returns (address token) { return _payoutToken(tokenId); } /** * @dev See {IERC165-supportsInterface}. * IERC5725Upgradeable interfaceId = 0xbd3a202b */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC721EnumerableUpgradeable, IERC165Upgradeable) returns (bool supported) { return interfaceId == type(IERC5725Upgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC5725Upgradeable}. */ function getClaimApproved(uint256 tokenId) public view returns (address operator) { return _tokenIdApprovals[tokenId]; } /** * @dev Returns true if `owner` has set `operator` to manage all `tokenId`s. * @param owner The owner allowing `operator` to manage all `tokenId`s. * @param operator The address who is given permission to spend tokens on behalf of the `owner`. */ function isClaimApprovedForAll(address owner, address operator) public view returns (bool isClaimApproved) { return _operatorApprovals[owner][operator]; } /** * @dev Public view which returns true if the operator has permission to claim for `tokenId` * @notice To remove permissions, set operator to zero address. * * @param operator The address that has permission for a `tokenId`. * @param tokenId The NFT `tokenId`. */ function isApprovedClaimOrOwner(address operator, uint256 tokenId) public view virtual returns (bool) { address owner = ownerOf(tokenId); return (operator == owner || isClaimApprovedForAll(owner, operator) || getClaimApproved(tokenId) == operator); } /** * @dev Internal function to set the operator status for a given owner to manage all `tokenId`s. * @notice To remove permissions, set approved to false. * * @param operator The address who is given permission to spend vested tokens. * @param approved The approved status. */ function _setClaimApprovalForAll(address operator, bool approved) internal virtual { _operatorApprovals[msg.sender][operator] = approved; } /** * @dev Internal function to set the operator status for a given tokenId. * @notice To remove permissions, set operator to zero address. * * @param operator The address who is given permission to spend vested tokens. * @param tokenId The NFT `tokenId`. */ function _setClaimApproval(address operator, uint256 tokenId) internal virtual { if (ownerOf(tokenId) != msg.sender) revert ERC721IncorrectOwner(msg.sender, tokenId, ownerOf(tokenId)); _tokenIdApprovals[tokenId] = operator; } /** * @dev See {IERC721-_beforeTokenTransfer}. * Clears the approval of a given `tokenId` when the token is transferred or burned. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); for (uint256 i = 0; i < batchSize; i++) { uint256 tokenId = firstTokenId + i; if (from != address(0) || from != to) { delete _tokenIdApprovals[tokenId]; } } } /** * @dev Internal function to get the payout token of a given vesting NFT * * @param tokenId on which to check the payout token address * @return address payout token address */ function _payoutToken(uint256 tokenId) internal view virtual returns (address); /** * @dev Internal function to get the total payout of a given vesting NFT. * @dev This is the total that will be paid out to the NFT owner, including historical tokens. * * @param tokenId to check * @return uint256 the total payout of a given vesting NFT */ function _payout(uint256 tokenId) internal view virtual returns (uint256); /** * @dev Internal function to get the start time of a given vesting NFT * * @param tokenId to check * @return uint256 the start time in epoch timestamp */ function _startTime(uint256 tokenId) internal view virtual returns (uint256); /** * @dev Internal function to get the end time of a given vesting NFT * * @param tokenId to check * @return uint256 the end time in epoch timestamp */ function _endTime(uint256 tokenId) internal view virtual returns (uint256); /** * @dev Checks if an address is authorized to manage the given token ID. * Used to verify if an address has the necessary permissions to execute actions on behalf of the token owner. * * @param owner the owner of the token * @param spender the address attempting to act on the token * @param tokenId the token ID to check for authorization * @return bool true if the spender is authorized, false otherwise */ function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { return spender != address(0) && (owner == spender || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; /** * @title Non-Fungible Vesting Token Standard. * @notice A non-fungible token standard used to vest ERC-20 tokens over a vesting release curve * scheduled using timestamps. * @dev Because this standard relies on timestamps for the vesting schedule, it's important to keep track of the * tokens claimed per Vesting NFT so that a user cannot withdraw more tokens than allotted for a specific Vesting NFT. * @custom:interface-id 0xbd3a202b */ interface IERC5725Upgradeable is IERC721Upgradeable { /** * This event is emitted when the payout is claimed through the claim function. * @param tokenId the NFT tokenId of the assets being claimed. * @param recipient The address which is receiving the payout. * @param claimAmount The amount of tokens being claimed. */ event PayoutClaimed(uint256 indexed tokenId, address indexed recipient, uint256 claimAmount); /** * This event is emitted when an `owner` sets an address to manage token claims for all tokens. * @param owner The address setting a manager to manage all tokens. * @param spender The address being permitted to manage all tokens. * @param approved A boolean indicating whether the spender is approved to claim for all tokens. */ event ClaimApprovalForAll(address indexed owner, address indexed spender, bool approved); /** * This event is emitted when an `owner` sets an address to manage token claims for a `tokenId`. * @param owner The `owner` of `tokenId`. * @param spender The address being permitted to manage a tokenId. * @param tokenId The unique identifier of the token being managed. * @param approved A boolean indicating whether the spender is approved to claim for `tokenId`. */ event ClaimApproval(address indexed owner, address indexed spender, uint256 indexed tokenId, bool approved); /** * @notice Claim the pending payout for the NFT. * @dev MUST grant the claimablePayout value at the time of claim being called to `msg.sender`. * MUST revert if not called by the token owner or approved users. * MUST emit PayoutClaimed. * SHOULD revert if there is nothing to claim. * @param tokenId The NFT token id. */ function claim(uint256 tokenId) external; /** * @notice Number of tokens for the NFT which have been claimed at the current timestamp. * @param tokenId The NFT token id. * @return payout The total amount of payout tokens claimed for this NFT. */ function claimedPayout(uint256 tokenId) external view returns (uint256 payout); /** * @notice Number of tokens for the NFT which can be claimed at the current timestamp. * @dev It is RECOMMENDED that this is calculated as the `vestedPayout()` subtracted from `payoutClaimed()`. * @param tokenId The NFT token id. * @return payout The amount of unlocked payout tokens for the NFT which have not yet been claimed. */ function claimablePayout(uint256 tokenId) external view returns (uint256 payout); /** * @notice Total amount of tokens which have been vested at the current timestamp. * This number also includes vested tokens which have been claimed. * @dev It is RECOMMENDED that this function calls `vestedPayoutAtTime` * with `block.timestamp` as the `timestamp` parameter. * @param tokenId The NFT token id. * @return payout Total amount of tokens which have been vested at the current timestamp. */ function vestedPayout(uint256 tokenId) external view returns (uint256 payout); /** * @notice Total amount of vested tokens at the provided timestamp. * This number also includes vested tokens which have been claimed. * @dev `timestamp` MAY be both in the future and in the past. * Zero MUST be returned if the timestamp is before the token was minted. * @param tokenId The NFT token id. * @param timestamp The timestamp to check on, can be both in the past and the future. * @return payout Total amount of tokens which have been vested at the provided timestamp. */ function vestedPayoutAtTime(uint256 tokenId, uint256 timestamp) external view returns (uint256 payout); /** * @notice Number of tokens for an NFT which are currently vesting. * @dev The sum of vestedPayout and vestingPayout SHOULD always be the total payout. * @param tokenId The NFT token id. * @return payout The number of tokens for the NFT which are vesting until a future date. */ function vestingPayout(uint256 tokenId) external view returns (uint256 payout); /** * @notice The start and end timestamps for the vesting of the provided NFT. * MUST return the timestamp where no further increase in vestedPayout occurs for `vestingEnd`. * @param tokenId The NFT token id. * @return vestingStart The beginning of the vesting as a unix timestamp. * @return vestingEnd The ending of the vesting as a unix timestamp. */ function vestingPeriod(uint256 tokenId) external view returns (uint256 vestingStart, uint256 vestingEnd); /** * @notice Token which is used to pay out the vesting claims. * @param tokenId The NFT token id. * @return token The token which is used to pay out the vesting claims. */ function payoutToken(uint256 tokenId) external view returns (address token); /** * @notice Sets a global `operator` with permission to manage all tokens owned by the current `msg.sender`. * @param operator The address to let manage all tokens. * @param approved A boolean indicating whether the spender is approved to claim for all tokens. */ function setClaimApprovalForAll(address operator, bool approved) external; /** * @notice Sets a tokenId `operator` with permission to manage a single `tokenId` owned by the `msg.sender`. * @param operator The address to let manage a single `tokenId`. * @param tokenId the `tokenId` to be managed. * @param approved A boolean indicating whether the spender is approved to claim for all tokens. */ function setClaimApproval(address operator, bool approved, uint256 tokenId) external; /** * @notice Returns true if `owner` has set `operator` to manage all `tokenId`s. * @param owner The owner allowing `operator` to manage all `tokenId`s. * @param operator The address who is given permission to spend tokens on behalf of the `owner`. */ function isClaimApprovedForAll(address owner, address operator) external view returns (bool isClaimApproved); /** * @notice Returns the operating address for a `tokenId`. * If `tokenId` is not managed, then returns the zero address. * @param tokenId The NFT `tokenId` to query for a `tokenId` manager. */ function getClaimApproved(uint256 tokenId) external view returns (address operator); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Standard ERC-721 Errors * @notice This update is included in openzeppelin/[email protected], but not in openzeppelin/[email protected] * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. * @custom:source https://github.com/OpenZeppelin/openzeppelin-contracts/blob/... * 0b343abcb5cecc42c40b95565cb7f5affb542727/contracts/interfaces/draft-IERC6093.sol#L55 */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; import {Checkpoints} from "../libraries/Checkpoints.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {IERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721EnumerableUpgradeable.sol"; interface IVotingEscrowV2Upgradeable is IVotes, IERC721EnumerableUpgradeable { struct LockDetails { uint256 amount; /// @dev amount of tokens locked uint256 startTime; /// @dev when locking started uint256 endTime; /// @dev when locking ends bool isPermanent; /// @dev if its a permanent lock } /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- event SupplyUpdated(uint256 oldSupply, uint256 newSupply); /// @notice Lock events event LockCreated(uint256 indexed tokenId, address indexed to, uint256 value, uint256 unlockTime, bool isPermanent); event LockUpdated(uint256 indexed tokenId, uint256 value, uint256 unlockTime, bool isPermanent); event LockMerged( uint256 indexed fromTokenId, uint256 indexed toTokenId, uint256 totalValue, uint256 unlockTime, bool isPermanent ); event LockSplit(uint256[] splitWeights, uint256 indexed _tokenId); event LockDurationExtended(uint256 indexed tokenId, uint256 newUnlockTime, bool isPermanent); event LockAmountIncreased(uint256 indexed tokenId, uint256 value); event UnlockPermanent(uint256 indexed tokenId, address indexed sender, uint256 unlockTime); /// @notice Delegate events event LockDelegateChanged( uint256 indexed tokenId, address indexed delegator, address fromDelegate, address indexed toDelegate ); /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- error AlreadyVoted(); error InvalidNonce(); error InvalidDelegatee(); error InvalidSignature(); error InvalidSignatureS(); error InvalidWeights(); error LockDurationNotInFuture(); error LockDurationTooLong(); error LockExpired(); error LockNotExpired(); error NoLockFound(); error NotPermanentLock(); error PermanentLock(); error PermanentLockMismatch(); error SameNFT(); error SignatureExpired(); error ZeroAmount(); error LockHoldsValue(); error NotLockOwner(); function supply() external view returns (uint); function token() external view returns (IERC20Upgradeable); function balanceOfNFT(uint256 _tokenId) external view returns (uint256); function balanceOfNFTAt(uint256 _tokenId, uint256 _timestamp) external view returns (uint256); function delegates(uint256 tokenId, uint48 timestamp) external view returns (address); function lockDetails(uint256 tokenId) external view returns (LockDetails calldata); function isApprovedOrOwner(address user, uint tokenId) external view returns (bool); function getPastEscrowPoint( uint256 _tokenId, uint256 _timePoint ) external view returns (Checkpoints.Point memory, uint48); function getFirstEscrowPoint(uint256 _tokenId) external view returns (Checkpoints.Point memory, uint48); function checkpoint() external; function increaseAmount(uint256 _tokenId, uint256 _value) external; function createLockFor( uint256 _value, uint256 _lockDuration, address _to, bool _permanent ) external returns (uint256); function createDelegatedLockFor( uint256 _value, uint256 _lockDuration, address _to, address _delegatee, bool _permanent ) external returns (uint256); function split(uint256[] memory _weights, uint256 _tokenId) external; function merge(uint256 _from, uint256 _to) external; function burn(uint256 _tokenId) external; function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // This file was derived from OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) pragma solidity 0.8.13; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; /** * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. */ library Checkpoints { struct Trace { Checkpoint[] _checkpoints; } /** * @dev Struct to keep track of the voting power over time. */ struct Point { /// @dev The voting power at a specific time /// - MUST never be negative. int128 bias; /// @dev The rate at which the voting power decreases over time. int128 slope; /// @dev The value of tokens which do not decrease over time, representing permanent voting power /// - MUST never be negative. int128 permanent; } struct Checkpoint { uint48 _key; Point _value; } /** * @dev A value was attempted to be inserted on a past checkpoint. */ error CheckpointUnorderedInsertions(); /** * @dev Pushes a (`key`, `value`) pair into a Trace so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the * library. */ function push(Trace storage self, uint48 key, Point memory value) internal returns (Point memory, Point memory) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(Trace storage self, uint48 key) internal view returns (Point memory) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? blankPoint() : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup( Trace storage self, uint48 key ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); exists = pos != 0; _value = exists ? _unsafeAccess(self._checkpoints, pos - 1)._value : blankPoint(); _key = exists ? _unsafeAccess(self._checkpoints, pos - 1)._key : 0; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent( Trace storage self, uint48 key ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); exists = pos != 0; _value = exists ? _unsafeAccess(self._checkpoints, pos - 1)._value : blankPoint(); _key = exists ? _unsafeAccess(self._checkpoints, pos - 1)._key : 0; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace storage self) internal view returns (Point memory) { uint256 pos = self._checkpoints.length; return pos == 0 ? blankPoint() : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint( Trace storage self ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, blankPoint()); } else { Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function firstCheckpoint( Trace storage self ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, blankPoint()); } else { Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, 0); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(Trace storage self, uint48 pos) internal view returns (Checkpoint memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert( Checkpoint[] storage self, uint48 key, Point memory value ) private returns (Point memory, Point memory) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. Checkpoint memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. if (last._key > key) { revert CheckpointUnorderedInsertions(); } // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(Checkpoint({_key: key, _value: value})); } return (last._value, value); } else { self.push(Checkpoint({_key: key, _value: value})); return (blankPoint(), value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and * exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private view returns (Checkpoint storage result) { return self[pos]; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _realUnsafeAccess( Checkpoint[] storage self, uint256 pos ) private pure returns (Checkpoint storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } function blankPoint() internal pure returns (Point memory) { return Point({bias: 0, slope: 0, permanent: 0}); } struct TraceAddress { CheckpointAddress[] _checkpoints; } struct CheckpointAddress { uint48 _key; address _value; } /** * @dev Pushes a (`key`, `value`) pair into a TraceAddress so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the * library. */ function push(TraceAddress storage self, uint48 key, address value) internal returns (address, address) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? address(0) : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(TraceAddress storage self) internal view returns (address) { uint256 pos = self._checkpoints.length; return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint( TraceAddress storage self ) internal view returns (bool exists, uint48 _key, address _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, address(0)); } else { CheckpointAddress memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(TraceAddress storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(TraceAddress storage self, uint48 pos) internal view returns (CheckpointAddress memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert(CheckpointAddress[] storage self, uint48 key, address value) private returns (address, address) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. CheckpointAddress memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. if (last._key > key) { revert CheckpointUnorderedInsertions(); } // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(CheckpointAddress({_key: key, _value: value})); } return (last._value, value); } else { self.push(CheckpointAddress({_key: key, _value: value})); return (address(0), value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( CheckpointAddress[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and * exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( CheckpointAddress[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( CheckpointAddress[] storage self, uint256 pos ) private pure returns (CheckpointAddress storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {SafeCastLibrary} from "../libraries/SafeCastLibrary.sol"; import {Checkpoints} from "../libraries/Checkpoints.sol"; import {Time} from "../libraries/Time.sol"; /** * @title CheckPointSystem * @dev This contract is used to manage checkpoints in the system. */ library EscrowDelegateCheckpoints { using Checkpoints for Checkpoints.Trace; using Checkpoints for Checkpoints.TraceAddress; using SafeCastLibrary for int128; using SafeCastLibrary for uint256; /// @notice Maximum time for a checkpoint int128 public constant MAX_TIME = 2 * 365 * 86400; /// @notice Unit of time for the clock uint48 public constant CLOCK_UNIT = 7 days; struct EscrowDelegateStore { /// @notice Global checkpoints Checkpoints.Trace _globalCheckpoints; /// @notice Mapping of global slope changes /// @dev Intended to be exposed with a getter mapping(uint256 => int128) globalSlopeChanges; /// @notice escrow lock checkpoints mapping(uint256 => Checkpoints.Trace) _escrowCheckpoints; /// @notice Delegate checkpoints mapping(address => Checkpoints.Trace) _delegateCheckpoints; /// @notice escrow lock to delegatee mapping mapping(uint256 => Checkpoints.TraceAddress) _escrowDelegateeAddress; /// @notice Delegatee slope changes /// @dev Intended to be exposed with a getter mapping(address => mapping(uint256 => int128)) delegateeSlopeChanges; } event CheckpointGlobal(uint48 timestamp, int128 slope, int128 bias, int128 permanent); event CheckpointDelegate(address delegatee, uint48 timestamp, int128 slope, int128 bias, int128 permanent); event CheckpointEscrow(uint256 escrowId, uint48 timestamp, int128 slope, int128 bias, int128 permanent); /** * @notice Clock used for flagging checkpoints. * @return Current timestamp */ function clock() public view returns (uint48) { return Time.timestamp(); } /** * @notice Clock used for flagging global checkpoints. * @return Current timestamp rounded to the nearest clock unit */ function globalClock() public view returns (uint48) { return toGlobalClock(Time.timestamp()); } /** * @notice Converts a timestamp to a global clock value. * @param timestamp The timestamp to convert * @return The converted global clock value */ function toGlobalClock(uint256 timestamp) internal pure returns (uint48) { return uint48((timestamp / CLOCK_UNIT) * CLOCK_UNIT); } /** * @dev Record global and per-escrow data to checkpoints. Used by VotingEscrow system. * @param store_ The EscrowDelegateStore struct containing all the storage mappings. * @param escrowId NFT escrow lock ID. No escrow checkpoint if 0 * @param uOldAmount Locked amount from last checkpoint * @param uNewAmount Locked amount from current checkpoint * @param uOldEndTime Last checkpoint time * @param uNewEndTime Current checkpoint time */ function checkpoint( EscrowDelegateStore storage store_, uint256 escrowId, int128 uOldAmount, int128 uNewAmount, uint256 uOldEndTime, uint256 uNewEndTime ) external { int128 oldDslope = 0; int128 newDslope = 0; Checkpoints.Point memory uOldPoint = Checkpoints.blankPoint(); Checkpoints.Point memory uNewPoint = Checkpoints.blankPoint(); /// @notice if this is not rounded to CLOCK_UNIT /// the system will not be able to go too long without checkpoints uNewEndTime = toGlobalClock(uNewEndTime); if (escrowId != 0) { // Calculate slopes and biases // Kept at zero when they have to uNewPoint.permanent = uNewEndTime == 0 ? uNewAmount : int128(0); uOldPoint.permanent = uOldEndTime == 0 ? uOldAmount : int128(0); if (uOldEndTime > block.timestamp && uOldAmount > 0) { /// @dev Calculate the slope based on the older checkpoint amount uOldPoint.slope = (uOldAmount) / MAX_TIME; uOldPoint.bias = (uOldPoint.slope * (uOldEndTime - block.timestamp).toInt128()); } if (uNewEndTime > block.timestamp && uNewAmount > 0) { uNewPoint.slope = (uNewAmount) / MAX_TIME; uNewPoint.bias = (uNewPoint.slope * (uNewEndTime - block.timestamp).toInt128()); } oldDslope = store_.globalSlopeChanges[uOldEndTime]; if (uNewEndTime != 0) { if (uNewEndTime == uOldEndTime) { newDslope = oldDslope; } else { newDslope = store_.globalSlopeChanges[uNewEndTime]; } } // Schedule the slope changes (slope is going down) // We subtract new escrow slope from [_newLocked.endTime] // and add old_escrow_slope to [_oldLocked.end] if (uOldEndTime > block.timestamp) { // oldDslope was <something> - uOld.slope, so we cancel that oldDslope += uOldPoint.slope; if (uOldEndTime == uNewEndTime) { oldDslope -= uNewPoint.slope; // It was a new deposit, not extension } store_.globalSlopeChanges[uOldEndTime] = oldDslope; } if (uNewEndTime > block.timestamp) { // update slope if new lock is greater than old lock and is not permanent or if old lock is permanent if ((uNewEndTime > uOldEndTime)) { newDslope -= uNewPoint.slope; // old slope disappeared at this point store_.globalSlopeChanges[uNewEndTime] = newDslope; } // else: we recorded it already in oldDslope } /// @dev Add the new point to the escrowId Checkpoints.Trace _pushPointAtClock(store_._escrowCheckpoints[escrowId], uNewPoint); emit CheckpointEscrow(escrowId, clock(), uNewPoint.slope, uNewPoint.bias, uNewPoint.permanent); (, uint48 delegateTs, address delegateeAddress) = store_ ._escrowDelegateeAddress[escrowId] .latestCheckpoint(); if (delegateTs != 0) { /// @notice this can likely be handled more efficiently _checkpointDelegatee(store_, delegateeAddress, uOldPoint, uOldEndTime, false); _checkpointDelegatee(store_, delegateeAddress, uNewPoint, uNewEndTime, true); } } /// @dev If escrowId is 0, this will still create a global checkpoint globalCheckpoint(store_, escrowId, uOldPoint, uNewPoint); } /** * @dev Function to update global checkpoint */ function globalCheckpoint(EscrowDelegateStore storage store_) external { globalCheckpoint(store_, 0, Checkpoints.blankPoint(), Checkpoints.blankPoint()); } /** * @dev Function to update global checkpoint with new points * @param escrowId The ID of the escrow lock * - If * @param uOldPoint The old point to be updated * @param uNewPoint The new point to be updated */ function globalCheckpoint( EscrowDelegateStore storage store_, uint256 escrowId, Checkpoints.Point memory uOldPoint, Checkpoints.Point memory uNewPoint ) public { (, uint48 lastPoint, Checkpoints.Point memory lastGlobal) = store_._globalCheckpoints.latestCheckpoint(); uint48 lastCheckpoint = lastPoint != 0 ? lastPoint : uint48(block.timestamp); { // Go over weeks to fill history and calculate what the current point is uint48 testTime = toGlobalClock(lastCheckpoint); /// @dev lastCheckpoint > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); while (testTime < block.timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > block.timestamp) { testTime = block.timestamp.toUint48(); } else { dSlope = store_.globalSlopeChanges[testTime]; } if (dSlope != 0) { lastGlobal.bias -= lastGlobal.slope * uint256(testTime - lastCheckpoint).toInt128(); lastGlobal.slope += dSlope; if (lastGlobal.bias < 0) { lastGlobal.bias = 0; } if (lastGlobal.slope < 0) { lastGlobal.slope = 0; } lastCheckpoint = testTime; store_._globalCheckpoints.push(lastCheckpoint, lastGlobal); } if (testTime > maxTime) break; } } if (escrowId != 0) { lastGlobal.bias = lastGlobal.bias - ((lastGlobal.slope * (block.timestamp - lastCheckpoint).toInt128())); lastGlobal.slope += uNewPoint.slope - uOldPoint.slope; lastGlobal.bias += uNewPoint.bias - uOldPoint.bias; lastGlobal.permanent += uNewPoint.permanent - uOldPoint.permanent; } else { // Initial value of testTime is always larger than the ts of the last point uint256 testTime = block.timestamp; lastGlobal.bias -= (lastGlobal.slope * (testTime - lastCheckpoint).toInt128()); } _pushPointAtClock(store_._globalCheckpoints, lastGlobal); emit CheckpointGlobal(clock(), lastGlobal.slope, lastGlobal.bias, lastGlobal.permanent); } /** * @dev Function to calculate total voting power at some point in the past * @param _delegateeAddress The address of the delegatee * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function getAdjustedVotes( EscrowDelegateStore storage store_, address _delegateeAddress, uint48 timestamp ) external view returns (uint256) { Checkpoints.Point memory lastPoint = _getAdjustedVotesCheckpoint(store_, _delegateeAddress, timestamp); return (lastPoint.bias + lastPoint.permanent).toUint256(); } /** * @dev Function to get delegated votes checkpoint at some point in the past * @param _delegateeAddress The address of the delegatee * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function _getAdjustedVotesCheckpoint( EscrowDelegateStore storage store_, address _delegateeAddress, uint48 timestamp ) internal view returns (Checkpoints.Point memory) { (bool exists, uint48 lastCheckpointTs, Checkpoints.Point memory lastPoint) = store_ ._delegateCheckpoints[_delegateeAddress] .upperLookupRecent(timestamp); if (!exists) return lastPoint; uint48 testTime = toGlobalClock(lastCheckpointTs); /// @dev lastCheckpointTs > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); while (testTime < timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > timestamp) { testTime = timestamp; } else { dSlope = store_.delegateeSlopeChanges[_delegateeAddress][testTime]; } if (dSlope != 0) { lastPoint.bias -= lastPoint.slope * uint256(testTime - lastCheckpointTs).toInt128(); lastPoint.slope += dSlope; if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (lastPoint.slope < 0) { lastPoint.slope = 0; } lastCheckpointTs = uint48(testTime); } if (testTime > maxTime) break; } int128 change = lastPoint.slope * uint256(timestamp - lastCheckpointTs).toInt128(); lastPoint.bias = lastPoint.bias < change ? int128(0) : lastPoint.bias - change; return lastPoint; } /** * @notice Public function to get the delegatee of an escrow lock * @param escrowId The ID of the escrow * @return The address of the delegate */ function getEscrowDelegatee(EscrowDelegateStore storage store_, uint256 escrowId) external view returns (address) { return getEscrowDelegateeAtTime(store_, escrowId, block.timestamp.toUint48()); } /** * @notice Public function to get the delegatee of an escrow lock * @param escrowId The ID of the escrow lock * @param timestamp The timestamp to get the delegate at * @return The address of the delegate */ function getEscrowDelegateeAtTime( EscrowDelegateStore storage store_, uint256 escrowId, uint48 timestamp ) public view returns (address) { return store_._escrowDelegateeAddress[escrowId].upperLookupRecent(timestamp); } /** * @dev Function to record escrow delegation checkpoints. Used by voting system. * @param escrowId The ID of the escrow lock * @param delegatee The address of the delegatee * @param endTime The end time of the delegation */ function delegate( EscrowDelegateStore storage store_, uint256 escrowId, address delegatee, uint256 endTime ) external returns (address oldDelegatee, address newDelegatee) { oldDelegatee = store_._escrowDelegateeAddress[escrowId].latest(); if (oldDelegatee == delegatee) return (oldDelegatee, delegatee); (, uint48 ts, Checkpoints.Point memory lastPoint) = store_._escrowCheckpoints[escrowId].latestCheckpoint(); lastPoint.bias -= ((lastPoint.slope * (block.timestamp - ts).toInt128())); if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (oldDelegatee != delegatee && oldDelegatee != address(0)) { _checkpointDelegatee(store_, oldDelegatee, lastPoint, endTime, false); } // Delegate to new delegator _checkpointDelegatee(store_, delegatee, lastPoint, endTime, true); _pushAddressAtClock(store_._escrowDelegateeAddress[escrowId], delegatee); return (oldDelegatee, delegatee); } /** * @dev Function to update delegatee's `delegatedBalance` by `balance`. * Only updates if delegating to a new delegatee. * @param delegateeAddress The address of the delegatee * @param escrowPoint The point of the escrow * @param endTime The end time of the delegation * @param increase Whether to increase or decrease the balance */ function _checkpointDelegatee( EscrowDelegateStore storage store_, address delegateeAddress, Checkpoints.Point memory escrowPoint, uint256 endTime, bool increase ) internal { (Checkpoints.Point memory lastPoint, uint48 lastCheckpoint) = baseCheckpointDelegatee(store_, delegateeAddress); int128 baseBias = lastPoint.bias - (lastPoint.slope * (block.timestamp - lastCheckpoint).toInt128()); if (!increase) { if (endTime > block.timestamp) { store_.delegateeSlopeChanges[delegateeAddress][endTime] += escrowPoint.slope; lastPoint.slope = escrowPoint.slope < lastPoint.slope ? lastPoint.slope - escrowPoint.slope : int128(0); } lastPoint.bias = escrowPoint.bias < baseBias ? baseBias - escrowPoint.bias : int128(0); lastPoint.permanent = escrowPoint.permanent < lastPoint.permanent ? lastPoint.permanent - escrowPoint.permanent : int128(0); } else { if (endTime > block.timestamp) { store_.delegateeSlopeChanges[delegateeAddress][endTime] -= escrowPoint.slope; lastPoint.slope = lastPoint.slope + escrowPoint.slope; } lastPoint.bias = baseBias + escrowPoint.bias; lastPoint.permanent = lastPoint.permanent + escrowPoint.permanent; } /// @dev bias can be rounded up by lack of precision. If slope is 0 we are out if (lastPoint.slope == 0) { lastPoint.bias = 0; } _pushPointAtClock(store_._delegateCheckpoints[delegateeAddress], lastPoint); emit CheckpointDelegate(delegateeAddress, clock(), lastPoint.slope, lastPoint.bias, lastPoint.permanent); } /** * @dev Function to update delegatee's checkpoint * @param delegateeAddress The address of the delegatee * @return lastPoint The last point of the delegatee * @return lastCheckpoint The last checkpoint time of the delegatee */ function baseCheckpointDelegatee( EscrowDelegateStore storage store_, address delegateeAddress ) public returns (Checkpoints.Point memory lastPoint, uint48 lastCheckpoint) { (bool exists, uint48 ts, Checkpoints.Point memory point) = store_ ._delegateCheckpoints[delegateeAddress] .latestCheckpoint(); lastPoint = point; lastCheckpoint = ts; if (exists) { // Go over days to fill history and calculate what the current point is uint48 testTime = toGlobalClock(lastCheckpoint); /// @dev lastCheckpoint > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); // Iterate over time until current block timestamp or maxtime while (testTime < block.timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > block.timestamp) { testTime = uint48(block.timestamp); } else { dSlope = store_.delegateeSlopeChanges[delegateeAddress][testTime]; } if (dSlope != 0) { lastPoint.bias -= lastPoint.slope * uint256(testTime - lastCheckpoint).toInt128(); lastPoint.slope += dSlope; if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (lastPoint.slope < 0) { lastPoint.slope = 0; } lastCheckpoint = uint48(testTime); store_._delegateCheckpoints[delegateeAddress].push(lastCheckpoint, lastPoint); } if (testTime > maxTime) break; } } emit CheckpointDelegate(delegateeAddress, clock(), lastPoint.slope, lastPoint.bias, lastPoint.permanent); } /** * @dev Function to calculate total voting power at some point in the past * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function getAdjustedGlobalVotes( EscrowDelegateStore storage store_, uint48 timestamp ) external view returns (uint256) { Checkpoints.Point memory lastPoint = _getAdjustedCheckpoint(store_, timestamp); return (lastPoint.bias + lastPoint.permanent).toUint256(); } /** * @dev Function to get latest checkpoint of some point in the past * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function _getAdjustedCheckpoint( EscrowDelegateStore storage store_, uint48 timestamp ) internal view returns (Checkpoints.Point memory) { uint48 clockTime = timestamp; (bool exists, uint48 lastCheckpointTs, Checkpoints.Point memory lastGlobal) = store_ ._globalCheckpoints .upperLookupRecent(clockTime); if (!exists) return lastGlobal; uint48 testTime = toGlobalClock(lastCheckpointTs); /// @dev lastCheckpointTs > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); // Iterate over time until the specified timestamp or maxtime is reached while (testTime < timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > timestamp) { testTime = timestamp; } else { dSlope = store_.globalSlopeChanges[testTime]; } if (dSlope != 0) { lastGlobal.bias -= lastGlobal.slope * uint256(testTime - lastCheckpointTs).toInt128(); lastGlobal.slope += dSlope; if (lastGlobal.bias < 0) { lastGlobal.bias = 0; } if (lastGlobal.slope < 0) { lastGlobal.slope = 0; } lastCheckpointTs = uint48(testTime); } if (testTime > maxTime) break; } int128 change = lastGlobal.slope * uint256(clockTime - lastCheckpointTs).toInt128(); lastGlobal.bias = lastGlobal.bias < change ? int128(0) : lastGlobal.bias - change; return lastGlobal; } /** * @notice Get the current bias for `escrowId` at `timestamp` * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility * @dev Fetches last escrow point prior to a certain timestamp, then walks forward to timestamp. * @param escrowId NFT for lock * @param timestamp Epoch time to return bias power at * @return NFT bias */ function getAdjustedEscrowBias( EscrowDelegateStore storage store_, uint256 escrowId, uint256 timestamp ) external view returns (uint256) { uint48 clockTime = timestamp.toUint48(); (Checkpoints.Point memory lastPoint,) = getAdjustedEscrow(store_, escrowId, clockTime); if (lastPoint.permanent != 0) return lastPoint.permanent.toUint256(); return lastPoint.bias.toUint256(); } /** * @notice Get the current bias for `escrowId` at `timestamp` * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility * @dev Fetches last escrow point prior to a certain timestamp, then walks forward to timestamp. * @param escrowId NFT for lock * @param timestamp Epoch time to return bias power at * @return NFT bias */ function getAdjustedEscrow( EscrowDelegateStore storage store_, uint256 escrowId, uint256 timestamp ) public view returns (Checkpoints.Point memory, uint48) { uint48 clockTime = timestamp.toUint48(); (bool exists, uint48 ts, Checkpoints.Point memory lastPoint) = store_ ._escrowCheckpoints[escrowId] .upperLookupRecent(clockTime); if (!exists) return (lastPoint, ts); int128 change = ((lastPoint.slope * uint256(clockTime - ts).toInt128())); lastPoint.bias = lastPoint.bias < change ? int128(0) : lastPoint.bias - change; return (lastPoint, ts); } function getFirstEscrowPoint( EscrowDelegateStore storage store_, uint256 escrowId ) internal view returns (Checkpoints.Point memory, uint48) { (, uint48 ts, Checkpoints.Point memory point) = store_._escrowCheckpoints[escrowId].firstCheckpoint(); return (point, ts); } /// ----------------------------------------------------------------------- /// Private functions /// ----------------------------------------------------------------------- /** * @dev Function to push an address to the checkpoint * @param store The storage to push the address to * @param value The address to be pushed * @return The old and new address */ function _pushAddressAtClock( Checkpoints.TraceAddress storage store, address value ) private returns (address, address) { return store.push(clock(), value); } /** * @dev Function to push a struct to the checkpoint * @param store The storage to push the struct to * @param value The struct to be pushed * @return The old and new struct */ function _pushPointAtClock( Checkpoints.Trace storage store, Checkpoints.Point memory value ) private returns (Checkpoints.Point memory, Checkpoints.Point memory) { return store.push(clock(), value); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {EscrowDelegateCheckpoints} from "./EscrowDelegateCheckpoints.sol"; /** * @title EscrowDelegateStorage * @dev This contract serves as the storage for checkpoints in the system. */ contract EscrowDelegateStorage { using EscrowDelegateCheckpoints for EscrowDelegateCheckpoints.EscrowDelegateStore; /// @notice Storage struct for the checkpoint system EscrowDelegateCheckpoints.EscrowDelegateStore internal edStore; /// @dev Must be reset in initialization for upgradeability uint256 MAX_TIME = uint256(uint128(EscrowDelegateCheckpoints.MAX_TIME)); /// @notice Gap for future upgrades uint256[50] private __gap; /// ----------------------------------------------------------------------- /// Getters /// ----------------------------------------------------------------------- function globalSlopeChanges(uint256 _timestamp) external view returns (int128) { return edStore.globalSlopeChanges[_timestamp]; } function delegateeSlopeChanges(address _delegatee, uint256 _timestamp) external view returns (int128) { return edStore.delegateeSlopeChanges[_delegatee][_timestamp]; } function toGlobalClock(uint256 _timestamp) public pure virtual returns (uint48) { return EscrowDelegateCheckpoints.toGlobalClock(_timestamp); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; /// @title SafeCast Library /// @author velodrome.finance /// @notice Safely convert unsigned and signed integers without overflow / underflow library SafeCastLibrary { error SafeCastOverflow(); error SafeCastUnderflow(); /// @dev Safely convert uint256 to int128 function toInt128(uint256 value) internal pure returns (int128) { if (value > uint128(type(int128).max)) revert SafeCastOverflow(); return int128(uint128(value)); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) revert SafeCastOverflow(); return uint48(value); } /// @dev Safely convert int128 to uint256 function toUint256(int128 value) internal pure returns (uint256) { if (value < 0) revert SafeCastUnderflow(); return uint256(int256(value)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {SafeCastLibrary} from "./SafeCastLibrary.sol"; /** * @notice Adapted from OpenZeppelin's Time library: v5.0.0 for solc 0.8.13 * @dev This library provides helpers for manipulating time-related objects. * * It uses the following types: * - `uint48` for timepoints * - `uint32` for durations * * While the library doesn't provide specific types for timepoints and duration, it does provide: * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point * - additional helper functions */ library Time { using Time for *; /** * @dev Get the block timestamp as a Timepoint. */ function timestamp() internal view returns (uint48) { return SafeCastLibrary.toUint48(block.timestamp); } /** * @dev Get the block number as a Timepoint. */ function blockNumber() internal view returns (uint48) { return SafeCastLibrary.toUint48(block.number); } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/VoterV5/VotingEscrow/libraries/EscrowDelegateCheckpoints.sol": { "EscrowDelegateCheckpoints": "0xa615388bd2f920ee2fec7606f26908b454f0c249" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyVoted","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[],"name":"InvalidDelegatee","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureS","type":"error"},{"inputs":[],"name":"InvalidWeights","type":"error"},{"inputs":[],"name":"LockDurationNotInFuture","type":"error"},{"inputs":[],"name":"LockDurationTooLong","type":"error"},{"inputs":[],"name":"LockExpired","type":"error"},{"inputs":[],"name":"LockHoldsValue","type":"error"},{"inputs":[],"name":"LockNotExpired","type":"error"},{"inputs":[],"name":"NoLockFound","type":"error"},{"inputs":[],"name":"NotLockOwner","type":"error"},{"inputs":[],"name":"NotPermanentLock","type":"error"},{"inputs":[],"name":"PermanentLock","type":"error"},{"inputs":[],"name":"PermanentLockMismatch","type":"error"},{"inputs":[],"name":"SafeCastOverflow","type":"error"},{"inputs":[],"name":"SameNFT","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"VotesExpiredSignature","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ClaimApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ClaimApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"LockAmountIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockTime","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isPermanent","type":"bool"}],"name":"LockCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"LockDelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUnlockTime","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isPermanent","type":"bool"}],"name":"LockDurationExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockTime","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isPermanent","type":"bool"}],"name":"LockMerged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"splitWeights","type":"uint256[]"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"LockSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockTime","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isPermanent","type":"bool"}],"name":"LockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimAmount","type":"uint256"}],"name":"PayoutClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"}],"name":"SupplyUpdated","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":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"unlockTime","type":"uint256"}],"name":"UnlockPermanent","type":"event"},{"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_lockDetails","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bool","name":"isPermanent","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_token","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"artProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","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":"_timestamp","type":"uint256"}],"name":"balanceOfNFTAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateeAddress","type":"address"}],"name":"checkpointDelegatee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"claimablePayout","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"claimedPayout","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_delegatee","type":"address"},{"internalType":"bool","name":"_permanent","type":"bool"}],"name":"createDelegatedLockFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"bool","name":"_permanent","type":"bool"}],"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"},{"internalType":"bool","name":"_permanent","type":"bool"}],"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":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"delegateeSlopeChanges","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint48","name":"timestamp","type":"uint48"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountDelegates","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"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":"getClaimApproved","outputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getFirstEscrowPoint","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"int128","name":"permanent","type":"int128"}],"internalType":"struct Checkpoints.Point","name":"","type":"tuple"},{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getLockDelegatee","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getPastEscrowPoint","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"int128","name":"permanent","type":"int128"}],"internalType":"struct Checkpoints.Point","name":"","type":"tuple"},{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timePoint","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalCheckpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"globalSlopeChanges","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"},{"internalType":"bool","name":"_permanent","type":"bool"}],"name":"increaseUnlockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"contract IERC20Upgradeable","name":"mainToken","type":"address"},{"internalType":"address","name":"_artProxy","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isApprovedClaimOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"user","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isClaimApprovedForAll","outputs":[{"internalType":"bool","name":"isClaimApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"lockDetails","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bool","name":"isPermanent","type":"bool"}],"internalType":"struct IVotingEscrowV2Upgradeable.LockDetails","name":"","type":"tuple"}],"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":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"tokenId","type":"uint256"}],"name":"payoutToken","outputs":[{"internalType":"address","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"setClaimApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setClaimApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_weights","type":"uint256[]"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"split","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"supported","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"toGlobalClock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","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":"totalNftsMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":"_tokenId","type":"uint256"}],"name":"unlockPermanent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"vestedPayout","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"vestedPayoutAtTime","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"vestingPayout","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"vestingPeriod","outputs":[{"internalType":"uint256","name":"vestingStart","type":"uint256"},{"internalType":"uint256","name":"vestingEnd","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040526303c26700610104556000610171553480156200002057600080fd5b506200002b62000041565b600161016b556200003b62000041565b62000102565b600054610100900460ff1615620000ae5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161462000100576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615f4780620001126000396000f3fe608060405234801561001057600080fd5b506004361061048d5760003560e01c80637ecebe001161026b578063c7d7d90f11610150578063db900b9d116100c8578063e7e242d411610097578063ecd0c0c31161007c578063ecd0c0c314610b72578063f778e0a314610b86578063fc0c546a14610b9957600080fd5b8063e7e242d414610b23578063e985e9c514610b3657600080fd5b8063db900b9d14610ac3578063e0514aba14610ad6578063e58ee17d14610ae9578063e7a324dc14610afc57600080fd5b8063d1c2babb1161011f578063d6d0faee11610104578063d6d0faee14610a7d578063d744515f14610a90578063d93aafb514610aa357600080fd5b8063d1c2babb14610a57578063d60371a714610a6a57600080fd5b8063c7d7d90f1461099c578063c87b56dd146109f7578063cae57c8914610a0a578063d113cfba14610a4457600080fd5b80639e0bd808116101e3578063b2383e55116101b2578063bb7cfce211610197578063bb7cfce21461094b578063c2c4c5c114610981578063c3cda5201461098957600080fd5b8063b2383e5514610925578063b88d4fde1461093857600080fd5b80639e0bd808146108b05780639f194422146108c3578063a22cb465146108d6578063a2e8a50c146108e957600080fd5b806384e968e61161023a5780638e539e8c1161021f5780638e539e8c1461088257806395d89b41146108955780639ab24eb01461089d57600080fd5b806384e968e61461085c5780638b9cb90b1461086f57600080fd5b80637ecebe00146107e4578063807c35311461080557806381d0526d1461082e57806384b0196e1461084157600080fd5b80633a46b1a811610391578063587cde1e116103095780636bec7397116102d857806370a08231116102bd57806370a08231146107b457806372fbaacb146107c7578063753c7328146107d157600080fd5b80636bec7397146107555780636c423c101461076857600080fd5b8063587cde1e146106d45780635c19a95c146106e757806363185237146106fa5780636352211e1461074257600080fd5b8063430c2081116103605780635594a045116103455780635594a0451461068557806356afe74414610699578063576561d2146106ac57600080fd5b8063430c20811461065f5780634f6ccce71461067257600080fd5b80633a46b1a8146106135780633c340b321461062657806342842e0e1461063957806342966c681461064c57600080fd5b80631ac40e66116104245780632f745c59116103f3578063323418c1116103d8578063323418c1146105da57806335b0f6bd146105ed578063379607f51461060057600080fd5b80632f745c59146105ad578063313ce567146105c057600080fd5b80631ac40e6614610555578063212d18c91461055d57806323b872dd146105875780632b3b09ec1461059a57600080fd5b806308bbb8241161046057806308bbb82414610512578063095ea7b3146105275780630a2abdb31461053a57806318160ddd1461054d57600080fd5b806301ffc9a714610492578063047fc9aa146104ba57806306fdde03146104d2578063081812fc146104e7575b600080fd5b6104a56104a036600461548a565b610bab565b60405190151581526020015b60405180910390f35b6104c461016d5481565b6040519081526020016104b1565b6104da610bef565b6040516104b191906154ff565b6104fa6104f5366004615512565b610c81565b6040516001600160a01b0390911681526020016104b1565b610525610520366004615540565b610ca8565b005b610525610535366004615570565b610e37565b6104c46105483660046155aa565b610f68565b6104c4610f96565b61052561102f565b61057061056b366004615512565b6110c0565b60405165ffffffffffff90911681526020016104b1565b6105256105953660046155f4565b6110cb565b6104fa6105a8366004615649565b611142565b6104c46105bb366004615570565b6111ee565b6105c8601281565b60405160ff90911681526020016104b1565b6105256105e836600461566e565b611296565b6105256105fb366004615512565b61130b565b61052561060e366004615512565b611522565b6104c4610621366004615570565b61152b565b6104c461063436600461569c565b6115d1565b6105256106473660046155f4565b611600565b61052561065a366004615512565b61161b565b6104a561066d366004615570565b6116bb565b6104c4610680366004615512565b6116d0565b61016e546104fa906001600160a01b031681565b6105256106a7366004615742565b611774565b6106bf6106ba366004615512565b611ad2565b604080519283526020830191909152016104b1565b6104fa6106e23660046157ee565b611b45565b6105256106f53660046157ee565b611c5f565b61070d610708366004615512565b611c69565b6040516104b1919081518152602080830151908201526040808301519082015260609182015115159181019190915260800190565b6104fa610750366004615512565b611ce1565b6104a5610763366004615570565b611d46565b61077b61077636600461580b565b611dce565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff1660608201526080016104b1565b6104c46107c23660046157ee565b611e94565b6104c46101715481565b6105256107df3660046157ee565b611f2e565b6104c46107f23660046157ee565b61016f6020526000908152604090205481565b6104fa610813366004615512565b600090815260ca60205260409020546001600160a01b031690565b6104c461083c366004615512565b611fdf565b61084961203e565b6040516104b19796959493929190615868565b6104c461086a366004615512565b612102565b6104fa61087d366004615512565b612152565b6104c4610890366004615512565b61219f565b6104da612234565b6104c46108ab3660046157ee565b612243565b6104c46108be366004615512565b6122ac565b6105256108d13660046158f2565b6122ff565b6105256108e436600461566e565b6124d2565b6104a56108f736600461592b565b6001600160a01b03918216600090815260cb6020908152604080832093909416825291909152205460ff1690565b61052561093336600461580b565b6124dd565b6105256109463660046159bf565b6125e5565b61096e610959366004615512565b600090815260ff6020526040902054600f0b90565b604051600f9190910b81526020016104b1565b610525612663565b610525610997366004615a3f565b61266b565b6109d56109aa366004615512565b6101706020526000908152604090208054600182015460028301546003909301549192909160ff1684565b60408051948552602085019390935291830152151560608201526080016104b1565b6104da610a05366004615512565b6126b3565b61096e610a18366004615570565b6001600160a01b03919091166000908152610103602090815260408083209383529290522054600f0b90565b610525610a52366004615aa1565b6127d9565b610525610a6536600461580b565b612875565b6104c4610a783660046158f2565b612c64565b610525610a8b366004615af1565b612c8a565b6104c4610a9e36600461580b565b612df6565b610ab6610ab13660046157ee565b612e6e565b6040516104b19190615b93565b6104c4610ad1366004615512565b612f9e565b6104c4610ae436600461580b565b612faa565b6104fa610af7366004615512565b612ff3565b6104c47fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b6104c4610b31366004615512565b613071565b6104a5610b4436600461592b565b6001600160a01b039182166000908152606a6020908152604080832093909416825291909152205460ff1690565b61016c546104fa906001600160a01b031681565b61077b610b94366004615512565b6130b9565b61016c546001600160a01b03166104fa565b60006001600160e01b031982167fddf0aba2000000000000000000000000000000000000000000000000000000001480610be95750610be9826130ea565b92915050565b606060658054610bfe90615be0565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2a90615be0565b8015610c775780601f10610c4c57610100808354040283529160200191610c77565b820191906000526020600020905b815481529060010190602001808311610c5a57829003601f168201915b5050505050905090565b6000610c8c82613128565b506000908152606960205260409020546001600160a01b031690565b60008281526067602052604090205482906001600160a01b031680610ce857604051637e27328960e01b8152600481018390526024015b60405180910390fd5b33610cf482828561318c565b610d235760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b60008581526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018890526001600160a01b03871660448201526064810191909152819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af4158015610da5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc99190615c1a565b91509150806001600160a01b0316610dde3390565b6001600160a01b0316887f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e85604051610e2691906001600160a01b0391909116815260200190565b60405180910390a450505050505050565b6000610e4282611ce1565b9050806001600160a01b0316836001600160a01b031603610ecb5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610cdf565b336001600160a01b0382161480610ee75750610ee78133610b44565b610f595760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610cdf565b610f6383836131ff565b505050565b6000610f7261326d565b610f81858585868660016132c8565b9050610f8e600161016b55565b949350505050565b600073a615388bd2f920ee2fec7606f26908b454f0c2496334e78a9e60fe610fbd4261353e565b6040516001600160e01b031960e085901b168152600481019290925265ffffffffffff166024820152604401602060405180830381865af4158015611006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102a9190615c49565b905090565b61103761326d565b6040517f6977e3a900000000000000000000000000000000000000000000000000000000815260fe600482015273a615388bd2f920ee2fec7606f26908b454f0c24990636977e3a99060240160006040518083038186803b15801561109b57600080fd5b505af41580156110af573d6000803e3d6000fd5b505050506110be600161016b55565b565b6000610be98261356b565b6110d53382613585565b6111375760405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608401610cdf565b610f638383836135f1565b6040517f9511aa5300000000000000000000000000000000000000000000000000000000815260fe60048201526024810183905265ffffffffffff8216604482015260009073a615388bd2f920ee2fec7606f26908b454f0c24990639511aa5390606401602060405180830381865af41580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190615c62565b9392505050565b60006111f983611e94565b821061126d5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610cdf565b506001600160a01b03919091166000908152609760209081526040808320938352929052205490565b33600090815260cb602090815260408083206001600160a01b03861684529091529020805460ff191682151517905560405181151581526001600160a01b0383169033907f199acb87f54d9aa34d4c071192d94f5ec4e0b152f52b81209d89085dd7dade7e9060200160405180910390a35050565b61131361326d565b60008181526067602052604090205481906001600160a01b03168061134e57604051637e27328960e01b815260048101839052602401610cdf565b3361135a82828561318c565b6113895760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000848152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff16151560608201819052611408576040517f2188f8ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61141a610104544261056b9190615c95565b65ffffffffffff166040808301919091526000606080840182905287825261017060209081529183902083516080810185528154815260018201549381019390935260028101549383019390935260039092015460ff16151591810191909152611486908690836137f7565b600085815261017060209081526040918290208351815590830151600182015590820151600282015560608201516003909101805460ff1916911515919091179055336001600160a01b0316857f7fbde6b5a06f47dab128f45cea79f339e710e4f5d9e5cda522585afe7b30539b836040015160405161150891815260200190565b60405180910390a35050505061151f600161016b55565b50565b61151f816138b1565b600073a615388bd2f920ee2fec7606f26908b454f0c24963f8183ecf60fe856115538661353e565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015265ffffffffffff1660448201526064015b602060405180830381865af41580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190615c49565b60006115db61326d565b6115ea868686868660016132c8565b90506115f7600161016b55565b95945050505050565b610f63838383604051806020016040528060008152506125e5565b6000818152606760205260409020546001600160a01b0316331461166b576040517f8e5693a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526101706020526040902054156116b2576040517f61442e5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61151f81613bab565b60006111e76116c983611ce1565b848461318c565b60006116db60995490565b821061174f5760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610cdf565b6099828154811061176257611762615cad565b90600052602060002001549050919050565b61177c61326d565b60008181526067602052604090205481906001600160a01b0316806117b757604051637e27328960e01b815260048101839052602401610cdf565b336117c382828561318c565b6117f25760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000848152610170602081815260408084208151608081018352815481526001820154818501526002820154928101928352600382015460ff16151560608201529489905292909152514290811080159061184f57508260600151155b1561186d576040516307b7d7dd60e51b815260040160405180910390fd5b8251158061187c575060028851105b1561189a57604051631f2a200560e01b815260040160405180910390fd5b825161016d80546000906118af908490615cc3565b90915550506000878152606760205260408120546001600160a01b031690805b8a51811015611911578a81815181106118ea576118ea615cad565b6020026020010151826118fd9190615c95565b91508061190981615cda565b9150506118cf565b508060000361194c576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000856060015161197e5783866040015111611969576000611981565b8386604001516119799190615cc3565b611981565b60005b865190915060005b8c51811015611a80576000848e83815181106119a7576119a7615cad565b60200260200101518a600001516119be9190615cf3565b6119c89190615d12565b905060018e516119d89190615cc3565b82036119e15750815b6119eb8184615cc3565b925081600003611a585780885561016d8054829190600090611a0e908490615c95565b9091555050604080516080810182528954815260018a0154602082015260028a015491810191909152600389015460ff1615156060820152611a53908e908b906137f7565b611a6d565b611a6b818588898d6060015160056132c8565b505b5080611a7881615cda565b915050611989565b508a7fef2d6e0b68eee68a522999443f2c077264967f8dec5d69a61161668da51663f58d604051611ab19190615d34565b60405180910390a250505050505050505050611ace600161016b55565b5050565b600080826000611af7826000908152606760205260409020546001600160a01b031690565b90506001600160a01b038116611b2357604051637e27328960e01b815260048101839052602401610cdf565b5050506000918252506101706020526040902060018101546002909101549091565b60008080611b5284611e94565b9050600081603211611b65576032611b67565b815b905060005b81811015611c55576000611b8087836111ee565b60405163f83bb31360e01b815260fe60048201526024810182905290915060009073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af4158015611bdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c019190615c62565b90506001600160a01b038616611c1957809550611c40565b806001600160a01b0316866001600160a01b031614611c4057506001979650505050505050565b50508080611c4d90615cda565b915050611b6c565b5091949350505050565b61151f3382613c4e565b611c9660405180608001604052806000815260200160008152602001600081526020016000151581525090565b506000908152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff161515606082015290565b6000818152606760205260408120546001600160a01b031680610be95760405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610cdf565b600080611d5283611ce1565b9050806001600160a01b0316846001600160a01b03161480611d9957506001600160a01b03808216600090815260cb602090815260408083209388168352929052205460ff165b80610f8e5750600083815260ca60205260409020546001600160a01b0380861691165b6001600160a01b031614949350505050565b60408051606081018252600080825260208201819052918101919091526040517fe680a31000000000000000000000000000000000000000000000000000000000815260fe6004820152602481018490526044810183905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063e680a31090606401608060405180830381865af4158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190615d5e565b915091509250929050565b60006001600160a01b038216611f125760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152608401610cdf565b506001600160a01b031660009081526068602052604090205490565b611f3661326d565b6040517fd7ac26da00000000000000000000000000000000000000000000000000000000815260fe60048201526001600160a01b038216602482015273a615388bd2f920ee2fec7606f26908b454f0c2499063d7ac26da90604401608060405180830381865af4158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd29190615d5e565b505061151f600161016b55565b60008181526067602052604081205482906001600160a01b03168061201a57604051637e27328960e01b815260048101839052602401610cdf565b61202384612f9e565b600085815261017060205260409020545b610f8e9190615cc3565b600060608060008060006060610137546000801b148015612060575061013854155b6120ac5760405162461bcd60e51b815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606401610cdf565b6120b4613e37565b6120bc613e47565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b60008181526067602052604081205482906001600160a01b03168061213d57604051637e27328960e01b815260048101839052602401610cdf565b505050600090815260c9602052604090205490565b60008181526067602052604081205482906001600160a01b03168061218d57604051637e27328960e01b815260048101839052602401610cdf565b61016c546001600160a01b0316610f8e565b600073a615388bd2f920ee2fec7606f26908b454f0c2496334e78a9e60fe6121c68561353e565b6040516001600160e01b031960e085901b168152600481019290925265ffffffffffff1660248201526044015b602060405180830381865af4158015612210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be99190615c49565b606060668054610bfe90615be0565b600073a615388bd2f920ee2fec7606f26908b454f0c24963f8183ecf60fe8461226b4261353e565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015265ffffffffffff1660448201526064016121f3565b60008181526067602052604081205482906001600160a01b0316806122e757604051637e27328960e01b815260048101839052602401610cdf565b600084815260c9602052604090205461203485612f9e565b61230761326d565b60008381526067602052604090205483906001600160a01b03168061234257604051637e27328960e01b815260048101839052602401610cdf565b3361234e82828561318c565b61237d5760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000868152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615801560608301526123e2576040516334d10f9560e11b815260040160405180910390fd5b600085612476576123f661056b8842615c95565b65ffffffffffff16905042826040015111612424576040516307b7d7dd60e51b815260040160405180910390fd5b8160400151811161244857604051638e6b5b6760e01b815260040160405180910390fd5b610104546124569042615c95565b8111156124765760405163f761f1cd60e01b815260040160405180910390fd5b61248688600083858a6003613e57565b60408051828152871515602082015289917fa239317f70ee4cfafe56d2bc53cac05379afea1286f6088d963d7a02da99a75d910160405180910390a25050505050610f63600161016b55565b611ace338383614012565b6124e561326d565b8060000361250657604051631f2a200560e01b815260040160405180910390fd5b60008281526101706020908152604080832081516080810183528154815260018201548185015260028201548184015260039091015460ff16151560608201528584526067909252909120546001600160a01b0316612591576040517ff90e998d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160400151111580156125a757508060600151155b156125c5576040516307b7d7dd60e51b815260040160405180910390fd5b6125d9838360008485606001516002613e57565b50611ace600161016b55565b6125ef3383613585565b6126515760405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608401610cdf565b61265d848484846140e0565b50505050565b6110be61102f565b60405162461bcd60e51b815260206004820152601760248201527f64656c656761746542795369673a2073697a65206375740000000000000000006044820152606401610cdf565b60008181526067602052604090205460609082906001600160a01b0316806126f157604051637e27328960e01b815260048101839052602401610cdf565b6000848152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff161515606082015261016e546001600160a01b031663dd9ec1498661275481613071565b604080860151865191516001600160e01b031960e087901b1681526127949493929060040193845260208401929092526040830152606082015260800190565b600060405180830381865afa1580156127b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f79190810190615de5565b60008181526067602052604090205481906001600160a01b03168061281457604051637e27328960e01b815260048101839052602401610cdf565b61281e858461415e565b82856001600160a01b0316336001600160a01b03167fb688daf266707251b810cde26b1bedfbbc6aa98cfc5667ea84fc354483e2ac8e87604051612866911515815260200190565b60405180910390a45050505050565b61287d61326d565b60008281526067602052604090205482906001600160a01b0316806128b857604051637e27328960e01b815260048101839052602401610cdf565b336128c482828561318c565b6128f35760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b60008481526067602052604090205484906001600160a01b03168061292e57604051637e27328960e01b815260048101839052602401610cdf565b3361293a82828561318c565b6129695760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b8688036129a2576040517f93b50ef200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600087815261017060209081526040808320815160808101835281548082526001830154948201949094526002820154928101929092526003015460ff16151560608201529103612a0657604051631f2a200560e01b815260040160405180910390fd5b42816040015111158015612a1c57508060600151155b15612a3a576040516307b7d7dd60e51b815260040160405180910390fd5b600089815261017060209081526040808320815160808101835281548082526001830154948201949094526002820154928101929092526003015460ff16151560608201529103612a9e57604051631f2a200560e01b815260040160405180910390fd5b606081015115156001148015612ac05750816060015115158160600151151514155b15612af7576040517f67fd3ad900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826040015182604001511015612b13578260400151612b19565b81604001515b60008c81526101706020908152604080832083815581516080810183529384526001810154928401929092526002820154908301526003015460ff1615156060820152909150612b6c908c9084906137f7565b612b9960405180608001604052806000815260200160008152602001600081526020016000151581525090565b82518451612ba79190615c95565b81526060808501511515908201819052612bc357604081018290525b612bce8b85836137f7565b60008b8152610170602090815260409182902083518082558483015160018301558484015160028301556060808601516003909301805460ff191693151593841790558451918252928101869052928301528c918e917fec3b82c6fa54397270e9474a17cd38c92b766ae2b2541f87715357ac7ddd48e0910160405180910390a350505050505050505050611ace600161016b55565b6000612c6e61326d565b612c7d848433338660016132c8565b90506111e7600161016b55565b600054610100900460ff1615808015612caa5750600054600160ff909116105b80612cc45750303b158015612cc4575060005460ff166001145b612d365760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610cdf565b6000805460ff191660011790558015612d59576000805461ff0019166101001790555b612d6386866141fd565b612d6d8685614328565b61016c80546001600160a01b038086166001600160a01b03199283161790925561016e8054928516929091169190911790556303c26700610104558015612dee576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008281526067602052604081205483906001600160a01b031680612e3157604051637e27328960e01b815260048101839052602401610cdf565b600085815261017060205260409020600201548410612e6157600085815261017060205260409020549250612e66565b600092505b505092915050565b60606000612e7b83611e94565b905060008167ffffffffffffffff811115612e9857612e986156fb565b604051908082528060200260200182016040528015612ec1578160200160208202803683370190505b50905060005b82811015612f96576000612edb86836111ee565b60405163f83bb31360e01b815260fe60048201526024810182905290915073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af4158015612f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f599190615c62565b838381518110612f6b57612f6b615cad565b6001600160a01b03909216602092830291909101909101525080612f8e81615cda565b915050612ec7565b509392505050565b6000610be98242612df6565b604051633d003cf160e21b815260fe6004820152602481018390526044810182905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f400f3c490606401611590565b60405163f83bb31360e01b815260fe60048201526024810182905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af415801561304d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be99190615c62565b604051633d003cf160e21b815260fe60048201526024810182905242604482015260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f400f3c4906064016121f3565b60408051606081018252600080825260208201819052918101829052906130e160fe8461439d565b91509150915091565b60006001600160e01b031982167fbd3a202b000000000000000000000000000000000000000000000000000000001480610be95750610be9826143e4565b6000818152606760205260409020546001600160a01b031661151f5760405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610cdf565b60006001600160a01b03831615801590610f8e5750826001600160a01b0316846001600160a01b031614806131e657506001600160a01b038085166000908152606a602090815260408083209387168352929052205460ff165b80610f8e5750826001600160a01b0316611dbc83610c81565b600081815260696020526040902080546001600160a01b0319166001600160a01b038416908117909155819061323482611ce1565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600261016b54036132c05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cdf565b600261016b55565b6000866000036132eb57604051631f2a200560e01b815260040160405180910390fd5b6101718054600091826132fd83615cda565b909155505061017154846133705761331861056b8942615c95565b65ffffffffffff16915042821161334257604051638e6b5b6760e01b815260040160405180910390fd5b610104546133509042615c95565b8211156133705760405163f761f1cd60e01b815260040160405180910390fd5b61337a8782614422565b6000818152610170602090815260409182902042600182018190558351608081018552825481529283015260028101549282019290925260039091015460ff16151560608201526133d29082908b9085908989613e57565b604051639bdd2e4d60e01b815260fe6004820152602481018290526001600160a01b03871660448201526064810183905273a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af415801561343e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134629190615c1a565b5050604080518a8152602081018490528615158183015290516001600160a01b0388169183917f551141c76a3b7e9a59ed1e32ccc940d667b98cfd98931126e89f1a17838f43519181900360600190a36040516001600160a01b03808816916000918a16907f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f908390a4604051600081526001600160a01b03808816919089169083907f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e9060200160405180910390a498975050505050505050565b600065ffffffffffff821115613567576040516393dafdf160e01b815260040160405180910390fd5b5090565b600062093a8061357b8184615d12565b610be99190615cf3565b60008061359183611ce1565b9050806001600160a01b0316846001600160a01b031614806135d857506001600160a01b038082166000908152606a602090815260408083209388168352929052205460ff165b80610f8e5750836001600160a01b0316611dbc84610c81565b826001600160a01b031661360482611ce1565b6001600160a01b0316146136685760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610cdf565b6001600160a01b0382166136e35760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610cdf565b6136f0838383600161443c565b826001600160a01b031661370382611ce1565b6001600160a01b0316146137675760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610cdf565b600081815260696020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260688552838620805460001901905590871680865283862080546001019055868652606790945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60fe73a615388bd2f920ee2fec7606f26908b454f0c249634cd2605690918561382386600001516145d2565b855161382e906145d2565b6040808901518882015191516001600160e01b031960e089901b16815260048101969096526024860194909452600f92830b6044860152910b6064840152608483019190915260a482015260c40160006040518083038186803b15801561389457600080fd5b505af41580156138a8573d6000803e3d6000fd5b50505050505050565b60008181526067602052604090205481906001600160a01b0316806138ec57604051637e27328960e01b815260048101839052602401610cdf565b6138f461326d565b60008381526067602052604090205483906001600160a01b03168061392f57604051637e27328960e01b815260048101839052602401610cdf565b3361393b82828561318c565b61396a5760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000868152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615801560608301526139cf576040516334d10f9560e11b815260040160405180910390fd5b60006139da886122ac565b905080600003613a16576040517f6855a80200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160808101825260008082526020808301828152838501838152606085018481528e8552610170909352948320935184555160018401559251600283015591516003909101805460ff191691151591909117905561016d805491839190613a808385615cc3565b90915550506000898152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615156060820152613ad9908a9085906137f7565b60405182815233908a907fe97cee5a4c0549d3fdc81e322b718ddf0aeb3418ec87dce4f9a7fb28d117c3129060200160405180910390a3600089815260c9602052604081208054849290613b2e908490615c95565b90915550613b5c90503383613b4c61016c546001600160a01b031690565b6001600160a01b03169190614605565b61016d546040805183815260208101929092527f313edf9a07fc8449830af260b03eb5d8ffd3e7fc45a0c71cc26775972a4669a3910160405180910390a1505050505050610f63600161016b55565b6000613bb682611ce1565b9050613bc681600084600161443c565b613bcf82611ce1565b600083815260696020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526068845282852080546000190190558785526067909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b613c5661326d565b6000613c6183611e94565b90506000805b82811015613ddf576000613c7b86836111ee565b60008181526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018490526001600160a01b0389166044820152606481019190915291925090819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af4158015613d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d259190615c1a565b91509150806001600160a01b0316886001600160a01b0316847f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e85604051613d7c91906001600160a01b0391909116815260200190565b60405180910390a46001600160a01b038516613d9a57819450613dc9565b6001600160a01b038516600114613dc957816001600160a01b0316856001600160a01b031614613dc957600194505b5050508080613dd790615cda565b915050613c67565b50826001600160a01b0316816001600160a01b0316856001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a45050611ace600161016b55565b60606101398054610bfe90615be0565b606061013a8054610bfe90615be0565b61016d80549086906000613e6b8385615c95565b9091555050604080516080810182526000808252602080830182815283850183815260608086019485528a51938b0151968b0151908b01511515909452929092529290528181529087908290613ec2908390615c95565b9052508515801590613ed2575083155b15613edf57604081018690525b8315613ef45760006040820152600160608201525b60008881526101706020908152604091829020835181558382015160018201558383015160028201556060808501516003909201805460ff19169215159290921790915582518a81529182018990528615158284015291518a927fca0c517aab9ec63932670fd23484369811c8412142cc2535c9f78f008ecd0ce1928290030190a2613f818886836137f7565b8615801590613fa257506005836005811115613f9f57613f9f615e53565b14155b15613fc057613fc03361016c546001600160a01b031690308a614696565b61016d547f313edf9a07fc8449830af260b03eb5d8ffd3e7fc45a0c71cc26775972a4669a390613ff08985615c95565b6040805192835260208301919091520160405180910390a15050505050505050565b816001600160a01b0316836001600160a01b0316036140735760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610cdf565b6001600160a01b038381166000818152606a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6140eb8484846135f1565b6140f7848484846146e7565b61265d5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b3361416882611ce1565b6001600160a01b0316146141cf57338161418183611ce1565b6040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015260248101929092529091166044820152606401610cdf565b600090815260ca6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff161580801561421d5750600054600160ff909116105b806142375750303b158015614237575060005460ff166001145b6142a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610cdf565b6000805460ff1916600117905580156142cc576000805461ff0019166101001790555b6142d68383614830565b6142de6148a5565b8015610f63576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b600054610100900460ff166143935760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b611ace8282614910565b604080516060810182526000808252602082018190529181019190915260008281526002840160205260408120819081906143d7906149b5565b9890975095505050505050565b60006001600160e01b031982167f780e9d63000000000000000000000000000000000000000000000000000000001480610be95750610be982614aa7565b611ace828260405180602001604052806000815250614b42565b61444884848484614bc0565b60005b818110156145cb57600061445f8285615c95565b9050846001600160a01b0316866001600160a01b0316146145b85760008181526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018490526001600160a01b03881660448201526064810191909152819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af41580156144fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145209190615c1a565b91509150806001600160a01b0316826001600160a01b0316886001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a46040516001600160a01b038381168252808316919089169085907f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e9060200160405180910390a450505b50806145c381615cda565b91505061444b565b5050505050565b60006f7fffffffffffffffffffffffffffffff821115613567576040516393dafdf160e01b815260040160405180910390fd5b6040516001600160a01b038316602482015260448101829052610f639084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614c43565b6040516001600160a01b038085166024830152831660448201526064810182905261265d9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161464a565b60006001600160a01b0384163b1561482857604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061472b903390899088908890600401615e69565b6020604051808303816000875af1925050508015614766575060408051601f3d908101601f1916820190925261476391810190615ea5565b60015b61480e573d808015614794576040519150601f19603f3d011682016040523d82523d6000602084013e614799565b606091505b5080516000036148065760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610f8e565b506001610f8e565b600054610100900460ff1661489b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b611ace8282614d2b565b600054610100900460ff166110be5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b600054610100900460ff1661497b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b815161498f906101399060208501906153e4565b5080516149a49061013a9060208401906153e4565b505060006101378190556101385550565b60408051606081018252600080825260208201819052918101829052819083546000819003614a2557600080614a19604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b93509350935050614aa0565b6000614a318682614dbd565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452700100000000000000000000000000000000909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250614aa0915050565b9193909250565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480614b0a57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610be957507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610be9565b614b4c8383614de7565b614b5960008484846146e7565b610f635760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b614bcc84848484614f80565b60005b818110156145cb576000614be38285615c95565b90506001600160a01b038616151580614c0e5750846001600160a01b0316866001600160a01b031614155b15614c3057600081815260ca6020526040902080546001600160a01b03191690555b5080614c3b81615cda565b915050614bcf565b6000614c98826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150b59092919063ffffffff16565b9050805160001480614cb9575080806020019051810190614cb99190615ec2565b610f635760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610cdf565b600054610100900460ff16614d965760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b8151614da99060659060208501906153e4565b508051610f639060669060208401906153e4565b6000828281548110614dd157614dd1615cad565b9060005260206000209060030201905092915050565b6001600160a01b038216614e3d5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610cdf565b6000818152606760205260409020546001600160a01b031615614ea25760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610cdf565b614eb060008383600161443c565b6000818152606760205260409020546001600160a01b031615614f155760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610cdf565b6001600160a01b038216600081815260686020908152604080832080546001019055848352606790915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115614ff75760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e736563757469766520747260448201527f616e7366657273206e6f7420737570706f7274656400000000000000000000006064820152608401610cdf565b816001600160a01b0385166150535761504e81609980546000838152609a60205260408120829055600182018355919091527f72a152ddfb8e864297c917af52ea6c1c68aead0fee1a62673fcc7e0c94979d000155565b615076565b836001600160a01b0316856001600160a01b0316146150765761507685826150c4565b6001600160a01b0384166150925761508d81615161565b6145cb565b846001600160a01b0316846001600160a01b0316146145cb576145cb8482615210565b6060610f8e8484600085615254565b600060016150d184611e94565b6150db9190615cc3565b60008381526098602052604090205490915080821461512e576001600160a01b03841660009081526097602090815260408083208584528252808320548484528184208190558352609890915290208190555b5060009182526098602090815260408084208490556001600160a01b039094168352609781528383209183525290812055565b60995460009061517390600190615cc3565b6000838152609a60205260408120546099805493945090928490811061519b5761519b615cad565b9060005260206000200154905080609983815481106151bc576151bc615cad565b6000918252602080832090910192909255828152609a909152604080822084905585825281205560998054806151f4576151f4615edf565b6001900381819060005260206000200160009055905550505050565b600061521b83611e94565b6001600160a01b039093166000908152609760209081526040808320868452825280832085905593825260989052919091209190915550565b6060824710156152cc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610cdf565b600080866001600160a01b031685876040516152e89190615ef5565b60006040518083038185875af1925050503d8060008114615325576040519150601f19603f3d011682016040523d82523d6000602084013e61532a565b606091505b509150915061533b87838387615346565b979650505050505050565b606083156153b55782516000036153ae576001600160a01b0385163b6153ae5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cdf565b5081610f8e565b610f8e83838151156153ca5781518083602001fd5b8060405162461bcd60e51b8152600401610cdf91906154ff565b8280546153f090615be0565b90600052602060002090601f0160209004810192826154125760008555615458565b82601f1061542b57805160ff1916838001178555615458565b82800160010185558215615458579182015b8281111561545857825182559160200191906001019061543d565b506135679291505b808211156135675760008155600101615460565b6001600160e01b03198116811461151f57600080fd5b60006020828403121561549c57600080fd5b81356111e781615474565b60005b838110156154c25781810151838201526020016154aa565b8381111561265d5750506000910152565b600081518084526154eb8160208601602086016154a7565b601f01601f19169290920160200192915050565b6020815260006111e760208301846154d3565b60006020828403121561552457600080fd5b5035919050565b6001600160a01b038116811461151f57600080fd5b6000806040838503121561555357600080fd5b8235915060208301356155658161552b565b809150509250929050565b6000806040838503121561558357600080fd5b823561558e8161552b565b946020939093013593505050565b801515811461151f57600080fd5b600080600080608085870312156155c057600080fd5b843593506020850135925060408501356155d98161552b565b915060608501356155e98161559c565b939692955090935050565b60008060006060848603121561560957600080fd5b83356156148161552b565b925060208401356156248161552b565b929592945050506040919091013590565b65ffffffffffff8116811461151f57600080fd5b6000806040838503121561565c57600080fd5b82359150602083013561556581615635565b6000806040838503121561568157600080fd5b823561568c8161552b565b915060208301356155658161559c565b600080600080600060a086880312156156b457600080fd5b853594506020860135935060408601356156cd8161552b565b925060608601356156dd8161552b565b915060808601356156ed8161559c565b809150509295509295909350565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561573a5761573a6156fb565b604052919050565b6000806040838503121561575557600080fd5b823567ffffffffffffffff8082111561576d57600080fd5b818501915085601f83011261578157600080fd5b8135602082821115615795576157956156fb565b8160051b92506157a6818401615711565b82815292840181019281810190898511156157c057600080fd5b948201945b848610156157de578535825294820194908201906157c5565b9997909101359750505050505050565b60006020828403121561580057600080fd5b81356111e78161552b565b6000806040838503121561581e57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561585d57815187529582019590820190600101615841565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e0602082015260006158a360e08301896154d3565b82810360408401526158b581896154d3565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526158e4818561582d565b9a9950505050505050505050565b60008060006060848603121561590757600080fd5b833592506020840135915060408401356159208161559c565b809150509250925092565b6000806040838503121561593e57600080fd5b82356159498161552b565b915060208301356155658161552b565b600067ffffffffffffffff821115615973576159736156fb565b50601f01601f191660200190565b600061599461598f84615959565b615711565b90508281528383830111156159a857600080fd5b828260208301376000602084830101529392505050565b600080600080608085870312156159d557600080fd5b84356159e08161552b565b935060208501356159f08161552b565b925060408501359150606085013567ffffffffffffffff811115615a1357600080fd5b8501601f81018713615a2457600080fd5b615a3387823560208401615981565b91505092959194509250565b60008060008060008060c08789031215615a5857600080fd5b8635615a638161552b565b95506020870135945060408701359350606087013560ff81168114615a8757600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215615ab657600080fd5b8335615ac18161552b565b925060208401356156248161559c565b600082601f830112615ae257600080fd5b6111e783833560208501615981565b600080600080600060a08688031215615b0957600080fd5b853567ffffffffffffffff80821115615b2157600080fd5b615b2d89838a01615ad1565b96506020880135915080821115615b4357600080fd5b615b4f89838a01615ad1565b95506040880135915080821115615b6557600080fd5b50615b7288828901615ad1565b9350506060860135615b838161552b565b915060808601356156ed8161552b565b6020808252825182820181905260009190848201906040850190845b81811015615bd45783516001600160a01b031683529284019291840191600101615baf565b50909695505050505050565b600181811c90821680615bf457607f821691505b602082108103615c1457634e487b7160e01b600052602260045260246000fd5b50919050565b60008060408385031215615c2d57600080fd5b8251615c388161552b565b60208401519092506155658161552b565b600060208284031215615c5b57600080fd5b5051919050565b600060208284031215615c7457600080fd5b81516111e78161552b565b634e487b7160e01b600052601160045260246000fd5b60008219821115615ca857615ca8615c7f565b500190565b634e487b7160e01b600052603260045260246000fd5b600082821015615cd557615cd5615c7f565b500390565b600060018201615cec57615cec615c7f565b5060010190565b6000816000190483118215151615615d0d57615d0d615c7f565b500290565b600082615d2f57634e487b7160e01b600052601260045260246000fd5b500490565b6020815260006111e7602083018461582d565b8051600f81900b8114615d5957600080fd5b919050565b6000808284036080811215615d7257600080fd5b6060811215615d8057600080fd5b506040516060810181811067ffffffffffffffff82111715615da457615da46156fb565b604052615db084615d47565b8152615dbe60208501615d47565b6020820152615dcf60408501615d47565b6040820152606084015190925061556581615635565b600060208284031215615df757600080fd5b815167ffffffffffffffff811115615e0e57600080fd5b8201601f81018413615e1f57600080fd5b8051615e2d61598f82615959565b818152856020838501011115615e4257600080fd5b6115f78260208301602086016154a7565b634e487b7160e01b600052602160045260246000fd5b60006001600160a01b03808716835280861660208401525083604083015260806060830152615e9b60808301846154d3565b9695505050505050565b600060208284031215615eb757600080fd5b81516111e781615474565b600060208284031215615ed457600080fd5b81516111e78161559c565b634e487b7160e01b600052603160045260246000fd5b60008251615f078184602087016154a7565b919091019291505056fea26469706673582212207c41d260adabcc3ca693a2f348ba09e3532b0220fd8c1572f4a3ac5e149ce61a64736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061048d5760003560e01c80637ecebe001161026b578063c7d7d90f11610150578063db900b9d116100c8578063e7e242d411610097578063ecd0c0c31161007c578063ecd0c0c314610b72578063f778e0a314610b86578063fc0c546a14610b9957600080fd5b8063e7e242d414610b23578063e985e9c514610b3657600080fd5b8063db900b9d14610ac3578063e0514aba14610ad6578063e58ee17d14610ae9578063e7a324dc14610afc57600080fd5b8063d1c2babb1161011f578063d6d0faee11610104578063d6d0faee14610a7d578063d744515f14610a90578063d93aafb514610aa357600080fd5b8063d1c2babb14610a57578063d60371a714610a6a57600080fd5b8063c7d7d90f1461099c578063c87b56dd146109f7578063cae57c8914610a0a578063d113cfba14610a4457600080fd5b80639e0bd808116101e3578063b2383e55116101b2578063bb7cfce211610197578063bb7cfce21461094b578063c2c4c5c114610981578063c3cda5201461098957600080fd5b8063b2383e5514610925578063b88d4fde1461093857600080fd5b80639e0bd808146108b05780639f194422146108c3578063a22cb465146108d6578063a2e8a50c146108e957600080fd5b806384e968e61161023a5780638e539e8c1161021f5780638e539e8c1461088257806395d89b41146108955780639ab24eb01461089d57600080fd5b806384e968e61461085c5780638b9cb90b1461086f57600080fd5b80637ecebe00146107e4578063807c35311461080557806381d0526d1461082e57806384b0196e1461084157600080fd5b80633a46b1a811610391578063587cde1e116103095780636bec7397116102d857806370a08231116102bd57806370a08231146107b457806372fbaacb146107c7578063753c7328146107d157600080fd5b80636bec7397146107555780636c423c101461076857600080fd5b8063587cde1e146106d45780635c19a95c146106e757806363185237146106fa5780636352211e1461074257600080fd5b8063430c2081116103605780635594a045116103455780635594a0451461068557806356afe74414610699578063576561d2146106ac57600080fd5b8063430c20811461065f5780634f6ccce71461067257600080fd5b80633a46b1a8146106135780633c340b321461062657806342842e0e1461063957806342966c681461064c57600080fd5b80631ac40e66116104245780632f745c59116103f3578063323418c1116103d8578063323418c1146105da57806335b0f6bd146105ed578063379607f51461060057600080fd5b80632f745c59146105ad578063313ce567146105c057600080fd5b80631ac40e6614610555578063212d18c91461055d57806323b872dd146105875780632b3b09ec1461059a57600080fd5b806308bbb8241161046057806308bbb82414610512578063095ea7b3146105275780630a2abdb31461053a57806318160ddd1461054d57600080fd5b806301ffc9a714610492578063047fc9aa146104ba57806306fdde03146104d2578063081812fc146104e7575b600080fd5b6104a56104a036600461548a565b610bab565b60405190151581526020015b60405180910390f35b6104c461016d5481565b6040519081526020016104b1565b6104da610bef565b6040516104b191906154ff565b6104fa6104f5366004615512565b610c81565b6040516001600160a01b0390911681526020016104b1565b610525610520366004615540565b610ca8565b005b610525610535366004615570565b610e37565b6104c46105483660046155aa565b610f68565b6104c4610f96565b61052561102f565b61057061056b366004615512565b6110c0565b60405165ffffffffffff90911681526020016104b1565b6105256105953660046155f4565b6110cb565b6104fa6105a8366004615649565b611142565b6104c46105bb366004615570565b6111ee565b6105c8601281565b60405160ff90911681526020016104b1565b6105256105e836600461566e565b611296565b6105256105fb366004615512565b61130b565b61052561060e366004615512565b611522565b6104c4610621366004615570565b61152b565b6104c461063436600461569c565b6115d1565b6105256106473660046155f4565b611600565b61052561065a366004615512565b61161b565b6104a561066d366004615570565b6116bb565b6104c4610680366004615512565b6116d0565b61016e546104fa906001600160a01b031681565b6105256106a7366004615742565b611774565b6106bf6106ba366004615512565b611ad2565b604080519283526020830191909152016104b1565b6104fa6106e23660046157ee565b611b45565b6105256106f53660046157ee565b611c5f565b61070d610708366004615512565b611c69565b6040516104b1919081518152602080830151908201526040808301519082015260609182015115159181019190915260800190565b6104fa610750366004615512565b611ce1565b6104a5610763366004615570565b611d46565b61077b61077636600461580b565b611dce565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff1660608201526080016104b1565b6104c46107c23660046157ee565b611e94565b6104c46101715481565b6105256107df3660046157ee565b611f2e565b6104c46107f23660046157ee565b61016f6020526000908152604090205481565b6104fa610813366004615512565b600090815260ca60205260409020546001600160a01b031690565b6104c461083c366004615512565b611fdf565b61084961203e565b6040516104b19796959493929190615868565b6104c461086a366004615512565b612102565b6104fa61087d366004615512565b612152565b6104c4610890366004615512565b61219f565b6104da612234565b6104c46108ab3660046157ee565b612243565b6104c46108be366004615512565b6122ac565b6105256108d13660046158f2565b6122ff565b6105256108e436600461566e565b6124d2565b6104a56108f736600461592b565b6001600160a01b03918216600090815260cb6020908152604080832093909416825291909152205460ff1690565b61052561093336600461580b565b6124dd565b6105256109463660046159bf565b6125e5565b61096e610959366004615512565b600090815260ff6020526040902054600f0b90565b604051600f9190910b81526020016104b1565b610525612663565b610525610997366004615a3f565b61266b565b6109d56109aa366004615512565b6101706020526000908152604090208054600182015460028301546003909301549192909160ff1684565b60408051948552602085019390935291830152151560608201526080016104b1565b6104da610a05366004615512565b6126b3565b61096e610a18366004615570565b6001600160a01b03919091166000908152610103602090815260408083209383529290522054600f0b90565b610525610a52366004615aa1565b6127d9565b610525610a6536600461580b565b612875565b6104c4610a783660046158f2565b612c64565b610525610a8b366004615af1565b612c8a565b6104c4610a9e36600461580b565b612df6565b610ab6610ab13660046157ee565b612e6e565b6040516104b19190615b93565b6104c4610ad1366004615512565b612f9e565b6104c4610ae436600461580b565b612faa565b6104fa610af7366004615512565b612ff3565b6104c47fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b6104c4610b31366004615512565b613071565b6104a5610b4436600461592b565b6001600160a01b039182166000908152606a6020908152604080832093909416825291909152205460ff1690565b61016c546104fa906001600160a01b031681565b61077b610b94366004615512565b6130b9565b61016c546001600160a01b03166104fa565b60006001600160e01b031982167fddf0aba2000000000000000000000000000000000000000000000000000000001480610be95750610be9826130ea565b92915050565b606060658054610bfe90615be0565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2a90615be0565b8015610c775780601f10610c4c57610100808354040283529160200191610c77565b820191906000526020600020905b815481529060010190602001808311610c5a57829003601f168201915b5050505050905090565b6000610c8c82613128565b506000908152606960205260409020546001600160a01b031690565b60008281526067602052604090205482906001600160a01b031680610ce857604051637e27328960e01b8152600481018390526024015b60405180910390fd5b33610cf482828561318c565b610d235760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b60008581526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018890526001600160a01b03871660448201526064810191909152819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af4158015610da5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc99190615c1a565b91509150806001600160a01b0316610dde3390565b6001600160a01b0316887f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e85604051610e2691906001600160a01b0391909116815260200190565b60405180910390a450505050505050565b6000610e4282611ce1565b9050806001600160a01b0316836001600160a01b031603610ecb5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610cdf565b336001600160a01b0382161480610ee75750610ee78133610b44565b610f595760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610cdf565b610f6383836131ff565b505050565b6000610f7261326d565b610f81858585868660016132c8565b9050610f8e600161016b55565b949350505050565b600073a615388bd2f920ee2fec7606f26908b454f0c2496334e78a9e60fe610fbd4261353e565b6040516001600160e01b031960e085901b168152600481019290925265ffffffffffff166024820152604401602060405180830381865af4158015611006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102a9190615c49565b905090565b61103761326d565b6040517f6977e3a900000000000000000000000000000000000000000000000000000000815260fe600482015273a615388bd2f920ee2fec7606f26908b454f0c24990636977e3a99060240160006040518083038186803b15801561109b57600080fd5b505af41580156110af573d6000803e3d6000fd5b505050506110be600161016b55565b565b6000610be98261356b565b6110d53382613585565b6111375760405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608401610cdf565b610f638383836135f1565b6040517f9511aa5300000000000000000000000000000000000000000000000000000000815260fe60048201526024810183905265ffffffffffff8216604482015260009073a615388bd2f920ee2fec7606f26908b454f0c24990639511aa5390606401602060405180830381865af41580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190615c62565b9392505050565b60006111f983611e94565b821061126d5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610cdf565b506001600160a01b03919091166000908152609760209081526040808320938352929052205490565b33600090815260cb602090815260408083206001600160a01b03861684529091529020805460ff191682151517905560405181151581526001600160a01b0383169033907f199acb87f54d9aa34d4c071192d94f5ec4e0b152f52b81209d89085dd7dade7e9060200160405180910390a35050565b61131361326d565b60008181526067602052604090205481906001600160a01b03168061134e57604051637e27328960e01b815260048101839052602401610cdf565b3361135a82828561318c565b6113895760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000848152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff16151560608201819052611408576040517f2188f8ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61141a610104544261056b9190615c95565b65ffffffffffff166040808301919091526000606080840182905287825261017060209081529183902083516080810185528154815260018201549381019390935260028101549383019390935260039092015460ff16151591810191909152611486908690836137f7565b600085815261017060209081526040918290208351815590830151600182015590820151600282015560608201516003909101805460ff1916911515919091179055336001600160a01b0316857f7fbde6b5a06f47dab128f45cea79f339e710e4f5d9e5cda522585afe7b30539b836040015160405161150891815260200190565b60405180910390a35050505061151f600161016b55565b50565b61151f816138b1565b600073a615388bd2f920ee2fec7606f26908b454f0c24963f8183ecf60fe856115538661353e565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015265ffffffffffff1660448201526064015b602060405180830381865af41580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190615c49565b60006115db61326d565b6115ea868686868660016132c8565b90506115f7600161016b55565b95945050505050565b610f63838383604051806020016040528060008152506125e5565b6000818152606760205260409020546001600160a01b0316331461166b576040517f8e5693a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526101706020526040902054156116b2576040517f61442e5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61151f81613bab565b60006111e76116c983611ce1565b848461318c565b60006116db60995490565b821061174f5760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610cdf565b6099828154811061176257611762615cad565b90600052602060002001549050919050565b61177c61326d565b60008181526067602052604090205481906001600160a01b0316806117b757604051637e27328960e01b815260048101839052602401610cdf565b336117c382828561318c565b6117f25760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000848152610170602081815260408084208151608081018352815481526001820154818501526002820154928101928352600382015460ff16151560608201529489905292909152514290811080159061184f57508260600151155b1561186d576040516307b7d7dd60e51b815260040160405180910390fd5b8251158061187c575060028851105b1561189a57604051631f2a200560e01b815260040160405180910390fd5b825161016d80546000906118af908490615cc3565b90915550506000878152606760205260408120546001600160a01b031690805b8a51811015611911578a81815181106118ea576118ea615cad565b6020026020010151826118fd9190615c95565b91508061190981615cda565b9150506118cf565b508060000361194c576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000856060015161197e5783866040015111611969576000611981565b8386604001516119799190615cc3565b611981565b60005b865190915060005b8c51811015611a80576000848e83815181106119a7576119a7615cad565b60200260200101518a600001516119be9190615cf3565b6119c89190615d12565b905060018e516119d89190615cc3565b82036119e15750815b6119eb8184615cc3565b925081600003611a585780885561016d8054829190600090611a0e908490615c95565b9091555050604080516080810182528954815260018a0154602082015260028a015491810191909152600389015460ff1615156060820152611a53908e908b906137f7565b611a6d565b611a6b818588898d6060015160056132c8565b505b5080611a7881615cda565b915050611989565b508a7fef2d6e0b68eee68a522999443f2c077264967f8dec5d69a61161668da51663f58d604051611ab19190615d34565b60405180910390a250505050505050505050611ace600161016b55565b5050565b600080826000611af7826000908152606760205260409020546001600160a01b031690565b90506001600160a01b038116611b2357604051637e27328960e01b815260048101839052602401610cdf565b5050506000918252506101706020526040902060018101546002909101549091565b60008080611b5284611e94565b9050600081603211611b65576032611b67565b815b905060005b81811015611c55576000611b8087836111ee565b60405163f83bb31360e01b815260fe60048201526024810182905290915060009073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af4158015611bdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c019190615c62565b90506001600160a01b038616611c1957809550611c40565b806001600160a01b0316866001600160a01b031614611c4057506001979650505050505050565b50508080611c4d90615cda565b915050611b6c565b5091949350505050565b61151f3382613c4e565b611c9660405180608001604052806000815260200160008152602001600081526020016000151581525090565b506000908152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff161515606082015290565b6000818152606760205260408120546001600160a01b031680610be95760405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610cdf565b600080611d5283611ce1565b9050806001600160a01b0316846001600160a01b03161480611d9957506001600160a01b03808216600090815260cb602090815260408083209388168352929052205460ff165b80610f8e5750600083815260ca60205260409020546001600160a01b0380861691165b6001600160a01b031614949350505050565b60408051606081018252600080825260208201819052918101919091526040517fe680a31000000000000000000000000000000000000000000000000000000000815260fe6004820152602481018490526044810183905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063e680a31090606401608060405180830381865af4158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190615d5e565b915091509250929050565b60006001600160a01b038216611f125760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152608401610cdf565b506001600160a01b031660009081526068602052604090205490565b611f3661326d565b6040517fd7ac26da00000000000000000000000000000000000000000000000000000000815260fe60048201526001600160a01b038216602482015273a615388bd2f920ee2fec7606f26908b454f0c2499063d7ac26da90604401608060405180830381865af4158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd29190615d5e565b505061151f600161016b55565b60008181526067602052604081205482906001600160a01b03168061201a57604051637e27328960e01b815260048101839052602401610cdf565b61202384612f9e565b600085815261017060205260409020545b610f8e9190615cc3565b600060608060008060006060610137546000801b148015612060575061013854155b6120ac5760405162461bcd60e51b815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606401610cdf565b6120b4613e37565b6120bc613e47565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b60008181526067602052604081205482906001600160a01b03168061213d57604051637e27328960e01b815260048101839052602401610cdf565b505050600090815260c9602052604090205490565b60008181526067602052604081205482906001600160a01b03168061218d57604051637e27328960e01b815260048101839052602401610cdf565b61016c546001600160a01b0316610f8e565b600073a615388bd2f920ee2fec7606f26908b454f0c2496334e78a9e60fe6121c68561353e565b6040516001600160e01b031960e085901b168152600481019290925265ffffffffffff1660248201526044015b602060405180830381865af4158015612210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be99190615c49565b606060668054610bfe90615be0565b600073a615388bd2f920ee2fec7606f26908b454f0c24963f8183ecf60fe8461226b4261353e565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015265ffffffffffff1660448201526064016121f3565b60008181526067602052604081205482906001600160a01b0316806122e757604051637e27328960e01b815260048101839052602401610cdf565b600084815260c9602052604090205461203485612f9e565b61230761326d565b60008381526067602052604090205483906001600160a01b03168061234257604051637e27328960e01b815260048101839052602401610cdf565b3361234e82828561318c565b61237d5760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000868152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615801560608301526123e2576040516334d10f9560e11b815260040160405180910390fd5b600085612476576123f661056b8842615c95565b65ffffffffffff16905042826040015111612424576040516307b7d7dd60e51b815260040160405180910390fd5b8160400151811161244857604051638e6b5b6760e01b815260040160405180910390fd5b610104546124569042615c95565b8111156124765760405163f761f1cd60e01b815260040160405180910390fd5b61248688600083858a6003613e57565b60408051828152871515602082015289917fa239317f70ee4cfafe56d2bc53cac05379afea1286f6088d963d7a02da99a75d910160405180910390a25050505050610f63600161016b55565b611ace338383614012565b6124e561326d565b8060000361250657604051631f2a200560e01b815260040160405180910390fd5b60008281526101706020908152604080832081516080810183528154815260018201548185015260028201548184015260039091015460ff16151560608201528584526067909252909120546001600160a01b0316612591576040517ff90e998d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160400151111580156125a757508060600151155b156125c5576040516307b7d7dd60e51b815260040160405180910390fd5b6125d9838360008485606001516002613e57565b50611ace600161016b55565b6125ef3383613585565b6126515760405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608401610cdf565b61265d848484846140e0565b50505050565b6110be61102f565b60405162461bcd60e51b815260206004820152601760248201527f64656c656761746542795369673a2073697a65206375740000000000000000006044820152606401610cdf565b60008181526067602052604090205460609082906001600160a01b0316806126f157604051637e27328960e01b815260048101839052602401610cdf565b6000848152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff161515606082015261016e546001600160a01b031663dd9ec1498661275481613071565b604080860151865191516001600160e01b031960e087901b1681526127949493929060040193845260208401929092526040830152606082015260800190565b600060405180830381865afa1580156127b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f79190810190615de5565b60008181526067602052604090205481906001600160a01b03168061281457604051637e27328960e01b815260048101839052602401610cdf565b61281e858461415e565b82856001600160a01b0316336001600160a01b03167fb688daf266707251b810cde26b1bedfbbc6aa98cfc5667ea84fc354483e2ac8e87604051612866911515815260200190565b60405180910390a45050505050565b61287d61326d565b60008281526067602052604090205482906001600160a01b0316806128b857604051637e27328960e01b815260048101839052602401610cdf565b336128c482828561318c565b6128f35760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b60008481526067602052604090205484906001600160a01b03168061292e57604051637e27328960e01b815260048101839052602401610cdf565b3361293a82828561318c565b6129695760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b8688036129a2576040517f93b50ef200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600087815261017060209081526040808320815160808101835281548082526001830154948201949094526002820154928101929092526003015460ff16151560608201529103612a0657604051631f2a200560e01b815260040160405180910390fd5b42816040015111158015612a1c57508060600151155b15612a3a576040516307b7d7dd60e51b815260040160405180910390fd5b600089815261017060209081526040808320815160808101835281548082526001830154948201949094526002820154928101929092526003015460ff16151560608201529103612a9e57604051631f2a200560e01b815260040160405180910390fd5b606081015115156001148015612ac05750816060015115158160600151151514155b15612af7576040517f67fd3ad900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826040015182604001511015612b13578260400151612b19565b81604001515b60008c81526101706020908152604080832083815581516080810183529384526001810154928401929092526002820154908301526003015460ff1615156060820152909150612b6c908c9084906137f7565b612b9960405180608001604052806000815260200160008152602001600081526020016000151581525090565b82518451612ba79190615c95565b81526060808501511515908201819052612bc357604081018290525b612bce8b85836137f7565b60008b8152610170602090815260409182902083518082558483015160018301558484015160028301556060808601516003909301805460ff191693151593841790558451918252928101869052928301528c918e917fec3b82c6fa54397270e9474a17cd38c92b766ae2b2541f87715357ac7ddd48e0910160405180910390a350505050505050505050611ace600161016b55565b6000612c6e61326d565b612c7d848433338660016132c8565b90506111e7600161016b55565b600054610100900460ff1615808015612caa5750600054600160ff909116105b80612cc45750303b158015612cc4575060005460ff166001145b612d365760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610cdf565b6000805460ff191660011790558015612d59576000805461ff0019166101001790555b612d6386866141fd565b612d6d8685614328565b61016c80546001600160a01b038086166001600160a01b03199283161790925561016e8054928516929091169190911790556303c26700610104558015612dee576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008281526067602052604081205483906001600160a01b031680612e3157604051637e27328960e01b815260048101839052602401610cdf565b600085815261017060205260409020600201548410612e6157600085815261017060205260409020549250612e66565b600092505b505092915050565b60606000612e7b83611e94565b905060008167ffffffffffffffff811115612e9857612e986156fb565b604051908082528060200260200182016040528015612ec1578160200160208202803683370190505b50905060005b82811015612f96576000612edb86836111ee565b60405163f83bb31360e01b815260fe60048201526024810182905290915073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af4158015612f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f599190615c62565b838381518110612f6b57612f6b615cad565b6001600160a01b03909216602092830291909101909101525080612f8e81615cda565b915050612ec7565b509392505050565b6000610be98242612df6565b604051633d003cf160e21b815260fe6004820152602481018390526044810182905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f400f3c490606401611590565b60405163f83bb31360e01b815260fe60048201526024810182905260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f83bb31390604401602060405180830381865af415801561304d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be99190615c62565b604051633d003cf160e21b815260fe60048201526024810182905242604482015260009073a615388bd2f920ee2fec7606f26908b454f0c2499063f400f3c4906064016121f3565b60408051606081018252600080825260208201819052918101829052906130e160fe8461439d565b91509150915091565b60006001600160e01b031982167fbd3a202b000000000000000000000000000000000000000000000000000000001480610be95750610be9826143e4565b6000818152606760205260409020546001600160a01b031661151f5760405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610cdf565b60006001600160a01b03831615801590610f8e5750826001600160a01b0316846001600160a01b031614806131e657506001600160a01b038085166000908152606a602090815260408083209387168352929052205460ff165b80610f8e5750826001600160a01b0316611dbc83610c81565b600081815260696020526040902080546001600160a01b0319166001600160a01b038416908117909155819061323482611ce1565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600261016b54036132c05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cdf565b600261016b55565b6000866000036132eb57604051631f2a200560e01b815260040160405180910390fd5b6101718054600091826132fd83615cda565b909155505061017154846133705761331861056b8942615c95565b65ffffffffffff16915042821161334257604051638e6b5b6760e01b815260040160405180910390fd5b610104546133509042615c95565b8211156133705760405163f761f1cd60e01b815260040160405180910390fd5b61337a8782614422565b6000818152610170602090815260409182902042600182018190558351608081018552825481529283015260028101549282019290925260039091015460ff16151560608201526133d29082908b9085908989613e57565b604051639bdd2e4d60e01b815260fe6004820152602481018290526001600160a01b03871660448201526064810183905273a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af415801561343e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134629190615c1a565b5050604080518a8152602081018490528615158183015290516001600160a01b0388169183917f551141c76a3b7e9a59ed1e32ccc940d667b98cfd98931126e89f1a17838f43519181900360600190a36040516001600160a01b03808816916000918a16907f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f908390a4604051600081526001600160a01b03808816919089169083907f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e9060200160405180910390a498975050505050505050565b600065ffffffffffff821115613567576040516393dafdf160e01b815260040160405180910390fd5b5090565b600062093a8061357b8184615d12565b610be99190615cf3565b60008061359183611ce1565b9050806001600160a01b0316846001600160a01b031614806135d857506001600160a01b038082166000908152606a602090815260408083209388168352929052205460ff165b80610f8e5750836001600160a01b0316611dbc84610c81565b826001600160a01b031661360482611ce1565b6001600160a01b0316146136685760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610cdf565b6001600160a01b0382166136e35760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610cdf565b6136f0838383600161443c565b826001600160a01b031661370382611ce1565b6001600160a01b0316146137675760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610cdf565b600081815260696020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260688552838620805460001901905590871680865283862080546001019055868652606790945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60fe73a615388bd2f920ee2fec7606f26908b454f0c249634cd2605690918561382386600001516145d2565b855161382e906145d2565b6040808901518882015191516001600160e01b031960e089901b16815260048101969096526024860194909452600f92830b6044860152910b6064840152608483019190915260a482015260c40160006040518083038186803b15801561389457600080fd5b505af41580156138a8573d6000803e3d6000fd5b50505050505050565b60008181526067602052604090205481906001600160a01b0316806138ec57604051637e27328960e01b815260048101839052602401610cdf565b6138f461326d565b60008381526067602052604090205483906001600160a01b03168061392f57604051637e27328960e01b815260048101839052602401610cdf565b3361393b82828561318c565b61396a5760405163177e802f60e01b81526001600160a01b038216600482015260248101849052604401610cdf565b6000868152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615801560608301526139cf576040516334d10f9560e11b815260040160405180910390fd5b60006139da886122ac565b905080600003613a16576040517f6855a80200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160808101825260008082526020808301828152838501838152606085018481528e8552610170909352948320935184555160018401559251600283015591516003909101805460ff191691151591909117905561016d805491839190613a808385615cc3565b90915550506000898152610170602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff1615156060820152613ad9908a9085906137f7565b60405182815233908a907fe97cee5a4c0549d3fdc81e322b718ddf0aeb3418ec87dce4f9a7fb28d117c3129060200160405180910390a3600089815260c9602052604081208054849290613b2e908490615c95565b90915550613b5c90503383613b4c61016c546001600160a01b031690565b6001600160a01b03169190614605565b61016d546040805183815260208101929092527f313edf9a07fc8449830af260b03eb5d8ffd3e7fc45a0c71cc26775972a4669a3910160405180910390a1505050505050610f63600161016b55565b6000613bb682611ce1565b9050613bc681600084600161443c565b613bcf82611ce1565b600083815260696020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526068845282852080546000190190558785526067909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b613c5661326d565b6000613c6183611e94565b90506000805b82811015613ddf576000613c7b86836111ee565b60008181526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018490526001600160a01b0389166044820152606481019190915291925090819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af4158015613d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d259190615c1a565b91509150806001600160a01b0316886001600160a01b0316847f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e85604051613d7c91906001600160a01b0391909116815260200190565b60405180910390a46001600160a01b038516613d9a57819450613dc9565b6001600160a01b038516600114613dc957816001600160a01b0316856001600160a01b031614613dc957600194505b5050508080613dd790615cda565b915050613c67565b50826001600160a01b0316816001600160a01b0316856001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a45050611ace600161016b55565b60606101398054610bfe90615be0565b606061013a8054610bfe90615be0565b61016d80549086906000613e6b8385615c95565b9091555050604080516080810182526000808252602080830182815283850183815260608086019485528a51938b0151968b0151908b01511515909452929092529290528181529087908290613ec2908390615c95565b9052508515801590613ed2575083155b15613edf57604081018690525b8315613ef45760006040820152600160608201525b60008881526101706020908152604091829020835181558382015160018201558383015160028201556060808501516003909201805460ff19169215159290921790915582518a81529182018990528615158284015291518a927fca0c517aab9ec63932670fd23484369811c8412142cc2535c9f78f008ecd0ce1928290030190a2613f818886836137f7565b8615801590613fa257506005836005811115613f9f57613f9f615e53565b14155b15613fc057613fc03361016c546001600160a01b031690308a614696565b61016d547f313edf9a07fc8449830af260b03eb5d8ffd3e7fc45a0c71cc26775972a4669a390613ff08985615c95565b6040805192835260208301919091520160405180910390a15050505050505050565b816001600160a01b0316836001600160a01b0316036140735760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610cdf565b6001600160a01b038381166000818152606a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6140eb8484846135f1565b6140f7848484846146e7565b61265d5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b3361416882611ce1565b6001600160a01b0316146141cf57338161418183611ce1565b6040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015260248101929092529091166044820152606401610cdf565b600090815260ca6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff161580801561421d5750600054600160ff909116105b806142375750303b158015614237575060005460ff166001145b6142a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610cdf565b6000805460ff1916600117905580156142cc576000805461ff0019166101001790555b6142d68383614830565b6142de6148a5565b8015610f63576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b600054610100900460ff166143935760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b611ace8282614910565b604080516060810182526000808252602082018190529181019190915260008281526002840160205260408120819081906143d7906149b5565b9890975095505050505050565b60006001600160e01b031982167f780e9d63000000000000000000000000000000000000000000000000000000001480610be95750610be982614aa7565b611ace828260405180602001604052806000815250614b42565b61444884848484614bc0565b60005b818110156145cb57600061445f8285615c95565b9050846001600160a01b0316866001600160a01b0316146145b85760008181526101706020526040808220600201549051639bdd2e4d60e01b815260fe6004820152602481018490526001600160a01b03881660448201526064810191909152819073a615388bd2f920ee2fec7606f26908b454f0c24990639bdd2e4d906084016040805180830381865af41580156144fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145209190615c1a565b91509150806001600160a01b0316826001600160a01b0316886001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a46040516001600160a01b038381168252808316919089169085907f39d7dc46c82aa27d4484a57e21232e5c6f22fe6c7ffc01795304084ba872811e9060200160405180910390a450505b50806145c381615cda565b91505061444b565b5050505050565b60006f7fffffffffffffffffffffffffffffff821115613567576040516393dafdf160e01b815260040160405180910390fd5b6040516001600160a01b038316602482015260448101829052610f639084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614c43565b6040516001600160a01b038085166024830152831660448201526064810182905261265d9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161464a565b60006001600160a01b0384163b1561482857604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061472b903390899088908890600401615e69565b6020604051808303816000875af1925050508015614766575060408051601f3d908101601f1916820190925261476391810190615ea5565b60015b61480e573d808015614794576040519150601f19603f3d011682016040523d82523d6000602084013e614799565b606091505b5080516000036148065760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610f8e565b506001610f8e565b600054610100900460ff1661489b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b611ace8282614d2b565b600054610100900460ff166110be5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b600054610100900460ff1661497b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b815161498f906101399060208501906153e4565b5080516149a49061013a9060208401906153e4565b505060006101378190556101385550565b60408051606081018252600080825260208201819052918101829052819083546000819003614a2557600080614a19604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b93509350935050614aa0565b6000614a318682614dbd565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452700100000000000000000000000000000000909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250614aa0915050565b9193909250565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480614b0a57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610be957507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610be9565b614b4c8383614de7565b614b5960008484846146e7565b610f635760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610cdf565b614bcc84848484614f80565b60005b818110156145cb576000614be38285615c95565b90506001600160a01b038616151580614c0e5750846001600160a01b0316866001600160a01b031614155b15614c3057600081815260ca6020526040902080546001600160a01b03191690555b5080614c3b81615cda565b915050614bcf565b6000614c98826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150b59092919063ffffffff16565b9050805160001480614cb9575080806020019051810190614cb99190615ec2565b610f635760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610cdf565b600054610100900460ff16614d965760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610cdf565b8151614da99060659060208501906153e4565b508051610f639060669060208401906153e4565b6000828281548110614dd157614dd1615cad565b9060005260206000209060030201905092915050565b6001600160a01b038216614e3d5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610cdf565b6000818152606760205260409020546001600160a01b031615614ea25760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610cdf565b614eb060008383600161443c565b6000818152606760205260409020546001600160a01b031615614f155760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610cdf565b6001600160a01b038216600081815260686020908152604080832080546001019055848352606790915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115614ff75760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e736563757469766520747260448201527f616e7366657273206e6f7420737570706f7274656400000000000000000000006064820152608401610cdf565b816001600160a01b0385166150535761504e81609980546000838152609a60205260408120829055600182018355919091527f72a152ddfb8e864297c917af52ea6c1c68aead0fee1a62673fcc7e0c94979d000155565b615076565b836001600160a01b0316856001600160a01b0316146150765761507685826150c4565b6001600160a01b0384166150925761508d81615161565b6145cb565b846001600160a01b0316846001600160a01b0316146145cb576145cb8482615210565b6060610f8e8484600085615254565b600060016150d184611e94565b6150db9190615cc3565b60008381526098602052604090205490915080821461512e576001600160a01b03841660009081526097602090815260408083208584528252808320548484528184208190558352609890915290208190555b5060009182526098602090815260408084208490556001600160a01b039094168352609781528383209183525290812055565b60995460009061517390600190615cc3565b6000838152609a60205260408120546099805493945090928490811061519b5761519b615cad565b9060005260206000200154905080609983815481106151bc576151bc615cad565b6000918252602080832090910192909255828152609a909152604080822084905585825281205560998054806151f4576151f4615edf565b6001900381819060005260206000200160009055905550505050565b600061521b83611e94565b6001600160a01b039093166000908152609760209081526040808320868452825280832085905593825260989052919091209190915550565b6060824710156152cc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610cdf565b600080866001600160a01b031685876040516152e89190615ef5565b60006040518083038185875af1925050503d8060008114615325576040519150601f19603f3d011682016040523d82523d6000602084013e61532a565b606091505b509150915061533b87838387615346565b979650505050505050565b606083156153b55782516000036153ae576001600160a01b0385163b6153ae5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cdf565b5081610f8e565b610f8e83838151156153ca5781518083602001fd5b8060405162461bcd60e51b8152600401610cdf91906154ff565b8280546153f090615be0565b90600052602060002090601f0160209004810192826154125760008555615458565b82601f1061542b57805160ff1916838001178555615458565b82800160010185558215615458579182015b8281111561545857825182559160200191906001019061543d565b506135679291505b808211156135675760008155600101615460565b6001600160e01b03198116811461151f57600080fd5b60006020828403121561549c57600080fd5b81356111e781615474565b60005b838110156154c25781810151838201526020016154aa565b8381111561265d5750506000910152565b600081518084526154eb8160208601602086016154a7565b601f01601f19169290920160200192915050565b6020815260006111e760208301846154d3565b60006020828403121561552457600080fd5b5035919050565b6001600160a01b038116811461151f57600080fd5b6000806040838503121561555357600080fd5b8235915060208301356155658161552b565b809150509250929050565b6000806040838503121561558357600080fd5b823561558e8161552b565b946020939093013593505050565b801515811461151f57600080fd5b600080600080608085870312156155c057600080fd5b843593506020850135925060408501356155d98161552b565b915060608501356155e98161559c565b939692955090935050565b60008060006060848603121561560957600080fd5b83356156148161552b565b925060208401356156248161552b565b929592945050506040919091013590565b65ffffffffffff8116811461151f57600080fd5b6000806040838503121561565c57600080fd5b82359150602083013561556581615635565b6000806040838503121561568157600080fd5b823561568c8161552b565b915060208301356155658161559c565b600080600080600060a086880312156156b457600080fd5b853594506020860135935060408601356156cd8161552b565b925060608601356156dd8161552b565b915060808601356156ed8161559c565b809150509295509295909350565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561573a5761573a6156fb565b604052919050565b6000806040838503121561575557600080fd5b823567ffffffffffffffff8082111561576d57600080fd5b818501915085601f83011261578157600080fd5b8135602082821115615795576157956156fb565b8160051b92506157a6818401615711565b82815292840181019281810190898511156157c057600080fd5b948201945b848610156157de578535825294820194908201906157c5565b9997909101359750505050505050565b60006020828403121561580057600080fd5b81356111e78161552b565b6000806040838503121561581e57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561585d57815187529582019590820190600101615841565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e0602082015260006158a360e08301896154d3565b82810360408401526158b581896154d3565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526158e4818561582d565b9a9950505050505050505050565b60008060006060848603121561590757600080fd5b833592506020840135915060408401356159208161559c565b809150509250925092565b6000806040838503121561593e57600080fd5b82356159498161552b565b915060208301356155658161552b565b600067ffffffffffffffff821115615973576159736156fb565b50601f01601f191660200190565b600061599461598f84615959565b615711565b90508281528383830111156159a857600080fd5b828260208301376000602084830101529392505050565b600080600080608085870312156159d557600080fd5b84356159e08161552b565b935060208501356159f08161552b565b925060408501359150606085013567ffffffffffffffff811115615a1357600080fd5b8501601f81018713615a2457600080fd5b615a3387823560208401615981565b91505092959194509250565b60008060008060008060c08789031215615a5857600080fd5b8635615a638161552b565b95506020870135945060408701359350606087013560ff81168114615a8757600080fd5b9598949750929560808101359460a0909101359350915050565b600080600060608486031215615ab657600080fd5b8335615ac18161552b565b925060208401356156248161559c565b600082601f830112615ae257600080fd5b6111e783833560208501615981565b600080600080600060a08688031215615b0957600080fd5b853567ffffffffffffffff80821115615b2157600080fd5b615b2d89838a01615ad1565b96506020880135915080821115615b4357600080fd5b615b4f89838a01615ad1565b95506040880135915080821115615b6557600080fd5b50615b7288828901615ad1565b9350506060860135615b838161552b565b915060808601356156ed8161552b565b6020808252825182820181905260009190848201906040850190845b81811015615bd45783516001600160a01b031683529284019291840191600101615baf565b50909695505050505050565b600181811c90821680615bf457607f821691505b602082108103615c1457634e487b7160e01b600052602260045260246000fd5b50919050565b60008060408385031215615c2d57600080fd5b8251615c388161552b565b60208401519092506155658161552b565b600060208284031215615c5b57600080fd5b5051919050565b600060208284031215615c7457600080fd5b81516111e78161552b565b634e487b7160e01b600052601160045260246000fd5b60008219821115615ca857615ca8615c7f565b500190565b634e487b7160e01b600052603260045260246000fd5b600082821015615cd557615cd5615c7f565b500390565b600060018201615cec57615cec615c7f565b5060010190565b6000816000190483118215151615615d0d57615d0d615c7f565b500290565b600082615d2f57634e487b7160e01b600052601260045260246000fd5b500490565b6020815260006111e7602083018461582d565b8051600f81900b8114615d5957600080fd5b919050565b6000808284036080811215615d7257600080fd5b6060811215615d8057600080fd5b506040516060810181811067ffffffffffffffff82111715615da457615da46156fb565b604052615db084615d47565b8152615dbe60208501615d47565b6020820152615dcf60408501615d47565b6040820152606084015190925061556581615635565b600060208284031215615df757600080fd5b815167ffffffffffffffff811115615e0e57600080fd5b8201601f81018413615e1f57600080fd5b8051615e2d61598f82615959565b818152856020838501011115615e4257600080fd5b6115f78260208301602086016154a7565b634e487b7160e01b600052602160045260246000fd5b60006001600160a01b03808716835280861660208401525083604083015260806060830152615e9b60808301846154d3565b9695505050505050565b600060208284031215615eb757600080fd5b81516111e781615474565b600060208284031215615ed457600080fd5b81516111e78161559c565b634e487b7160e01b600052603160045260246000fd5b60008251615f078184602087016154a7565b919091019291505056fea26469706673582212207c41d260adabcc3ca693a2f348ba09e3532b0220fd8c1572f4a3ac5e149ce61a64736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.