Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60a06040 | 18482122 | 391 days ago | IN | 0 ETH | 0.08120389 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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:
MemecoinClaim
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IDelegationRegistry} from "contracts/delegation_registry/IDelegationRegistry.sol"; import {IDelegateRegistry} from "contracts/delegation_registry/IDelegateRegistry.sol"; import "./interfaces/IMemecoinClaim.sol"; /// @title A contract for claiming $MEME over a parameterized vesting schedule contract MemecoinClaim is IMemecoinClaim, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable, OwnableUpgradeable { using SafeERC20 for IERC20; uint256 private constant _BASIS_POINTS = 10_000; uint256 private constant _LOCK_UP_SLOT = 180; uint256 private constant _END_CYCLE = 4; uint256 private constant _END_CYCLE_CONTRIBUTORS = 8; uint256 private constant _MAX_CLAIM_PERIOD = 69 days; address public upgrader; // to be set address public multiClaim; // to be set IERC721[] public nftCollections; IDelegationRegistry public dc; IDelegateRegistry public dcV2; uint256 public claimStartDate; IERC20 public claimToken; bool public claimActive; bool public claimTokenDeposited; bool public unclaimedNFTRewardsWithdrawn; bool public upgraderRenounced; uint64 public currentNFTUnlockedBP; uint64 public previousNFTUnlockedBP; uint128 public currentNFTUnlockTimestamp; mapping(address userAddress => mapping(ClaimType claimType => ClaimData userClaimData)) public usersClaimData; mapping(uint256 collectionId => mapping(uint256 tokenId => NFTClaimData userClaimData)) public nftUsersClaimData; mapping(ClaimType claimType => ClaimSchedule claimSchedule) public claimScheduleOf; mapping(uint256 collectionId => UnclaimedNFTRewards) public unclaimedNftRewards; // required by the OZ UUPS module function _authorizeUpgrade(address) internal override onlyUpgrader {} /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address _claimTokenAddress, address _mvpAddress, address _captainzAddress, address _potatozAddress ) external initializer { ReentrancyGuardUpgradeable.__ReentrancyGuard_init_unchained(); OwnableUpgradeable.__Ownable_init_unchained(); UUPSUpgradeable.__UUPSUpgradeable_init(); dc = IDelegationRegistry(0x00000000000076A84feF008CDAbe6409d2FE638B); dcV2 = IDelegateRegistry(0x00000000000000447e69651d841bD8D104Bed493); claimToken = IERC20(_claimTokenAddress); nftCollections = [IERC721(_mvpAddress), IERC721(_captainzAddress), IERC721(_potatozAddress)]; } /// @notice Claim token by claimTypes according to the vesting schedule after claim starts, user won't be able to claim after the allocated $MEME are fully vested for _MAX_CLAIM_PERIOD /// @dev ONLY presaleClaim, ecosystem and contributor contract; Verify claim data and transfer claim token to user if needed, should not be called by NFT holder, /// emit { UserClaimed } event for amount claimed /// @param _vault Vault address of delegate.xyz; pass address(0) if not using delegate wallet /// @param _claimTypes Array of ClaimType to claim function claim(address _vault, ClaimType[] calldata _claimTypes) external nonReentrant onlyValidClaimSetup { address requester = _getRequester(_vault); uint256 totalClaimable = _claim(requester, _claimTypes); claimToken.safeTransfer(requester, totalClaimable); } /// @notice Claim OPTIONALLY on NFTAirdrop/NFTRewards/WalletRewards token by all eligible NFTs according to the vesting schedule after claim starts, user won't be able to claim after the allocated $MEME are fully vested for _MAX_CLAIM_PERIOD /// @dev ONLY nftClaim contract; ONLY related to NFT claimTypes(i.e. NFTRewards & WalletRewards); Verify claim data and transfer claim token to NFT owner if needed, emit { BulkClaimedInNFTs } event for amount claimed /// @param _vault Vault address of delegate.xyz; pass address(0) if not using delegate wallet /// @param _nftCollectionClaimRequests Array of NFTCollectionClaimRequest that consists collection ID of the NFT, token ID(s) the owner owns, array of booleans to indicate NFTAirdrop/NFTRewards claim for each token ID function claimInNFTs( address _vault, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests, bool _withWalletRewards ) external nonReentrant onlyValidClaimSetup { address requester = _getRequester(_vault); uint256 totalClaimable = _claimInNFTs(requester, _nftCollectionClaimRequests, _withWalletRewards); claimToken.safeTransfer(requester, totalClaimable); } // =================== // Multicall Functions // =================== /// @notice Claim token by claimTypes according to the vesting schedule after claim starts /// @dev Verify caller is multiClaim, claim data and transfer claim token to _requester if needed, should not be called by NFT holder /// emit { UserClaimed } event for amount claimed /// @param _requester address of eligible claim wallet /// @param _claimTypes Array of ClaimType to claim function claimFromMulti(address _requester, ClaimType[] calldata _claimTypes) external nonReentrant onlyValidClaimSetup onlyMultiClaim { uint256 totalClaimable = _claim(_requester, _claimTypes); claimToken.safeTransfer(_requester, totalClaimable); } /// @notice Bulk claim token by claimTypes and eligible NFTs according to the vesting schedule after claim starts /// @dev Verify caller is multiClaim, claim data and transfer claim token to NFT owner if needed, emit { BulkClaimedInNFTs } event for amount claimed /// @param _requester address of eligible holder wallet /// @param _nftCollectionClaimRequests Array of NFTCollectionClaimRequest that consists collection ID of the NFT, token ID(s) the owner owns, array of booleans to indicate NFTAirdrop/NFTRewards claim for each token ID function claimInNFTsFromMulti( address _requester, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests, bool _withWalletRewards ) external nonReentrant onlyValidClaimSetup onlyMultiClaim { uint256 totalClaimable = _claimInNFTs(_requester, _nftCollectionClaimRequests, _withWalletRewards); claimToken.safeTransfer(_requester, totalClaimable); } /// @notice Support both v1 and v2 delegate wallet during the v1 to v2 migration /// @dev Given _vault (cold wallet) address, verify whether _msgSender() is a permitted delegate to operate on behalf of it /// @param _vault Address to verify against _msgSender function _getRequester(address _vault) private view returns (address) { if (_vault == address(0)) return _msgSender(); bool isDelegateValid = dcV2.checkDelegateForAll(_msgSender(), _vault, ""); if (isDelegateValid) return _vault; isDelegateValid = dc.checkDelegateForAll(_msgSender(), _vault); if (!isDelegateValid) revert InvalidDelegate(); return _vault; } function _claim(address _requester, ClaimType[] memory _claimTypes) internal returns (uint128 amountClaimed) { amountClaimed = _executeClaim(_requester, _claimTypes); if (amountClaimed == 0) revert NoClaimableToken(); emit UserClaimed(_requester, amountClaimed, block.timestamp); } function _claimInNFTs( address _requester, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests, bool _withWalletRewards ) internal returns (uint128 amountClaimed) { amountClaimed = _executeClaimInNFTs(_requester, _nftCollectionClaimRequests); if (_withWalletRewards) { ClaimData storage userClaimData = usersClaimData[_requester][ClaimType.WalletRewards]; uint128 claimable = _calculateClaimable(userClaimData, ClaimType.WalletRewards); if (claimable > 0) { /// @dev assume no overflow as the max amountClaimed amount won't exceed uint128 throughout the whole life cycle unchecked { userClaimData.claimed += claimable; amountClaimed += claimable; } } } if (amountClaimed == 0) revert NoClaimableToken(); emit ClaimedInNFTs(_requester, amountClaimed, block.timestamp); } /// @dev Update `claimed` in usersClaimData for the given ClaimTypes /// @param _requester Address of the claimer /// @param _claimTypes Array of ClaimType to claim /// @return totalClaimable Amount of total claimable calculated from the given ClaimTypes function _executeClaim(address _requester, ClaimType[] memory _claimTypes) private returns (uint128 totalClaimable) { for (uint256 i; i < _claimTypes.length; i++) { ClaimData storage userClaimData = usersClaimData[_requester][_claimTypes[i]]; uint128 claimable = _calculateClaimable(userClaimData, _claimTypes[i]); if (claimable > 0) { /// @dev assume no overflow as the max totalClaimable amount won't exceed uint128 throughout the whole life cycle unchecked { userClaimData.claimed += claimable; totalClaimable += claimable; } } } } /// @dev Update `airdropClaimed` AND/OR `rewardsClaimed` based on the booleans passed in nftUsersClaimData for the given NFT Collection ID and token ID(s) /// @param _requester Address of the claimer /// @param _nftCollectionClaimRequests Array of NFTCollectionClaimRequest that consists collection ID of the NFT, token ID(s) the owner owns, array of booleans to indicate NFTAirdrop/NFTRewards claim for each token ID /// @return totalNFTClaimable Amount of total NFT claimable calculated from the given NFT Collection ID and token ID(s) function _executeClaimInNFTs(address _requester, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests) private returns (uint128 totalNFTClaimable) { for (uint256 i; i < _nftCollectionClaimRequests.length;) { uint256[] calldata tokenIds = _nftCollectionClaimRequests[i].tokenIds; bool[] calldata withNFTAirdropList = _nftCollectionClaimRequests[i].withNFTAirdropList; bool[] calldata withNFTRewardsList = _nftCollectionClaimRequests[i].withNFTRewardsList; uint256 len = tokenIds.length; if (len != withNFTAirdropList.length || len != withNFTRewardsList.length) { revert MismatchedArrays(); } uint256 collectionId = _nftCollectionClaimRequests[i].collectionId; for (uint256 j; j < len;) { uint128 claimable; if (withNFTAirdropList[j]) { claimable = _verifyNFTClaim(_requester, collectionId, tokenIds[j]); if (claimable > 0) { /// @dev assume no overflow as the max claimable amount won't exceed uint128 unchecked { nftUsersClaimData[collectionId][tokenIds[j]].airdropClaimed += claimable; totalNFTClaimable += claimable; } } } if (withNFTRewardsList[j]) { claimable = _verifyNFTRewardClaim(_requester, collectionId, tokenIds[j]); if (claimable > 0) { unchecked { nftUsersClaimData[collectionId][tokenIds[j]].rewardsClaimed += claimable; totalNFTClaimable += claimable; } } } unchecked { ++j; } } unchecked { ++i; } } } /// @dev Verify if the caller owns the NFT, and return the correct amount of claimable token /// @param _requester Address of the claimer /// @param _collectionId Collection ID of the NFT /// @param _tokenId Token ID that the owner owns function _verifyNFTClaim(address _requester, uint256 _collectionId, uint256 _tokenId) private view onlyValidCollectionId(_collectionId) returns (uint128) { if (nftCollections[_collectionId].ownerOf(_tokenId) != _requester) revert Unauthorized(); return _calculateNFTClaimable(nftUsersClaimData[_collectionId][_tokenId]); } function _verifyNFTRewardClaim(address _requester, uint256 _collectionId, uint256 _tokenId) private view onlyValidCollectionId(_collectionId) returns (uint128) { if (nftCollections[_collectionId].ownerOf(_tokenId) != _requester) revert Unauthorized(); return _calculateNFTRewardsClaimable(nftUsersClaimData[_collectionId][_tokenId]); } function _calculateClaimable(ClaimData memory _userClaimdata, ClaimType _claimType) private view returns (uint128) { uint128 totalClaimable = _userClaimdata.totalClaimable; uint128 claimed = _userClaimdata.claimed; if (totalClaimable == 0 || claimed >= totalClaimable) return 0; // for WalletRewards claim will expire after _MAX_CLAIM_PERIOD has passed since claim starts if (_claimType == ClaimType.WalletRewards) { if (block.timestamp > claimStartDate + _MAX_CLAIM_PERIOD) { return 0; } return totalClaimable; } ClaimSchedule memory claimSchedule = claimScheduleOf[_claimType]; uint256 numOfLockUpBPs = claimSchedule.lockUpBPs.length; if (numOfLockUpBPs == 0) revert InvalidClaimSetup(); // claim will expire after the allocated $MEME are fully vested for _MAX_CLAIM_PERIOD if (block.timestamp > claimStartDate + _LOCK_UP_SLOT * numOfLockUpBPs * 1 days + _MAX_CLAIM_PERIOD) { return 0; } uint256 daysElapsed = (block.timestamp - claimStartDate) / 1 days; // count the cycles passed to distinguish which cycle's 180 days is elapsed uint256 cyclesPassed = daysElapsed / _LOCK_UP_SLOT; // PrivatePresale first cycle unlocked amount locks up until the start of next cycle and allows instant claim if (_claimType == ClaimType.PrivatePresale && daysElapsed < _LOCK_UP_SLOT) return 0; // Contributors has a different number of cycles, other claim types share the same one bool isClaimTypeFullyVested = _claimType != ClaimType.Contributors && cyclesPassed >= _END_CYCLE; bool isContributorFullyVested = _claimType == ClaimType.Contributors && cyclesPassed >= _END_CYCLE_CONTRIBUTORS; if (isClaimTypeFullyVested || isContributorFullyVested) { return _calculateRemainClaimable(totalClaimable, claimed); } // cyclesPassed + 1 because we want to calculate the current cycle's (with < 180 days elapsed) unlocked amount return _calculateRemainClaimable( _calculateUnlockedAmount(claimSchedule, numOfLockUpBPs, totalClaimable, cyclesPassed + 1, daysElapsed), claimed ); } function _calculateNFTClaimable(NFTClaimData memory _nftUserClaimdata) private view returns (uint128) { uint256 currentNFTUnlockedBP_ = currentNFTUnlockedBP; if (currentNFTUnlockedBP_ == 0) return 0; // claim will expire after the allocated $MEME are fully vested for _MAX_CLAIM_PERIOD if (currentNFTUnlockedBP_ == _BASIS_POINTS) { if (block.timestamp > currentNFTUnlockTimestamp + _MAX_CLAIM_PERIOD) { return 0; } } uint128 airdropTotalClaimable = _nftUserClaimdata.airdropTotalClaimable; uint128 airdropClaimed = _nftUserClaimdata.airdropClaimed; if (airdropTotalClaimable == 0 || airdropClaimed >= airdropTotalClaimable) return 0; return _calculateRemainClaimable(_calculateNFTUnlockedAmount(airdropTotalClaimable), airdropClaimed); } function _calculateNFTRewardsClaimable(NFTClaimData memory _nftUserClaimdata) private view returns (uint128) { uint128 rewardsTotalClaimable = _nftUserClaimdata.rewardsTotalClaimable; uint128 rewardsClaimed = _nftUserClaimdata.rewardsClaimed; if (rewardsTotalClaimable == 0 || rewardsClaimed >= rewardsTotalClaimable) return 0; // claim will expire after the allocated $MEME are fully vested for _MAX_CLAIM_PERIOD if (block.timestamp > claimStartDate + _MAX_CLAIM_PERIOD) { return 0; } return _calculateRemainClaimable(rewardsTotalClaimable, rewardsClaimed); } function _calculateRemainClaimable(uint128 _totalClaimable, uint128 _claimed) private pure returns (uint128) { /// @dev assume no underflow because we already return zero when _claimed is >= _totalClaimable unchecked { return _totalClaimable <= _claimed ? 0 : _totalClaimable - _claimed; } } function _calculateUnlockedAmount( ClaimSchedule memory _claimSchedule, uint256 _numOfLockUpBPs, uint128 _totalClaimable, uint256 _currentCycle, uint256 _daysElapsed ) private pure returns (uint128) { if (_currentCycle < _claimSchedule.startCycle) return 0; if (_currentCycle > _numOfLockUpBPs) return _totalClaimable; // _currentCycle == _numOfLockUpBPs means _currentCycle is the last one uint256 currentUnlockedBP = _currentCycle == _numOfLockUpBPs ? _BASIS_POINTS : _claimSchedule.lockUpBPs[_currentCycle]; return _calculateUnlockedAmountByDaysElapsed( _totalClaimable, _claimSchedule.lockUpBPs[_currentCycle - 1], currentUnlockedBP, _daysElapsed % _LOCK_UP_SLOT ); } function _calculateUnlockedAmountByDaysElapsed( uint128 _totalClaimable, uint256 _previousUnlockedBP, uint256 _currentUnlockedBP, uint256 _daysElapsedForCurrentCycle ) private pure returns (uint128) { if (_daysElapsedForCurrentCycle == 0) { return _toUint128(_totalClaimable * _previousUnlockedBP / _BASIS_POINTS); } return _toUint128( _totalClaimable * _previousUnlockedBP / _BASIS_POINTS + _totalClaimable * (_currentUnlockedBP - _previousUnlockedBP) * _daysElapsedForCurrentCycle / _BASIS_POINTS / _LOCK_UP_SLOT ); } function _calculateNFTUnlockedAmount(uint128 _totalClaimable) private view returns (uint128) { return block.timestamp < currentNFTUnlockTimestamp ? _toUint128(_totalClaimable * previousNFTUnlockedBP / _BASIS_POINTS) : _toUint128(_totalClaimable * currentNFTUnlockedBP / _BASIS_POINTS); } function _toUint128(uint256 value) private pure returns (uint128) { if (value >= 1 << 128) revert Uint128Overflow(); return uint128(value); } // ==================== // Validation Modifiers // ==================== modifier onlyUpgrader() { if (_msgSender() != upgrader) revert Unauthorized(); _; } modifier onlyMultiClaim() { if (_msgSender() != multiClaim) revert Unauthorized(); _; } modifier onlyClaimNotOpen() { if (claimActive) revert ClaimNotClosed(); _; } modifier onlyValidClaimSetup() { if (!claimActive || claimStartDate == 0 || block.timestamp < claimStartDate) revert ClaimNotAvailable(); if (address(claimToken) == address(0)) revert ClaimTokenZeroAddress(); _; } modifier onlyValidCollectionId(uint256 _collectionId) { if (_collectionId >= nftCollections.length) revert InvalidCollectionId(); _; } // ============== // Claimable Settings // ============== /// @dev Set `totalClaimable` in usersClaimData for claim type(s) /// @param _addresses Array of addresses eligible for the claim /// @param _claimables Array of amounts of claim token /// @param _claimTypes Array of ClaimType function setClaimables( address[] calldata _addresses, uint128[] calldata _claimables, ClaimType[] calldata _claimTypes ) external onlyOwner { uint256 len = _addresses.length; if (len != _claimables.length || len != _claimTypes.length) revert MismatchedArrays(); for (uint256 i; i < len;) { usersClaimData[_addresses[i]][_claimTypes[i]].totalClaimable = _claimables[i]; unchecked { ++i; } } } /// @dev Set `airdropTotalClaimable` and `rewardsTotalClaimable` in nftUsersClaimData for token ID(s) of respective collection ID /// @param _nftClaimables Array of NFTClaimable which consists of collectionId, tokenId and amount of claim token function setNFTClaimables(NFTClaimable[] calldata _nftClaimables) external onlyOwner { for (uint256 i; i < _nftClaimables.length;) { uint256 collectionId = _nftClaimables[i].collectionId; uint256 tokenId = _nftClaimables[i].tokenId; uint128 airdropAmount = _nftClaimables[i].airdropTotalClaimable; uint128 rewardsAmount = _nftClaimables[i].rewardsTotalClaimable; nftUsersClaimData[collectionId][tokenId].airdropTotalClaimable = airdropAmount; nftUsersClaimData[collectionId][tokenId].rewardsTotalClaimable = rewardsAmount; unchecked { ++i; } } } /// @dev Add new unlock percentage in Basis Points(BP) for NFT holders to instant claim until _BASIS_POINTS is reached /// @param _additionalNFTUnlockedBP Additional unlocked BP, only add up the currentNFTUnlockedBP /// @param _newUnlockTimestamp Timestamp for new unlocked BP to take effect function addNFTUnlockedBPAndSetUnlockTs(uint64 _additionalNFTUnlockedBP, uint128 _newUnlockTimestamp) external onlyOwner { uint64 currentNFTUnlockedBP_ = currentNFTUnlockedBP; uint128 currentNFTUnlockTimestamp_ = currentNFTUnlockTimestamp; if ( _additionalNFTUnlockedBP == 0 || currentNFTUnlockedBP_ + _additionalNFTUnlockedBP > _BASIS_POINTS || _newUnlockTimestamp <= currentNFTUnlockTimestamp_ ) revert InvalidClaimSetup(); previousNFTUnlockedBP = currentNFTUnlockedBP_; currentNFTUnlockTimestamp = _newUnlockTimestamp; currentNFTUnlockedBP += _additionalNFTUnlockedBP; } /// @dev Set the unclaimedNFTRewards mapping in order to withdraw unclaimed NFTRewards after they are expired /// @param _collectionId Respective collection ID with unclaimed NFTRewards /// @param _unclaimTokenIds Array of token IDs with NFTRewards that are left unclaimed function setUnclaimedNFTRewards(uint256 _collectionId, uint128[] calldata _unclaimTokenIds) external onlyValidCollectionId(_collectionId) onlyOwner { if (block.timestamp <= claimStartDate + _MAX_CLAIM_PERIOD) revert NFTRewardsNotExpired(); UnclaimedNFTRewards storage _unclaimedNftRewards = unclaimedNftRewards[_collectionId]; uint256 len = _unclaimTokenIds.length; if (len == 0 || _unclaimedNftRewards.lastTokenId > _unclaimTokenIds[0]) revert InvalidWithdrawalSetup(); uint128 totalRewardsUnclaimed; for (uint256 i; i < len;) { // ensure the next tokenId is bigger than the prev one if (i != 0) { if (_unclaimTokenIds[i] < _unclaimTokenIds[i - 1]) revert InvalidWithdrawalSetup(); } NFTClaimData memory nftUserClaimData = nftUsersClaimData[_collectionId][_unclaimTokenIds[i]]; uint128 rewardsUnclaimed = nftUserClaimData.rewardsTotalClaimable - nftUserClaimData.rewardsClaimed; if (rewardsUnclaimed > 0) totalRewardsUnclaimed += rewardsUnclaimed; unchecked { ++i; } } _unclaimedNftRewards.lastTokenId = _unclaimTokenIds[len - 1]; _unclaimedNftRewards.totalUnclaimed += totalRewardsUnclaimed; } /// @dev Set `airdropTotalClaimable` in nftUsersClaimData specifically for single token ID of a newly revelaed Captainz /// @param _tokenId Token ID of the newly revealed Captainz /// @param _additionalAirdropTotalClaimable Additional airdropTotalClaimable, only add up since a base amount will be set for unrevealed Captainz function setRevealedCaptainzClaimable(uint256 _tokenId, uint128 _additionalAirdropTotalClaimable) external onlyOwner { nftUsersClaimData[1][_tokenId].airdropTotalClaimable += _additionalAirdropTotalClaimable; } // ============== // Claim Settings // ============== /// @dev Deposit claim token to contract and start the claim, to be called ONCE only /// @param _tokenAmount Amount of claim token to be deposited /// @param _claimStartDate Unix timestamp of the claim start date function depositClaimTokenAndStartClaim(uint256 _tokenAmount, uint256 _claimStartDate) external onlyOwner { if (claimTokenDeposited) revert AlreadyDeposited(); if (address(claimToken) == address(0)) revert ClaimTokenZeroAddress(); if (_tokenAmount == 0) revert InvalidClaimSetup(); if (_claimStartDate == 0) revert InvalidClaimSetup(); claimToken.safeTransferFrom(_msgSender(), address(this), _tokenAmount); claimStartDate = _claimStartDate; claimActive = true; claimTokenDeposited = true; emit ClaimTokenDepositedAndClaimStarted(_tokenAmount, _claimStartDate); } /// @dev Withdraw claim token from contract only when claim is not open /// @param _receiver Address to receive the token /// @param _amount Amount of claim token to be withdrawn function withdrawClaimToken(address _receiver, uint256 _amount) external onlyOwner onlyClaimNotOpen { if (address(claimToken) == address(0)) revert ClaimTokenZeroAddress(); claimToken.safeTransfer(_receiver, _amount); } /// @dev Withdraw unclaimed NFTRewards after they are expired when _MAX_CLAIM_PERIOD has passed since claim starts, to be called ONCE only /// @param _receiver Address to receive the token function withdrawUnclaimedNFTRewards(address _receiver) external onlyOwner { if (unclaimedNFTRewardsWithdrawn) revert AlreadyWithdrawn(); if (block.timestamp <= claimStartDate + _MAX_CLAIM_PERIOD) revert NFTRewardsNotExpired(); if (_receiver == address(0)) revert InvalidWithdrawalSetup(); uint256 totalWithdrawn; for (uint256 i; i < nftCollections.length;) { UnclaimedNFTRewards storage _unclaimedNftRewards = unclaimedNftRewards[i]; uint128 unclaimed = _unclaimedNftRewards.totalUnclaimed; if (unclaimed > 0) { claimToken.safeTransfer(_receiver, unclaimed); totalWithdrawn += unclaimed; } unchecked { ++i; } } unclaimedNFTRewardsWithdrawn = true; emit UnclaimedNFTRewardsWithdrawn(totalWithdrawn, block.timestamp); } /// @dev Set claim schedule(s) for claim type(s) /// @param _claimTypes Array of ClaimType /// @param _claimSchedules Array of ClaimSchedule for each claim type function setClaimSchedules(ClaimType[] calldata _claimTypes, ClaimSchedule[] calldata _claimSchedules) external onlyOwner onlyClaimNotOpen { uint256 len = _claimSchedules.length; if (_claimTypes.length != len) revert MismatchedArrays(); for (uint256 i; i < len;) { uint256[] memory lockUpBPs = _claimSchedules[i].lockUpBPs; for (uint256 j; j < lockUpBPs.length;) { if (lockUpBPs[j] > _BASIS_POINTS) revert InvalidClaimSetup(); // ensure the accumulated lockupBP is bigger than the prev one if (j != 0) { if (lockUpBPs[j] < lockUpBPs[j - 1]) revert InvalidClaimSetup(); } unchecked { ++j; } } claimScheduleOf[_claimTypes[i]] = _claimSchedules[i]; unchecked { ++i; } } } /// @dev Start/stop the claim /// @param _claimActive New boolean to indicate active or not function setClaimActive(bool _claimActive) external onlyOwner { claimActive = _claimActive; emit ClaimStatusUpdated(_claimActive); } /// @dev Set the new claim start date, allow flexibility on setting as past date to unlock claim earlier /// @param _claimStartDate New date to start the claim function setClaimStartDate(uint256 _claimStartDate) external onlyOwner { claimStartDate = _claimStartDate; } /// @dev Set the new MultiClaim contract address /// @param _multiClaim New MultiClaim contract address function setMultiClaimAddress(address _multiClaim) external onlyOwner { multiClaim = _multiClaim; } /// @dev Set the new UUPS proxy upgrader, allow setting address(0) to disable upgradeability /// @param _upgrader New upgrader function setUpgrader(address _upgrader) external onlyOwner { if (upgraderRenounced) revert UpgraderRenounced(); upgrader = _upgrader; emit UpgraderUpdated(_upgrader); } /// @notice Renounce the upgradibility of this contract function renounceUpgrader() external onlyOwner { if (upgraderRenounced) revert UpgraderRenounced(); upgraderRenounced = true; upgrader = address(0); emit UpgraderUpdated(address(0)); } // ======= // Getters // ======= /// @notice Get claim info of a user after claim starts /// @param _user Address of user /// @return claimableAmount Amount of claimable tokens for a user /// @return claimableExpiry Timestamp of the claim expiry date for the respective _claimType function getClaimInfo(address _user, ClaimType _claimType) public view onlyValidClaimSetup returns (uint128 claimableAmount, uint256 claimableExpiry) { uint256 numOfLockUpBPs = claimScheduleOf[_claimType].lockUpBPs.length; claimableAmount = _calculateClaimable(usersClaimData[_user][_claimType], _claimType); claimableExpiry = _claimType == ClaimType.WalletRewards ? claimStartDate + _MAX_CLAIM_PERIOD : claimStartDate + _LOCK_UP_SLOT * numOfLockUpBPs * 1 days + _MAX_CLAIM_PERIOD; } /// @notice Get claim info of one eligible NFT after claiming starts /// @param _collectionId Address of the eligible NFT /// @param _tokenId Token ID that the owner owns /// @return claimableAmount Amount of claimable tokens for the NFT /// @return claimableExpiry Timestamp of the claim expiry date for NFT airdrop function getClaimInfoByNFT(uint256 _collectionId, uint256 _tokenId) public view onlyValidClaimSetup onlyValidCollectionId(_collectionId) returns (uint128 claimableAmount, uint256 claimableExpiry) { NFTClaimData memory nftUserClaimData = nftUsersClaimData[_collectionId][_tokenId]; claimableAmount = _calculateNFTClaimable(nftUserClaimData); claimableExpiry = currentNFTUnlockedBP == _BASIS_POINTS ? currentNFTUnlockTimestamp + _MAX_CLAIM_PERIOD : 0; } /// @notice Get rewards claim info of one eligible NFT after claiming starts /// @param _collectionId Address of the eligible NFT /// @param _tokenId Token ID that the owner owns /// @return claimableAmount Amount of claimable tokens for the NFT /// @return claimableExpiry Timestamp of the claim expiry date for NFT rewards function getRewardsClaimInfoByNFT(uint256 _collectionId, uint256 _tokenId) public view onlyValidClaimSetup onlyValidCollectionId(_collectionId) returns (uint128 claimableAmount, uint256 claimableExpiry) { NFTClaimData memory nftUserClaimData = nftUsersClaimData[_collectionId][_tokenId]; claimableAmount = _calculateNFTRewardsClaimable(nftUserClaimData); claimableExpiry = claimStartDate + _MAX_CLAIM_PERIOD; } /// @notice Get total amounts of claimable tokens of multiple tokenIds in one eligible collection after claiming starts /// @param _collectionId ID of NFT collection /// @param _tokenIds Array of all token IDs the owner owns in that collection function getTotalClaimableAmountsByNFTs(uint256 _collectionId, uint256[] calldata _tokenIds) public view returns (uint128 totalClaimable) { for (uint256 i; i < _tokenIds.length; i++) { (uint128 claimable,) = getClaimInfoByNFT(_collectionId, _tokenIds[i]); if (claimable == 0) continue; totalClaimable += claimable; } } /// @notice Get user claim data of multiple tokenIds in multiple eligible collections /// @param _nftCollectionsInfo Array of NFTCollectionInfo with collectionId and tokenId(s) /// @return collectionClaimInfo Array of CollectionClaimData that includes claim data for each tokenId of respective collection function getUserClaimDataByCollections(NFTCollectionInfo[] calldata _nftCollectionsInfo) public view returns (CollectionClaimData[] memory collectionClaimInfo) { uint256 numOfTokenIds; uint256 len = _nftCollectionsInfo.length; for (uint256 i = 0; i < len; i++) { numOfTokenIds += _nftCollectionsInfo[i].tokenIds.length; } collectionClaimInfo = new CollectionClaimData[](numOfTokenIds); uint256 activeId = 0; for (uint256 i; i < len; i++) { uint256 collectionId = _nftCollectionsInfo[i].collectionId; uint256[] memory tokenIds = _nftCollectionsInfo[i].tokenIds; for (uint256 j; j < tokenIds.length; j++) { (uint128 airdropClaimable, uint256 airdropClaimableExpiry) = getClaimInfoByNFT(collectionId, tokenIds[j]); (uint128 rewardsClaimable, uint256 rewardClaimableExpiry) = getRewardsClaimInfoByNFT(collectionId, tokenIds[j]); collectionClaimInfo[activeId++] = CollectionClaimData( collectionId, tokenIds[j], airdropClaimable, airdropClaimableExpiry, nftUsersClaimData[collectionId][tokenIds[j]].airdropTotalClaimable, nftUsersClaimData[collectionId][tokenIds[j]].airdropClaimed, rewardsClaimable, rewardClaimableExpiry, nftUsersClaimData[collectionId][tokenIds[j]].rewardsTotalClaimable, nftUsersClaimData[collectionId][tokenIds[j]].rewardsClaimed ); } } } /// @notice Get the claim schedule of a certain claim type function getClaimSchedule(ClaimType _claimType) public view returns (ClaimSchedule memory) { return claimScheduleOf[_claimType]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @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[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967Upgradeable { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/IERC1967Upgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @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) (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.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeTo(address newImplementation) public virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @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) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @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 ReentrancyGuardUpgradeable is Initializable { // 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; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _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; } /** * @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[49] private __gap; }
// 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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../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; } /** * @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/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (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. */ interface IERC20Permit { /** * @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]. */ 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 IERC20 { /** * @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.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 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( IERC20Permit 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(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 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(IERC20 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))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface IERC721 { function ownerOf(uint256 tokenId) external view returns (address owner); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {IERC721} from "./IERC721.sol"; import "../lib/Errors.sol"; import "../lib/Structs.sol"; interface IMemecoinClaim { event UserClaimed(address indexed user, uint128 amount, uint256 claimedAt); event ClaimedInNFTs(address indexed owner, uint128 amount, uint256 claimedAt); event ClaimStatusUpdated(bool claimActive); event UpgraderUpdated(address newUpgrader); event UnclaimedNFTRewardsWithdrawn(uint256 totalWithdrawn, uint256 withdrawnAt); event ClaimTokenDepositedAndClaimStarted(uint256 tokenAmount, uint256 claimStartDate); function claim(address _vault, ClaimType[] calldata _claimTypes) external; function claimInNFTs( address _vault, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests, bool _withWalletRewards ) external; function claimFromMulti(address _requester, ClaimType[] calldata _claimTypes) external; function claimInNFTsFromMulti( address _requester, NFTCollectionClaimRequest[] calldata _nftCollectionClaimRequests, bool _withWalletRewards ) external; function setClaimables( address[] calldata _addresses, uint128[] calldata _claimables, ClaimType[] calldata _claimTypes ) external; function setNFTClaimables(NFTClaimable[] calldata _nftClaimables) external; function addNFTUnlockedBPAndSetUnlockTs(uint64 _additionalNFTUnlockedBP, uint128 _newUnlockedBPEffectiveTs) external; function setUnclaimedNFTRewards(uint256 _collectionId, uint128[] calldata _unclaimTokenIds) external; function setRevealedCaptainzClaimable(uint256 _tokenId, uint128 _additionalAirdropTotalClaimable) external; function depositClaimTokenAndStartClaim(uint256 _tokenAmount, uint256 _claimStartDate) external; function withdrawClaimToken(address _receiver, uint256 _amount) external; function withdrawUnclaimedNFTRewards(address _receiver) external; function setClaimSchedules(ClaimType[] calldata _claimTypes, ClaimSchedule[] calldata _claimSchedules) external; function setClaimActive(bool _claimActive) external; function setClaimStartDate(uint256 _claimStartDate) external; function setMultiClaimAddress(address _multiClaim) external; function setUpgrader(address _upgrader) external; function getClaimInfo(address _user, ClaimType _claimType) external returns (uint128 claimableAmount, uint256 claimableExpiry); function getClaimInfoByNFT(uint256 _collectionId, uint256 _tokenId) external returns (uint128 claimableAmount, uint256 claimableExpiry); function getRewardsClaimInfoByNFT(uint256 _collectionId, uint256 _tokenId) external returns (uint128 claimableAmount, uint256 claimableExpiry); function getTotalClaimableAmountsByNFTs(uint256 _collectionId, uint256[] calldata _tokenIds) external returns (uint128 totalClaimable); function getUserClaimDataByCollections(NFTCollectionInfo[] calldata _nftCollectionInfo) external returns (CollectionClaimData[] memory collectionClaimInfo); function getClaimSchedule(ClaimType _claimType) external returns (ClaimSchedule memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; error ClaimNotAvailable(); error ClaimNotClosed(); error NFTRewardsNotExpired(); error UpgraderRenounced(); error ClaimTokenZeroAddress(); error AlreadyDeposited(); error AlreadyWithdrawn(); error InvalidClaimSetup(); error InvalidWithdrawalSetup(); error InvalidCollectionId(); error InvalidDelegate(); error NoClaimableToken(); error MismatchedArrays(); error Unauthorized(); error Uint128Overflow();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; enum ClaimType { WalletRewards, CommunityPresale, PrivatePresale, Ecosystem, Contributors } struct ClaimData { uint128 totalClaimable; uint128 claimed; } struct NFTClaimData { uint128 airdropTotalClaimable; uint128 rewardsTotalClaimable; uint128 airdropClaimed; uint128 rewardsClaimed; } struct ClaimSchedule { uint256 startCycle; uint256[] lockUpBPs; } struct NFTClaimable { uint256 collectionId; uint256 tokenId; uint128 airdropTotalClaimable; uint128 rewardsTotalClaimable; } struct NFTCollectionInfo { uint256 collectionId; uint256[] tokenIds; } struct NFTCollectionClaimRequest { uint256 collectionId; uint256[] tokenIds; bool[] withNFTAirdropList; bool[] withNFTRewardsList; } struct CollectionClaimData { uint256 collectionId; uint256 tokenId; uint128 airdropClaimable; uint256 airdropClaimableExpiry; uint128 airdropTotalClaimable; uint128 airdropClaimed; uint128 rewardsClaimable; uint256 rewardsClaimableExpiry; uint128 rewardsTotalClaimable; uint128 rewardsClaimed; } struct UnclaimedNFTRewards { uint128 lastTokenId; uint128 totalUnclaimed; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity >=0.8.13; /** * @title IDelegateRegistry * @custom:version 2.0 * @custom:author foobar (0xfoobar) * @notice A standalone immutable registry storing delegated permissions from one address to another */ interface IDelegateRegistry { /// @notice Delegation type, NONE is used when a delegation does not exist or is revoked enum DelegationType { NONE, ALL, CONTRACT, ERC721, ERC20, ERC1155 } /// @notice Struct for returning delegations struct Delegation { DelegationType type_; address to; address from; bytes32 rights; address contract_; uint256 tokenId; uint256 amount; } /// @notice Emitted when an address delegates or revokes rights for their entire wallet event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable); /// @notice Emitted when an address delegates or revokes rights for a contract address event DelegateContract( address indexed from, address indexed to, address indexed contract_, bytes32 rights, bool enable ); /// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId event DelegateERC721( address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, bool enable ); /// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens event DelegateERC20( address indexed from, address indexed to, address indexed contract_, bytes32 rights, uint256 amount ); /// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId event DelegateERC1155( address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, uint256 amount ); /// @notice Thrown if multicall calldata is malformed error MulticallFailed(); /** * ----------- WRITE ----------- */ /** * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed * @param data The encoded function data for each of the calls to make to this contract * @return results The results from each of the calls passed in via data */ function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); /** * @notice Allow the delegate to act on behalf of `msg.sender` for all contracts * @param to The address to act as delegate * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights * @param enable Whether to enable or disable this delegation, true delegates and false revokes * @return delegationHash The unique identifier of the delegation */ function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash); /** * @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract * @param to The address to act as delegate * @param contract_ The contract whose rights are being delegated * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights * @param enable Whether to enable or disable this delegation, true delegates and false revokes * @return delegationHash The unique identifier of the delegation */ function delegateContract(address to, address contract_, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash); /** * @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token * @param to The address to act as delegate * @param contract_ The contract whose rights are being delegated * @param tokenId The token id to delegate * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights * @param enable Whether to enable or disable this delegation, true delegates and false revokes * @return delegationHash The unique identifier of the delegation */ function delegateERC721(address to, address contract_, uint256 tokenId, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash); /** * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) * @param to The address to act as delegate * @param contract_ The address for the fungible token contract * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights * @param amount The amount to delegate, > 0 delegates and 0 revokes * @return delegationHash The unique identifier of the delegation */ function delegateERC20(address to, address contract_, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash); /** * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) * @param to The address to act as delegate * @param contract_ The address of the contract that holds the token * @param tokenId The token id to delegate * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights * @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes * @return delegationHash The unique identifier of the delegation */ function delegateERC1155(address to, address contract_, uint256 tokenId, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash); /** * ----------- CHECKS ----------- */ /** * @notice Check if `to` is a delegate of `from` for the entire wallet * @param to The potential delegate address * @param from The potential address who delegated rights * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only * @return valid Whether delegate is granted to act on the from's behalf */ function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool); /** * @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet * @param to The delegated address to check * @param contract_ The specific contract address being checked * @param from The cold wallet who issued the delegation * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only * @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract */ function checkDelegateForContract(address to, address from, address contract_, bytes32 rights) external view returns (bool); /** * @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet * @param to The delegated address to check * @param contract_ The specific contract address being checked * @param tokenId The token id for the token to delegating * @param from The wallet that issued the delegation * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only * @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId */ function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (bool); /** * @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of * @param to The delegated address to check * @param contract_ The address of the token contract * @param from The cold wallet who issued the delegation * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only * @return balance The delegated balance, which will be 0 if the delegation does not exist */ function checkDelegateForERC20(address to, address from, address contract_, bytes32 rights) external view returns (uint256); /** * @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of * @param to The delegated address to check * @param contract_ The address of the token contract * @param tokenId The token id to check the delegated amount of * @param from The cold wallet who issued the delegation * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only * @return balance The delegated balance, which will be 0 if the delegation does not exist */ function checkDelegateForERC1155(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (uint256); /** * ----------- ENUMERATIONS ----------- */ /** * @notice Returns all enabled delegations a given delegate has received * @param to The address to retrieve delegations for * @return delegations Array of Delegation structs */ function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations); /** * @notice Returns all enabled delegations an address has given out * @param from The address to retrieve delegations for * @return delegations Array of Delegation structs */ function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations); /** * @notice Returns all hashes associated with enabled delegations an address has received * @param to The address to retrieve incoming delegation hashes for * @return delegationHashes Array of delegation hashes */ function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes); /** * @notice Returns all hashes associated with enabled delegations an address has given out * @param from The address to retrieve outgoing delegation hashes for * @return delegationHashes Array of delegation hashes */ function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes); /** * @notice Returns the delegations for a given array of delegation hashes * @param delegationHashes is an array of hashes that correspond to delegations * @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations */ function getDelegationsFromHashes(bytes32[] calldata delegationHashes) external view returns (Delegation[] memory delegations); /** * ----------- STORAGE ACCESS ----------- */ /** * @notice Allows external contracts to read arbitrary storage slots */ function readSlot(bytes32 location) external view returns (bytes32); /** * @notice Allows external contracts to read an arbitrary array of storage slots */ function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory); }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.17; /** * @title An immutable registry contract to be deployed as a standalone primitive * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations * from here and integrate those permissions into their flow */ interface IDelegationRegistry { /// @notice Delegation type enum DelegationType { NONE, ALL, CONTRACT, TOKEN } /// @notice Info about a single delegation, used for onchain enumeration struct DelegationInfo { DelegationType type_; address vault; address delegate; address contract_; uint256 tokenId; } /// @notice Info about a single contract-level delegation struct ContractDelegation { address contract_; address delegate; } /// @notice Info about a single token-level delegation struct TokenDelegation { address contract_; uint256 tokenId; address delegate; } /// @notice Emitted when a user delegates their entire wallet event DelegateForAll(address vault, address delegate, bool value); /// @notice Emitted when a user delegates a specific contract event DelegateForContract(address vault, address delegate, address contract_, bool value); /// @notice Emitted when a user delegates a specific token event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value); /// @notice Emitted when a user revokes all delegations event RevokeAllDelegates(address vault); /// @notice Emitted when a user revoes all delegations for a given delegate event RevokeDelegate(address vault, address delegate); /** * ----------- WRITE ----------- */ /** * @notice Allow the delegate to act on your behalf for all contracts * @param delegate The hotwallet to act on your behalf * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForAll(address delegate, bool value) external; /** * @notice Allow the delegate to act on your behalf for a specific contract * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForContract(address delegate, address contract_, bool value) external; /** * @notice Allow the delegate to act on your behalf for a specific token * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param tokenId The token id for the token you're delegating * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external; /** * @notice Revoke all delegates */ function revokeAllDelegates() external; /** * @notice Revoke a specific delegate for all their permissions * @param delegate The hotwallet to revoke */ function revokeDelegate(address delegate) external; /** * @notice Remove yourself as a delegate for a specific vault * @param vault The vault which delegated to the msg.sender, and should be removed */ function revokeSelf(address vault) external; /** * ----------- READ ----------- */ /** * @notice Returns all active delegations a given delegate is able to claim on behalf of * @param delegate The delegate that you would like to retrieve delegations for * @return info Array of DelegationInfo structs */ function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory); /** * @notice Returns an array of wallet-level delegates for a given vault * @param vault The cold wallet who issued the delegation * @return addresses Array of wallet-level delegates for a given vault */ function getDelegatesForAll(address vault) external view returns (address[] memory); /** * @notice Returns an array of contract-level delegates for a given vault and contract * @param vault The cold wallet who issued the delegation * @param contract_ The address for the contract you're delegating * @return addresses Array of contract-level delegates for a given vault and contract */ function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory); /** * @notice Returns an array of contract-level delegates for a given vault's token * @param vault The cold wallet who issued the delegation * @param contract_ The address for the contract holding the token * @param tokenId The token id for the token you're delegating * @return addresses Array of contract-level delegates for a given vault's token */ function getDelegatesForToken(address vault, address contract_, uint256 tokenId) external view returns (address[] memory); /** * @notice Returns all contract-level delegations for a given vault * @param vault The cold wallet who issued the delegations * @return delegations Array of ContractDelegation structs */ function getContractLevelDelegations(address vault) external view returns (ContractDelegation[] memory delegations); /** * @notice Returns all token-level delegations for a given vault * @param vault The cold wallet who issued the delegations * @return delegations Array of TokenDelegation structs */ function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations); /** * @notice Returns true if the address is delegated to act on the entire vault * @param delegate The hotwallet to act on your behalf * @param vault The cold wallet who issued the delegation */ function checkDelegateForAll(address delegate, address vault) external view returns (bool); /** * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param vault The cold wallet who issued the delegation */ function checkDelegateForContract(address delegate, address vault, address contract_) external view returns (bool); /** * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param tokenId The token id for the token you're delegating * @param vault The cold wallet who issued the delegation */ function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId) external view returns (bool); }
{ "evmVersion": "shanghai", "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyDeposited","type":"error"},{"inputs":[],"name":"AlreadyWithdrawn","type":"error"},{"inputs":[],"name":"ClaimNotAvailable","type":"error"},{"inputs":[],"name":"ClaimNotClosed","type":"error"},{"inputs":[],"name":"ClaimTokenZeroAddress","type":"error"},{"inputs":[],"name":"InvalidClaimSetup","type":"error"},{"inputs":[],"name":"InvalidCollectionId","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidWithdrawalSetup","type":"error"},{"inputs":[],"name":"MismatchedArrays","type":"error"},{"inputs":[],"name":"NFTRewardsNotExpired","type":"error"},{"inputs":[],"name":"NoClaimableToken","type":"error"},{"inputs":[],"name":"Uint128Overflow","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UpgraderRenounced","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"claimActive","type":"bool"}],"name":"ClaimStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimStartDate","type":"uint256"}],"name":"ClaimTokenDepositedAndClaimStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"claimedAt","type":"uint256"}],"name":"ClaimedInNFTs","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalWithdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawnAt","type":"uint256"}],"name":"UnclaimedNFTRewardsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newUpgrader","type":"address"}],"name":"UpgraderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"claimedAt","type":"uint256"}],"name":"UserClaimed","type":"event"},{"inputs":[{"internalType":"uint64","name":"_additionalNFTUnlockedBP","type":"uint64"},{"internalType":"uint128","name":"_newUnlockTimestamp","type":"uint128"}],"name":"addNFTUnlockedBPAndSetUnlockTs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"enum ClaimType[]","name":"_claimTypes","type":"uint8[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_requester","type":"address"},{"internalType":"enum ClaimType[]","name":"_claimTypes","type":"uint8[]"}],"name":"claimFromMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"components":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bool[]","name":"withNFTAirdropList","type":"bool[]"},{"internalType":"bool[]","name":"withNFTRewardsList","type":"bool[]"}],"internalType":"struct NFTCollectionClaimRequest[]","name":"_nftCollectionClaimRequests","type":"tuple[]"},{"internalType":"bool","name":"_withWalletRewards","type":"bool"}],"name":"claimInNFTs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_requester","type":"address"},{"components":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bool[]","name":"withNFTAirdropList","type":"bool[]"},{"internalType":"bool[]","name":"withNFTRewardsList","type":"bool[]"}],"internalType":"struct NFTCollectionClaimRequest[]","name":"_nftCollectionClaimRequests","type":"tuple[]"},{"internalType":"bool","name":"_withWalletRewards","type":"bool"}],"name":"claimInNFTsFromMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ClaimType","name":"claimType","type":"uint8"}],"name":"claimScheduleOf","outputs":[{"internalType":"uint256","name":"startCycle","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimStartDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimTokenDeposited","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentNFTUnlockTimestamp","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentNFTUnlockedBP","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dc","outputs":[{"internalType":"contract IDelegationRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dcV2","outputs":[{"internalType":"contract IDelegateRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint256","name":"_claimStartDate","type":"uint256"}],"name":"depositClaimTokenAndStartClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"enum ClaimType","name":"_claimType","type":"uint8"}],"name":"getClaimInfo","outputs":[{"internalType":"uint128","name":"claimableAmount","type":"uint128"},{"internalType":"uint256","name":"claimableExpiry","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collectionId","type":"uint256"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getClaimInfoByNFT","outputs":[{"internalType":"uint128","name":"claimableAmount","type":"uint128"},{"internalType":"uint256","name":"claimableExpiry","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ClaimType","name":"_claimType","type":"uint8"}],"name":"getClaimSchedule","outputs":[{"components":[{"internalType":"uint256","name":"startCycle","type":"uint256"},{"internalType":"uint256[]","name":"lockUpBPs","type":"uint256[]"}],"internalType":"struct ClaimSchedule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collectionId","type":"uint256"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getRewardsClaimInfoByNFT","outputs":[{"internalType":"uint128","name":"claimableAmount","type":"uint128"},{"internalType":"uint256","name":"claimableExpiry","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collectionId","type":"uint256"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"getTotalClaimableAmountsByNFTs","outputs":[{"internalType":"uint128","name":"totalClaimable","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"internalType":"struct NFTCollectionInfo[]","name":"_nftCollectionsInfo","type":"tuple[]"}],"name":"getUserClaimDataByCollections","outputs":[{"components":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"airdropClaimable","type":"uint128"},{"internalType":"uint256","name":"airdropClaimableExpiry","type":"uint256"},{"internalType":"uint128","name":"airdropTotalClaimable","type":"uint128"},{"internalType":"uint128","name":"airdropClaimed","type":"uint128"},{"internalType":"uint128","name":"rewardsClaimable","type":"uint128"},{"internalType":"uint256","name":"rewardsClaimableExpiry","type":"uint256"},{"internalType":"uint128","name":"rewardsTotalClaimable","type":"uint128"},{"internalType":"uint128","name":"rewardsClaimed","type":"uint128"}],"internalType":"struct CollectionClaimData[]","name":"collectionClaimInfo","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_claimTokenAddress","type":"address"},{"internalType":"address","name":"_mvpAddress","type":"address"},{"internalType":"address","name":"_captainzAddress","type":"address"},{"internalType":"address","name":"_potatozAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"multiClaim","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftCollections","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"nftUsersClaimData","outputs":[{"internalType":"uint128","name":"airdropTotalClaimable","type":"uint128"},{"internalType":"uint128","name":"rewardsTotalClaimable","type":"uint128"},{"internalType":"uint128","name":"airdropClaimed","type":"uint128"},{"internalType":"uint128","name":"rewardsClaimed","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previousNFTUnlockedBP","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceUpgrader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_claimActive","type":"bool"}],"name":"setClaimActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ClaimType[]","name":"_claimTypes","type":"uint8[]"},{"components":[{"internalType":"uint256","name":"startCycle","type":"uint256"},{"internalType":"uint256[]","name":"lockUpBPs","type":"uint256[]"}],"internalType":"struct ClaimSchedule[]","name":"_claimSchedules","type":"tuple[]"}],"name":"setClaimSchedules","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimStartDate","type":"uint256"}],"name":"setClaimStartDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint128[]","name":"_claimables","type":"uint128[]"},{"internalType":"enum ClaimType[]","name":"_claimTypes","type":"uint8[]"}],"name":"setClaimables","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_multiClaim","type":"address"}],"name":"setMultiClaimAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"collectionId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"airdropTotalClaimable","type":"uint128"},{"internalType":"uint128","name":"rewardsTotalClaimable","type":"uint128"}],"internalType":"struct NFTClaimable[]","name":"_nftClaimables","type":"tuple[]"}],"name":"setNFTClaimables","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint128","name":"_additionalAirdropTotalClaimable","type":"uint128"}],"name":"setRevealedCaptainzClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collectionId","type":"uint256"},{"internalType":"uint128[]","name":"_unclaimTokenIds","type":"uint128[]"}],"name":"setUnclaimedNFTRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_upgrader","type":"address"}],"name":"setUpgrader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedNFTRewardsWithdrawn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collectionId","type":"uint256"}],"name":"unclaimedNftRewards","outputs":[{"internalType":"uint128","name":"lastTokenId","type":"uint128"},{"internalType":"uint128","name":"totalUnclaimed","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"upgrader","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upgraderRenounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"enum ClaimType","name":"claimType","type":"uint8"}],"name":"usersClaimData","outputs":[{"internalType":"uint128","name":"totalClaimable","type":"uint128"},{"internalType":"uint128","name":"claimed","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawClaimToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdrawUnclaimedNFTRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523060805234801562000014575f80fd5b506200001f62000025565b620000e3565b5f54610100900460ff1615620000915760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811614620000e1575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051614b00620001185f395f81816112150152818161125e015281816116fd0152818161173d01526117ce0152614b005ff3fe6080604052600436106102a5575f3560e01c806374a4e4431161016f578063b607bc30116100d8578063e274842911610092578063f2fde38b1161006d578063f2fde38b14610983578063f60c7158146109a2578063f8c8765e146109c1578063f92b41bd146109e0575f80fd5b8063e274842914610930578063f0fd108414610950578063f163d7121461096f575f80fd5b8063b607bc3014610854578063bc5800e514610893578063bfca66c9146108b2578063c6e4fc93146108d1578063d4a6a2fd146108f0578063d8a531a614610911575f80fd5b80638da5cb5b116101295780638da5cb5b14610782578063976289171461079f578063ab14dee4146107be578063af269745146107ea578063b21185b314610809578063b4ab6cf114610828575f80fd5b806374a4e443146106c45780637b2d3e69146106e55780638110c50f146107045780638131fd161461072557806385c23195146107445780638ad0838d14610763575f80fd5b80634d9c41a711610211578063675151b2116101cb578063675151b2146105a85780636afffd90146105c75780636d5bc5ca146105e65780636e35d39514610646578063715018a61461069157806373417b09146106a5575f80fd5b80634d9c41a71461046e5780634f1ef286146104ad57806351fa7cc2146104c057806352d1902d146105515780635f03b6b214610573578063648de06b14610589575f80fd5b80633659cfe6116102625780633659cfe6146103655780633c11bdd614610384578063416b3e1e146103c7578063427fa204146103e65780634451d89f14610417578063474954c31461044f575f80fd5b806319a8b4a0146102a95780631b878f71146102ca5780631d671c5b146102e9578063232275c1146103085780632f1521581461032757806332e52ae114610346575b5f80fd5b3480156102b4575f80fd5b506102c86102c3366004614030565b610a0c565b005b3480156102d5575f80fd5b506102c86102e4366004614080565b610b2a565b3480156102f4575f80fd5b506102c86103033660046140b6565b610bb3565b348015610313575f80fd5b506102c86103223660046140f4565b610cbf565b348015610332575f80fd5b506102c8610341366004614186565b610df9565b348015610351575f80fd5b506102c8610360366004614080565b6110b9565b348015610370575f80fd5b506102c861037f366004614080565b61120b565b34801561038f575f80fd5b506103a361039e3660046141b4565b6112f1565b604080516001600160801b0390931683526020830191909152015b60405180910390f35b3480156103d2575f80fd5b506103a36103e13660046141e2565b611440565b3480156103f1575f80fd5b506101015461040790600160b01b900460ff1681565b60405190151581526020016103be565b348015610422575f80fd5b5061010154610437906001600160a01b031681565b6040516001600160a01b0390911681526020016103be565b34801561045a575f80fd5b506102c86104693660046141b4565b6115ea565b348015610479575f80fd5b506101025461049590600160401b90046001600160801b031681565b6040516001600160801b0390911681526020016103be565b6102c86104bb366004614220565b6116f3565b3480156104cb575f80fd5b5061051e6104da3660046141b4565b61010460209081525f9283526040808420909152908252902080546001909101546001600160801b0380831692600160801b90819004821692808316929190041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103be565b34801561055c575f80fd5b506105656117c2565b6040519081526020016103be565b34801561057e575f80fd5b506105656101005481565b348015610594575f80fd5b506102c86105a33660046142dd565b611873565b3480156105b3575f80fd5b506102c86105c236600461430b565b6118e8565b3480156105d2575f80fd5b506102c86105e136600461436e565b6119b1565b3480156105f1575f80fd5b50610626610600366004614398565b6101066020525f90815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016103be565b348015610651575f80fd5b506106266106603660046141e2565b61010360209081525f92835260408084209091529082529020546001600160801b0380821691600160801b90041682565b34801561069c575f80fd5b506102c8611a27565b3480156106b0575f80fd5b506102c86106bf3660046143af565b611a3a565b3480156106cf575f80fd5b506101015461040790600160a81b900460ff1681565b3480156106f0575f80fd5b506102c86106ff366004614398565b611a90565b34801561070f575f80fd5b506101015461040790600160b81b900460ff1681565b348015610730575f80fd5b5060fc54610437906001600160a01b031681565b34801561074f575f80fd5b5060ff54610437906001600160a01b031681565b34801561076e575f80fd5b5061049561077d366004614186565b611a9e565b34801561078d575f80fd5b5060c9546001600160a01b0316610437565b3480156107aa575f80fd5b506102c86107b936600461430b565b611b0d565b3480156107c9575f80fd5b506107dd6107d83660046143ca565b611bf6565b6040516103be91906143e3565b3480156107f5575f80fd5b5060fb54610437906001600160a01b031681565b348015610814575f80fd5b506102c8610823366004614080565b611caf565b348015610833575f80fd5b5061084761084236600461443a565b611cd9565b6040516103be9190614478565b34801561085f575f80fd5b506101015461087b90600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016103be565b34801561089e575f80fd5b506103a36108ad3660046141b4565b6120dd565b3480156108bd575f80fd5b506104376108cc366004614398565b6121ed565b3480156108dc575f80fd5b506102c86108eb36600461452e565b612215565b3480156108fb575f80fd5b506101015461040790600160a01b900460ff1681565b34801561091c575f80fd5b5060fe54610437906001600160a01b031681565b34801561093b575f80fd5b506101025461087b906001600160401b031681565b34801561095b575f80fd5b506102c861096a366004614030565b6122f8565b34801561097a575f80fd5b506102c86123eb565b34801561098e575f80fd5b506102c861099d366004614080565b612478565b3480156109ad575f80fd5b506102c86109bc36600461459c565b6124ee565b3480156109cc575f80fd5b506102c86109db366004614602565b612701565b3480156109eb575f80fd5b506105656109fa3660046143ca565b6101056020525f908152604090205481565b610a1461289e565b61010154600160a01b900460ff161580610a2f575061010054155b80610a3c57506101005442105b15610a5a57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b0316610a845760405163206d376f60e01b815260040160405180910390fd5b60fc546001600160a01b0316336001600160a01b031614610ab7576040516282b42960e81b815260040160405180910390fd5b5f610af4848484808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506128f792505050565b610101546001600160801b03919091169150610b1a906001600160a01b0316858361297f565b50610b256001606555565b505050565b610b326129e9565b61010154600160b81b900460ff1615610b5e57604051639a8d50df60e01b815260040160405180910390fd5b60fb80546001600160a01b0319166001600160a01b0383169081179091556040519081527fef1cd24a01120da2689be4a7980f64da049419dcd5866a87bff7b5d978a5078c906020015b60405180910390a150565b610bbb6129e9565b6101015461010254600160c01b9091046001600160401b0390811691600160401b90046001600160801b03169084161580610c095750612710610bfe8584614664565b6001600160401b0316115b80610c265750806001600160801b0316836001600160801b031611155b15610c4457604051630a6428c360e11b815260040160405180910390fd5b61010280546001600160401b038481166001600160c01b031990921691909117600160401b6001600160801b038716021790915561010180548692601891610c95918591600160c01b900416614664565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050505050565b610cc76129e9565b848381141580610cd75750808214155b15610cf55760405163a121188760e01b815260040160405180910390fd5b5f5b81811015610def57858582818110610d1157610d11614684565b9050602002016020810190610d269190614698565b6101035f8a8a85818110610d3c57610d3c614684565b9050602002016020810190610d519190614080565b6001600160a01b03166001600160a01b031681526020019081526020015f205f868685818110610d8357610d83614684565b9050602002016020810190610d9891906143ca565b6004811115610da957610da96146b1565b6004811115610dba57610dba6146b1565b815260208101919091526040015f2080546001600160801b0319166001600160801b0392909216919091179055600101610cf7565b5050505050505050565b60fd5483908110610e1d5760405163017e9c7d60e41b815260040160405180910390fd5b610e256129e9565b625af78061010054610e3791906146c5565b4211610e5657604051632e9cc64960e21b815260040160405180910390fd5b5f8481526101066020526040902082801580610ea5575084845f818110610e7f57610e7f614684565b9050602002016020810190610e949190614698565b82546001600160801b039182169116115b15610ec357604051633be4064960e01b815260040160405180910390fd5b5f805b82811015611024578015610f5d578686610ee16001846146d8565b818110610ef057610ef0614684565b9050602002016020810190610f059190614698565b6001600160801b0316878783818110610f2057610f20614684565b9050602002016020810190610f359190614698565b6001600160801b03161015610f5d57604051633be4064960e01b815260040160405180910390fd5b5f8881526101046020526040812081898985818110610f7e57610f7e614684565b9050602002016020810190610f939190614698565b6001600160801b03908116825260208083019390935260409182015f908120835160808101855281548085168252600160801b9081900485169682018790526001909201548085169582019590955293049091166060830181905291935091610ffc91906146eb565b90506001600160801b0381161561101a57611017818561470b565b93505b5050600101610ec6565b5085856110326001856146d8565b81811061104157611041614684565b90506020020160208101906110569190614698565b83546001600160801b0319166001600160801b03918216178085558291859160109161108c918591600160801b9091041661470b565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b6110c16129e9565b61010154600160b01b900460ff16156110ed57604051636507689f60e01b815260040160405180910390fd5b625af780610100546110ff91906146c5565b421161111e57604051632e9cc64960e21b815260040160405180910390fd5b6001600160a01b03811661114557604051633be4064960e01b815260040160405180910390fd5b5f805b60fd548110156111b9575f818152610106602052604090208054600160801b90046001600160801b031680156111af5761010154611199906001600160a01b0316866001600160801b03841661297f565b6111ac6001600160801b038216856146c5565b93505b5050600101611148565b50610101805460ff60b01b1916600160b01b179055604080518281524260208201527f51c3c049b061ef6ad9b287a90842a19c63db19253589bf999293790b4adffa1491015b60405180910390a15050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361125c5760405162461bcd60e51b81526004016112539061472b565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166112a45f80516020614a84833981519152546001600160a01b031690565b6001600160a01b0316146112ca5760405162461bcd60e51b815260040161125390614777565b6112d381612a43565b604080515f808252602082019092526112ee91839190612a76565b50565b610101545f908190600160a01b900460ff161580611310575061010054155b8061131d57506101005442105b1561133b57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166113655760405163206d376f60e01b815260040160405180910390fd5b60fd54849081106113895760405163017e9c7d60e41b815260040160405180910390fd5b5f85815261010460209081526040808320878452825291829020825160808101845281546001600160801b038082168352600160801b918290048116948301949094526001909201548084169482019490945292041660608201526113ed81612be0565b610101549094506001600160401b03600160c01b9091041661271014611413575f611435565b6101025461143590625af78090600160401b90046001600160801b03166146c5565b925050509250929050565b610101545f908190600160a01b900460ff16158061145f575061010054155b8061146c57506101005442105b1561148a57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166114b45760405163206d376f60e01b815260040160405180910390fd5b5f6101055f8560048111156114cb576114cb6146b1565b60048111156114dc576114dc6146b1565b81526020019081526020015f2060010180549050905061157b6101035f876001600160a01b03166001600160a01b031681526020019081526020015f205f86600481111561152c5761152c6146b1565b600481111561153d5761153d6146b1565b815260208082019290925260409081015f208151808301909252546001600160801b038082168352600160801b909104169181019190915285612c98565b92505f846004811115611590576115906146b1565b146115ce57625af7806115a48260b46147c3565b6115b190620151806147c3565b610100546115bf91906146c5565b6115c991906146c5565b6115e0565b625af780610100546115e091906146c5565b9150509250929050565b6115f26129e9565b61010154600160a81b900460ff161561161e5760405163d5a8211560e01b815260040160405180910390fd5b610101546001600160a01b03166116485760405163206d376f60e01b815260040160405180910390fd5b815f0361166857604051630a6428c360e11b815260040160405180910390fd5b805f0361168857604051630a6428c360e11b815260040160405180910390fd5b6116a133610101546001600160a01b0316903085612f32565b610100819055610101805461ffff60a01b191661010160a01b17905560408051838152602081018390527f5ba5bfb53e85b015ce3b9ccbb1c00fe1fbee62fe700c131b5835bed2982a73d091016111ff565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361173b5760405162461bcd60e51b81526004016112539061472b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166117835f80516020614a84833981519152546001600160a01b031690565b6001600160a01b0316146117a95760405162461bcd60e51b815260040161125390614777565b6117b282612a43565b6117be82826001612a76565b5050565b5f306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118615760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401611253565b505f80516020614a8483398151915290565b61187b6129e9565b5f8281527f366700fa4a54fabf41470ae21330c7a9ced6ce535b281916c3ea8a91b225034d6020526040812080548392906118c09084906001600160801b031661470b565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505050565b6118f061289e565b61010154600160a01b900460ff16158061190b575061010054155b8061191857506101005442105b1561193657604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166119605760405163206d376f60e01b815260040160405180910390fd5b5f61196a85612f6a565b90505f611979828686866130bd565b610101546001600160801b0391909116915061199f906001600160a01b0316838361297f565b50506119ab6001606555565b50505050565b6119b96129e9565b61010154600160a01b900460ff16156119e55760405163f1a3368f60e01b815260040160405180910390fd5b610101546001600160a01b0316611a0f5760405163206d376f60e01b815260040160405180910390fd5b610101546117be906001600160a01b0316838361297f565b611a2f6129e9565b611a385f6131dc565b565b611a426129e9565b6101018054821515600160a01b0260ff60a01b199091161790556040517f7d9bc7474aa5661520727056d5036520e3004dfa67eebc8ea98dd139b044aae190610ba890831515815260200190565b611a986129e9565b61010055565b5f805b82811015611b05575f611acc86868685818110611ac057611ac0614684565b905060200201356112f1565b509050806001600160801b03165f03611ae55750611af3565b611aef818461470b565b9250505b80611afd816147da565b915050611aa1565b509392505050565b611b1561289e565b61010154600160a01b900460ff161580611b30575061010054155b80611b3d57506101005442105b15611b5b57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b0316611b855760405163206d376f60e01b815260040160405180910390fd5b60fc546001600160a01b0316336001600160a01b031614611bb8576040516282b42960e81b815260040160405180910390fd5b5f611bc5858585856130bd565b610101546001600160801b03919091169150611beb906001600160a01b0316868361297f565b506119ab6001606555565b604080518082019091525f8152606060208201526101055f836004811115611c2057611c206146b1565b6004811115611c3157611c316146b1565b81526020019081526020015f206040518060400160405290815f820154815260200160018201805480602002602001604051908101604052809291908181526020018280548015611c9f57602002820191905f5260205f20905b815481526020019060010190808311611c8b575b5050505050815250509050919050565b611cb76129e9565b60fc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f82815b81811015611d3857858582818110611cf957611cf9614684565b9050602002810190611d0b91906147f2565b611d19906020810190614810565b611d249150846146c5565b925080611d30816147da565b915050611cdf565b50816001600160401b03811115611d5157611d5161420c565b604051908082528060200260200182016040528015611dce57816020015b60408051610140810182525f8082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282525f19909201910181611d6f5790505b5092505f805b828110156120d3575f878783818110611def57611def614684565b9050602002810190611e0191906147f2565b3590505f888884818110611e1757611e17614684565b9050602002810190611e2991906147f2565b611e37906020810190614810565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509394505050505b81518110156120bd575f80611e9885858581518110611e8b57611e8b614684565b60200260200101516112f1565b915091505f80611ec187878781518110611eb457611eb4614684565b60200260200101516120dd565b91509150604051806101400160405280888152602001878781518110611ee957611ee9614684565b60200260200101518152602001856001600160801b031681526020018481526020016101045f8a81526020019081526020015f205f898981518110611f3057611f30614684565b60209081029190910181015182528181019290925260409081015f908120546001600160801b031684528b815261010483529081208a5193909201928a908a908110611f7e57611f7e614684565b602002602001015181526020019081526020015f206001015f9054906101000a90046001600160801b03166001600160801b03168152602001836001600160801b031681526020018281526020016101045f8a81526020019081526020015f205f898981518110611ff157611ff1614684565b602002602001015181526020019081526020015f205f0160109054906101000a90046001600160801b03166001600160801b031681526020016101045f8a81526020019081526020015f205f89898151811061204f5761204f614684565b60209081029190910181015182528101919091526040015f2060010154600160801b90046001600160801b031690528c8a612089816147da565b9b508151811061209b5761209b614684565b60200260200101819052505050505080806120b5906147da565b915050611e6a565b50505080806120cb906147da565b915050611dd4565b5050505092915050565b610101545f908190600160a01b900460ff1615806120fc575061010054155b8061210957506101005442105b1561212757604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166121515760405163206d376f60e01b815260040160405180910390fd5b60fd54849081106121755760405163017e9c7d60e41b815260040160405180910390fd5b5f85815261010460209081526040808320878452825291829020825160808101845281546001600160801b038082168352600160801b918290048116948301949094526001909201548084169482019490945292041660608201526121d98161322d565b9350625af7806101005461143591906146c5565b60fd81815481106121fc575f80fd5b5f918252602090912001546001600160a01b0316905081565b61221d6129e9565b5f5b81811015610b25575f83838381811061223a5761223a614684565b9050608002015f013590505f84848481811061225857612258614684565b9050608002016020013590505f85858581811061227757612277614684565b905060800201604001602081019061228f9190614698565b90505f8686868181106122a4576122a4614684565b90506080020160600160208101906122bc9190614698565b5f94855261010460209081526040808720958752949052929093206001600160801b03928316600160801b02919092161790555060010161221f565b61230061289e565b61010154600160a01b900460ff16158061231b575061010054155b8061232857506101005442105b1561234657604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166123705760405163206d376f60e01b815260040160405180910390fd5b5f61237a84612f6a565b90505f6123b9828585808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506128f792505050565b610101546001600160801b039190911691506123df906001600160a01b0316838361297f565b5050610b256001606555565b6123f36129e9565b61010154600160b81b900460ff161561241f57604051639a8d50df60e01b815260040160405180910390fd5b610101805460ff60b81b1916600160b81b17905560fb80546001600160a01b03191690556040515f81527fef1cd24a01120da2689be4a7980f64da049419dcd5866a87bff7b5d978a5078c9060200160405180910390a1565b6124806129e9565b6001600160a01b0381166124e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611253565b6112ee816131dc565b6124f66129e9565b61010154600160a01b900460ff16156125225760405163f1a3368f60e01b815260040160405180910390fd5b808381146125435760405163a121188760e01b815260040160405180910390fd5b5f5b818110156126f9575f84848381811061256057612560614684565b905060200281019061257291906147f2565b612580906020810190614810565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509394505050505b8151811015612663576127108282815181106125d1576125d1614684565b602002602001015111156125f857604051630a6428c360e11b815260040160405180910390fd5b801561265b578161260a6001836146d8565b8151811061261a5761261a614684565b602002602001015182828151811061263457612634614684565b6020026020010151101561265b57604051630a6428c360e11b815260040160405180910390fd5b6001016125b3565b5084848381811061267657612676614684565b905060200281019061268891906147f2565b6101055f89898681811061269e5761269e614684565b90506020020160208101906126b391906143ca565b60048111156126c4576126c46146b1565b60048111156126d5576126d56146b1565b81526020019081526020015f2081816126ee9190614855565b505050600101612545565b505050505050565b5f54610100900460ff161580801561271f57505f54600160ff909116105b806127385750303b15801561273857505f5460ff166001145b61279b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611253565b5f805460ff1916600117905580156127bc575f805461ff0019166101001790555b6127c46132a4565b6127cc6132ca565b6127d46132f9565b60fe80546001600160a01b03199081166d76a84fef008cdabe6409d2fe638b1790915560ff805482166c447e69651d841bd8d104bed49317905561010180546001600160a01b03888116919093161790556040805160608101825286831681528583166020820152918416908201526128519060fd906003613f67565b508015612897575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6002606554036128f05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611253565b6002606555565b5f612902838361331f565b9050806001600160801b03165f0361292d576040516358c45ad560e01b815260040160405180910390fd5b604080516001600160801b03831681524260208201526001600160a01b038516917f7a61a2933ee34cf5cca59f8cd920eb077db0bd64d01b5f67c1387e2e4f0a81ec910160405180910390a292915050565b6040516001600160a01b038316602482015260448101829052610b2590849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613438565b6001606555565b60c9546001600160a01b03163314611a385760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611253565b60fb546001600160a01b0316336001600160a01b0316146112ee576040516282b42960e81b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612aa957610b258361350b565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612b03575060408051601f3d908101601f19168201909252612b009181019061490d565b60015b612b665760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401611253565b5f80516020614a848339815191528114612bd45760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401611253565b50610b258383836135a6565b610101545f90600160c01b90046001600160401b0316808203612c0557505f92915050565b6127108103612c3f5761010254612c3090625af78090600160401b90046001600160801b03166146c5565b421115612c3f57505f92915050565b825160408401516001600160801b0382161580612c6e5750816001600160801b0316816001600160801b031610155b15612c7d57505f949350505050565b612c8f612c89836135ca565b82613648565b95945050505050565b815160208301515f91906001600160801b0382161580612cca5750816001600160801b0316816001600160801b031610155b15612cd9575f92505050612f2c565b5f846004811115612cec57612cec6146b1565b03612d1c57625af78061010054612d0391906146c5565b421115612d14575f92505050612f2c565b509050612f2c565b5f6101055f866004811115612d3357612d336146b1565b6004811115612d4457612d446146b1565b81526020019081526020015f206040518060400160405290815f820154815260200160018201805480602002602001604051908101604052809291908181526020018280548015612db257602002820191905f5260205f20905b815481526020019060010190808311612d9e575b50505050508152505090505f8160200151519050805f03612de657604051630a6428c360e11b815260040160405180910390fd5b625af780612df58260b46147c3565b612e0290620151806147c3565b61010054612e1091906146c5565b612e1a91906146c5565b421115612e2d575f945050505050612f2c565b5f620151806101005442612e4191906146d8565b612e4b9190614938565b90505f612e5960b483614938565b90506002886004811115612e6f57612e6f6146b1565b148015612e7c575060b482105b15612e8f575f9650505050505050612f2c565b5f6004896004811115612ea457612ea46146b1565b14158015612eb3575060048210155b90505f60048a6004811115612eca57612eca6146b1565b148015612ed8575060088310155b90508180612ee35750805b15612f0157612ef28888613648565b98505050505050505050612f2c565b612f21612f1b87878b612f158860016146c5565b89613674565b88613648565b985050505050505050505b92915050565b6040516001600160a01b03808516602483015283166044820152606481018290526119ab9085906323b872dd60e01b906084016129ab565b5f6001600160a01b038216612f7f5733612f2c565b60ff545f906001600160a01b031663e839bd53336040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290861660248201525f6044820152606401602060405180830381865afa158015612fe3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613007919061494b565b90508015613016575090919050565b60fe546001600160a01b0316639c395bc2336040516001600160e01b031960e084901b1681526001600160a01b0391821660048201529086166024820152604401602060405180830381865afa158015613072573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613096919061494b565b9050806130b657604051632d618d8160e21b815260040160405180910390fd5b5090919050565b5f6130c9858585613712565b9050811561315f576001600160a01b0385165f908152610103602090815260408083208380528252808320815180830190925280546001600160801b038082168452600160801b90910416928201929092529091906131289082612c98565b90506001600160801b0381161561315c5781546001600160801b03600160801b808304821684018216029116178255918201915b50505b806001600160801b03165f03613188576040516358c45ad560e01b815260040160405180910390fd5b604080516001600160801b03831681524260208201526001600160a01b038716917f6bae97ad4b952cdee3720ed0ea228b5eb79d5adb4475c05d9f3f6539627d8e2a910160405180910390a2949350505050565b60c980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b602081015160608201515f91906001600160801b03821615806132625750816001600160801b0316816001600160801b031610155b1561327057505f9392505050565b625af7806101005461328291906146c5565b42111561329257505f9392505050565b61329c8282613648565b949350505050565b5f54610100900460ff166129e25760405162461bcd60e51b815260040161125390614966565b5f54610100900460ff166132f05760405162461bcd60e51b815260040161125390614966565b611a38336131dc565b5f54610100900460ff16611a385760405162461bcd60e51b815260040161125390614966565b5f805b8251811015613431576001600160a01b0384165f908152610103602052604081208451829086908590811061335957613359614684565b60200260200101516004811115613372576133726146b1565b6004811115613383576133836146b1565b815260208082019290925260409081015f908120825180840190935280546001600160801b038082168552600160801b90910416938301939093528651929350916133e891908790869081106133db576133db614684565b6020026020010151612c98565b90506001600160801b0381161561341c5781546001600160801b03600160801b808304821684018216029116178255928301925b50508080613429906147da565b915050613322565b5092915050565b5f61348c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139cf9092919063ffffffff16565b905080515f14806134ac5750808060200190518101906134ac919061494b565b610b255760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611253565b6001600160a01b0381163b6135785760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401611253565b5f80516020614a8483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6135af836139dd565b5f825111806135bb5750805b15610b25576119ab8383613a1c565b610102545f90600160401b90046001600160801b031642106136295761010154613624906127109061360c90600160c01b90046001600160401b0316856149b1565b6001600160801b031661361f9190614938565b613a41565b612f2c565b61010254612f2c906127109061360c906001600160401b0316856149b1565b5f816001600160801b0316836001600160801b0316111561366b5781830361366d565b5f5b9392505050565b84515f9083101561368657505f612c8f565b84831115613695575082612c8f565b5f8584146136c057866020015184815181106136b3576136b3614684565b60200260200101516136c4565b6127105b90506137078588602001516001876136dc91906146d8565b815181106136ec576136ec614684565b60200260200101518360b48761370291906149dc565b613a6a565b979650505050505050565b5f805b82811015611b0557365f85858481811061373157613731614684565b905060200281019061374391906149ef565b613751906020810190614810565b91509150365f87878681811061376957613769614684565b905060200281019061377b91906149ef565b613789906040810190614810565b91509150365f8989888181106137a1576137a1614684565b90506020028101906137b391906149ef565b6137c1906060810190614810565b90925090508483811415806137d65750808214155b156137f45760405163a121188760e01b815260040160405180910390fd5b5f8b8b8a81811061380757613807614684565b905060200281019061381991906149ef565b3590505f5b828110156139bb575f87878381811061383957613839614684565b905060200201602081019061384e91906143af565b156138ec576138768f848c8c8681811061386a5761386a614684565b90506020020135613b0a565b90506001600160801b038116156138ec575f8381526101046020526040812082918c8c868181106138a9576138a9614684565b602090810292909201358352508101919091526040015f2060010180546001600160801b031981166001600160801b0391821693909301169190911790559a8b019a5b8585838181106138fe576138fe614684565b905060200201602081019061391391906143af565b156139b25761393b8f848c8c8681811061392f5761392f614684565b90506020020135613c4a565b90506001600160801b038116156139b2575f8381526101046020526040812082918c8c8681811061396e5761396e614684565b602090810292909201358352508101919091526040015f2060010180546001600160801b03600160801b8083048216909401811690930292169190911790559a8b019a5b5060010161381e565b508860010198505050505050505050613715565b606061329c84845f85613d8a565b6139e68161350b565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061366d8383604051806060016040528060278152602001614aa460279139613e56565b5f600160801b8210613a665760405163ede341c760e01b815260040160405180910390fd5b5090565b5f815f03613a9c57613a95612710613a8b866001600160801b0389166147c3565b61361f9190614938565b905061329c565b612c8f60b461271084613aaf88886146d8565b613ac2906001600160801b038b166147c3565b613acc91906147c3565b613ad69190614938565b613ae09190614938565b612710613af6876001600160801b038a166147c3565b613b009190614938565b61361f91906146c5565b60fd545f9083908110613b305760405163017e9c7d60e41b815260040160405180910390fd5b846001600160a01b031660fd8581548110613b4d57613b4d614684565b5f918252602090912001546040516331a9108f60e11b8152600481018690526001600160a01b0390911690636352211e90602401602060405180830381865afa158015613b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bc09190614a03565b6001600160a01b031614613be6576040516282b42960e81b815260040160405180910390fd5b5f84815261010460209081526040808320868452825291829020825160808101845281546001600160801b038082168352600160801b91829004811694830194909452600190920154808416948201949094529204166060820152612c8f90612be0565b60fd545f9083908110613c705760405163017e9c7d60e41b815260040160405180910390fd5b846001600160a01b031660fd8581548110613c8d57613c8d614684565b5f918252602090912001546040516331a9108f60e11b8152600481018690526001600160a01b0390911690636352211e90602401602060405180830381865afa158015613cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d009190614a03565b6001600160a01b031614613d26576040516282b42960e81b815260040160405180910390fd5b5f84815261010460209081526040808320868452825291829020825160808101845281546001600160801b038082168352600160801b91829004811694830194909452600190920154808416948201949094529204166060820152612c8f9061322d565b606082471015613deb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611253565b5f80866001600160a01b03168587604051613e069190614a40565b5f6040518083038185875af1925050503d805f8114613e40576040519150601f19603f3d011682016040523d82523d5f602084013e613e45565b606091505b509150915061370787838387613eca565b60605f80856001600160a01b031685604051613e729190614a40565b5f60405180830381855af49150503d805f8114613eaa576040519150601f19603f3d011682016040523d82523d5f602084013e613eaf565b606091505b5091509150613ec086838387613eca565b9695505050505050565b60608315613f385782515f03613f31576001600160a01b0385163b613f315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611253565b508161329c565b61329c8383815115613f4d5781518083602001fd5b8060405162461bcd60e51b81526004016112539190614a51565b828054828255905f5260205f20908101928215613fba579160200282015b82811115613fba57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613f85565b50613a669291505b80821115613a66575f8155600101613fc2565b6001600160a01b03811681146112ee575f80fd5b5f8083601f840112613ff9575f80fd5b5081356001600160401b0381111561400f575f80fd5b6020830191508360208260051b8501011115614029575f80fd5b9250929050565b5f805f60408486031215614042575f80fd5b833561404d81613fd5565b925060208401356001600160401b03811115614067575f80fd5b61407386828701613fe9565b9497909650939450505050565b5f60208284031215614090575f80fd5b813561366d81613fd5565b80356001600160801b03811681146140b1575f80fd5b919050565b5f80604083850312156140c7575f80fd5b82356001600160401b03811681146140dd575f80fd5b91506140eb6020840161409b565b90509250929050565b5f805f805f8060608789031215614109575f80fd5b86356001600160401b038082111561411f575f80fd5b61412b8a838b01613fe9565b90985096506020890135915080821115614143575f80fd5b61414f8a838b01613fe9565b90965094506040890135915080821115614167575f80fd5b5061417489828a01613fe9565b979a9699509497509295939492505050565b5f805f60408486031215614198575f80fd5b8335925060208401356001600160401b03811115614067575f80fd5b5f80604083850312156141c5575f80fd5b50508035926020909101359150565b8035600581106140b1575f80fd5b5f80604083850312156141f3575f80fd5b82356141fe81613fd5565b91506140eb602084016141d4565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215614231575f80fd5b823561423c81613fd5565b915060208301356001600160401b0380821115614257575f80fd5b818501915085601f83011261426a575f80fd5b81358181111561427c5761427c61420c565b604051601f8201601f19908116603f011681019083821181831017156142a4576142a461420c565b816040528281528860208487010111156142bc575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156142ee575f80fd5b823591506140eb6020840161409b565b80151581146112ee575f80fd5b5f805f806060858703121561431e575f80fd5b843561432981613fd5565b935060208501356001600160401b03811115614343575f80fd5b61434f87828801613fe9565b9094509250506040850135614363816142fe565b939692955090935050565b5f806040838503121561437f575f80fd5b823561438a81613fd5565b946020939093013593505050565b5f602082840312156143a8575f80fd5b5035919050565b5f602082840312156143bf575f80fd5b813561366d816142fe565b5f602082840312156143da575f80fd5b61366d826141d4565b6020808252825182820152828101516040808401528051606084018190525f9291820190839060808601905b8083101561442f578351825292840192600192909201919084019061440f565b509695505050505050565b5f806020838503121561444b575f80fd5b82356001600160401b03811115614460575f80fd5b61446c85828601613fe9565b90969095509350505050565b602080825282518282018190525f919060409081850190868401855b82811015614521578151805185528681015187860152858101516001600160801b03908116878701526060808301519087015260808083015182169087015260a08083015182169087015260c08083015182169087015260e08083015190870152610100808301518216908701526101209182015116908501526101409093019290850190600101614494565b5091979650505050505050565b5f806020838503121561453f575f80fd5b82356001600160401b0380821115614555575f80fd5b818501915085601f830112614568575f80fd5b813581811115614576575f80fd5b8660208260071b850101111561458a575f80fd5b60209290920196919550909350505050565b5f805f80604085870312156145af575f80fd5b84356001600160401b03808211156145c5575f80fd5b6145d188838901613fe9565b909650945060208701359150808211156145e9575f80fd5b506145f687828801613fe9565b95989497509550505050565b5f805f8060808587031215614615575f80fd5b843561462081613fd5565b9350602085013561463081613fd5565b9250604085013561464081613fd5565b9150606085013561436381613fd5565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b0381811683821601908082111561343157613431614650565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156146a8575f80fd5b61366d8261409b565b634e487b7160e01b5f52602160045260245ffd5b80820180821115612f2c57612f2c614650565b81810381811115612f2c57612f2c614650565b6001600160801b0382811682821603908082111561343157613431614650565b6001600160801b0381811683821601908082111561343157613431614650565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b8082028115828204841417612f2c57612f2c614650565b5f600182016147eb576147eb614650565b5060010190565b5f8235603e19833603018112614806575f80fd5b9190910192915050565b5f808335601e19843603018112614825575f80fd5b8301803591506001600160401b0382111561483e575f80fd5b6020019150600581901b3603821315614029575f80fd5b813581556001808201602080850135601e19863603018112614875575f80fd5b850180356001600160401b0381111561488c575f80fd5b82820191508060051b36038213156148a2575f80fd5b600160401b8111156148b6576148b661420c565b8354818555808210156148e9575f8581528481208381019083015b808210156148e557828255908801906148d1565b5050505b505f93845260208420935b81811015610def578235858201559183019185016148f4565b5f6020828403121561491d575f80fd5b5051919050565b634e487b7160e01b5f52601260045260245ffd5b5f8261494657614946614924565b500490565b5f6020828403121561495b575f80fd5b815161366d816142fe565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160801b038181168382160280821691908281146149d4576149d4614650565b505092915050565b5f826149ea576149ea614924565b500690565b5f8235607e19833603018112614806575f80fd5b5f60208284031215614a13575f80fd5b815161366d81613fd5565b5f5b83811015614a38578181015183820152602001614a20565b50505f910152565b5f8251614806818460208701614a1e565b602081525f8251806020840152614a6f816040850160208701614a1e565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208edb9f3a17f4af48ff75923f9d90dfcc99c86889fa497046674e279890be8f5564736f6c63430008150033
Deployed Bytecode
0x6080604052600436106102a5575f3560e01c806374a4e4431161016f578063b607bc30116100d8578063e274842911610092578063f2fde38b1161006d578063f2fde38b14610983578063f60c7158146109a2578063f8c8765e146109c1578063f92b41bd146109e0575f80fd5b8063e274842914610930578063f0fd108414610950578063f163d7121461096f575f80fd5b8063b607bc3014610854578063bc5800e514610893578063bfca66c9146108b2578063c6e4fc93146108d1578063d4a6a2fd146108f0578063d8a531a614610911575f80fd5b80638da5cb5b116101295780638da5cb5b14610782578063976289171461079f578063ab14dee4146107be578063af269745146107ea578063b21185b314610809578063b4ab6cf114610828575f80fd5b806374a4e443146106c45780637b2d3e69146106e55780638110c50f146107045780638131fd161461072557806385c23195146107445780638ad0838d14610763575f80fd5b80634d9c41a711610211578063675151b2116101cb578063675151b2146105a85780636afffd90146105c75780636d5bc5ca146105e65780636e35d39514610646578063715018a61461069157806373417b09146106a5575f80fd5b80634d9c41a71461046e5780634f1ef286146104ad57806351fa7cc2146104c057806352d1902d146105515780635f03b6b214610573578063648de06b14610589575f80fd5b80633659cfe6116102625780633659cfe6146103655780633c11bdd614610384578063416b3e1e146103c7578063427fa204146103e65780634451d89f14610417578063474954c31461044f575f80fd5b806319a8b4a0146102a95780631b878f71146102ca5780631d671c5b146102e9578063232275c1146103085780632f1521581461032757806332e52ae114610346575b5f80fd5b3480156102b4575f80fd5b506102c86102c3366004614030565b610a0c565b005b3480156102d5575f80fd5b506102c86102e4366004614080565b610b2a565b3480156102f4575f80fd5b506102c86103033660046140b6565b610bb3565b348015610313575f80fd5b506102c86103223660046140f4565b610cbf565b348015610332575f80fd5b506102c8610341366004614186565b610df9565b348015610351575f80fd5b506102c8610360366004614080565b6110b9565b348015610370575f80fd5b506102c861037f366004614080565b61120b565b34801561038f575f80fd5b506103a361039e3660046141b4565b6112f1565b604080516001600160801b0390931683526020830191909152015b60405180910390f35b3480156103d2575f80fd5b506103a36103e13660046141e2565b611440565b3480156103f1575f80fd5b506101015461040790600160b01b900460ff1681565b60405190151581526020016103be565b348015610422575f80fd5b5061010154610437906001600160a01b031681565b6040516001600160a01b0390911681526020016103be565b34801561045a575f80fd5b506102c86104693660046141b4565b6115ea565b348015610479575f80fd5b506101025461049590600160401b90046001600160801b031681565b6040516001600160801b0390911681526020016103be565b6102c86104bb366004614220565b6116f3565b3480156104cb575f80fd5b5061051e6104da3660046141b4565b61010460209081525f9283526040808420909152908252902080546001909101546001600160801b0380831692600160801b90819004821692808316929190041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103be565b34801561055c575f80fd5b506105656117c2565b6040519081526020016103be565b34801561057e575f80fd5b506105656101005481565b348015610594575f80fd5b506102c86105a33660046142dd565b611873565b3480156105b3575f80fd5b506102c86105c236600461430b565b6118e8565b3480156105d2575f80fd5b506102c86105e136600461436e565b6119b1565b3480156105f1575f80fd5b50610626610600366004614398565b6101066020525f90815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016103be565b348015610651575f80fd5b506106266106603660046141e2565b61010360209081525f92835260408084209091529082529020546001600160801b0380821691600160801b90041682565b34801561069c575f80fd5b506102c8611a27565b3480156106b0575f80fd5b506102c86106bf3660046143af565b611a3a565b3480156106cf575f80fd5b506101015461040790600160a81b900460ff1681565b3480156106f0575f80fd5b506102c86106ff366004614398565b611a90565b34801561070f575f80fd5b506101015461040790600160b81b900460ff1681565b348015610730575f80fd5b5060fc54610437906001600160a01b031681565b34801561074f575f80fd5b5060ff54610437906001600160a01b031681565b34801561076e575f80fd5b5061049561077d366004614186565b611a9e565b34801561078d575f80fd5b5060c9546001600160a01b0316610437565b3480156107aa575f80fd5b506102c86107b936600461430b565b611b0d565b3480156107c9575f80fd5b506107dd6107d83660046143ca565b611bf6565b6040516103be91906143e3565b3480156107f5575f80fd5b5060fb54610437906001600160a01b031681565b348015610814575f80fd5b506102c8610823366004614080565b611caf565b348015610833575f80fd5b5061084761084236600461443a565b611cd9565b6040516103be9190614478565b34801561085f575f80fd5b506101015461087b90600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016103be565b34801561089e575f80fd5b506103a36108ad3660046141b4565b6120dd565b3480156108bd575f80fd5b506104376108cc366004614398565b6121ed565b3480156108dc575f80fd5b506102c86108eb36600461452e565b612215565b3480156108fb575f80fd5b506101015461040790600160a01b900460ff1681565b34801561091c575f80fd5b5060fe54610437906001600160a01b031681565b34801561093b575f80fd5b506101025461087b906001600160401b031681565b34801561095b575f80fd5b506102c861096a366004614030565b6122f8565b34801561097a575f80fd5b506102c86123eb565b34801561098e575f80fd5b506102c861099d366004614080565b612478565b3480156109ad575f80fd5b506102c86109bc36600461459c565b6124ee565b3480156109cc575f80fd5b506102c86109db366004614602565b612701565b3480156109eb575f80fd5b506105656109fa3660046143ca565b6101056020525f908152604090205481565b610a1461289e565b61010154600160a01b900460ff161580610a2f575061010054155b80610a3c57506101005442105b15610a5a57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b0316610a845760405163206d376f60e01b815260040160405180910390fd5b60fc546001600160a01b0316336001600160a01b031614610ab7576040516282b42960e81b815260040160405180910390fd5b5f610af4848484808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506128f792505050565b610101546001600160801b03919091169150610b1a906001600160a01b0316858361297f565b50610b256001606555565b505050565b610b326129e9565b61010154600160b81b900460ff1615610b5e57604051639a8d50df60e01b815260040160405180910390fd5b60fb80546001600160a01b0319166001600160a01b0383169081179091556040519081527fef1cd24a01120da2689be4a7980f64da049419dcd5866a87bff7b5d978a5078c906020015b60405180910390a150565b610bbb6129e9565b6101015461010254600160c01b9091046001600160401b0390811691600160401b90046001600160801b03169084161580610c095750612710610bfe8584614664565b6001600160401b0316115b80610c265750806001600160801b0316836001600160801b031611155b15610c4457604051630a6428c360e11b815260040160405180910390fd5b61010280546001600160401b038481166001600160c01b031990921691909117600160401b6001600160801b038716021790915561010180548692601891610c95918591600160c01b900416614664565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050505050565b610cc76129e9565b848381141580610cd75750808214155b15610cf55760405163a121188760e01b815260040160405180910390fd5b5f5b81811015610def57858582818110610d1157610d11614684565b9050602002016020810190610d269190614698565b6101035f8a8a85818110610d3c57610d3c614684565b9050602002016020810190610d519190614080565b6001600160a01b03166001600160a01b031681526020019081526020015f205f868685818110610d8357610d83614684565b9050602002016020810190610d9891906143ca565b6004811115610da957610da96146b1565b6004811115610dba57610dba6146b1565b815260208101919091526040015f2080546001600160801b0319166001600160801b0392909216919091179055600101610cf7565b5050505050505050565b60fd5483908110610e1d5760405163017e9c7d60e41b815260040160405180910390fd5b610e256129e9565b625af78061010054610e3791906146c5565b4211610e5657604051632e9cc64960e21b815260040160405180910390fd5b5f8481526101066020526040902082801580610ea5575084845f818110610e7f57610e7f614684565b9050602002016020810190610e949190614698565b82546001600160801b039182169116115b15610ec357604051633be4064960e01b815260040160405180910390fd5b5f805b82811015611024578015610f5d578686610ee16001846146d8565b818110610ef057610ef0614684565b9050602002016020810190610f059190614698565b6001600160801b0316878783818110610f2057610f20614684565b9050602002016020810190610f359190614698565b6001600160801b03161015610f5d57604051633be4064960e01b815260040160405180910390fd5b5f8881526101046020526040812081898985818110610f7e57610f7e614684565b9050602002016020810190610f939190614698565b6001600160801b03908116825260208083019390935260409182015f908120835160808101855281548085168252600160801b9081900485169682018790526001909201548085169582019590955293049091166060830181905291935091610ffc91906146eb565b90506001600160801b0381161561101a57611017818561470b565b93505b5050600101610ec6565b5085856110326001856146d8565b81811061104157611041614684565b90506020020160208101906110569190614698565b83546001600160801b0319166001600160801b03918216178085558291859160109161108c918591600160801b9091041661470b565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b6110c16129e9565b61010154600160b01b900460ff16156110ed57604051636507689f60e01b815260040160405180910390fd5b625af780610100546110ff91906146c5565b421161111e57604051632e9cc64960e21b815260040160405180910390fd5b6001600160a01b03811661114557604051633be4064960e01b815260040160405180910390fd5b5f805b60fd548110156111b9575f818152610106602052604090208054600160801b90046001600160801b031680156111af5761010154611199906001600160a01b0316866001600160801b03841661297f565b6111ac6001600160801b038216856146c5565b93505b5050600101611148565b50610101805460ff60b01b1916600160b01b179055604080518281524260208201527f51c3c049b061ef6ad9b287a90842a19c63db19253589bf999293790b4adffa1491015b60405180910390a15050565b6001600160a01b037f000000000000000000000000dc79d2c13ec218049405836a74454952902ec42d16300361125c5760405162461bcd60e51b81526004016112539061472b565b60405180910390fd5b7f000000000000000000000000dc79d2c13ec218049405836a74454952902ec42d6001600160a01b03166112a45f80516020614a84833981519152546001600160a01b031690565b6001600160a01b0316146112ca5760405162461bcd60e51b815260040161125390614777565b6112d381612a43565b604080515f808252602082019092526112ee91839190612a76565b50565b610101545f908190600160a01b900460ff161580611310575061010054155b8061131d57506101005442105b1561133b57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166113655760405163206d376f60e01b815260040160405180910390fd5b60fd54849081106113895760405163017e9c7d60e41b815260040160405180910390fd5b5f85815261010460209081526040808320878452825291829020825160808101845281546001600160801b038082168352600160801b918290048116948301949094526001909201548084169482019490945292041660608201526113ed81612be0565b610101549094506001600160401b03600160c01b9091041661271014611413575f611435565b6101025461143590625af78090600160401b90046001600160801b03166146c5565b925050509250929050565b610101545f908190600160a01b900460ff16158061145f575061010054155b8061146c57506101005442105b1561148a57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166114b45760405163206d376f60e01b815260040160405180910390fd5b5f6101055f8560048111156114cb576114cb6146b1565b60048111156114dc576114dc6146b1565b81526020019081526020015f2060010180549050905061157b6101035f876001600160a01b03166001600160a01b031681526020019081526020015f205f86600481111561152c5761152c6146b1565b600481111561153d5761153d6146b1565b815260208082019290925260409081015f208151808301909252546001600160801b038082168352600160801b909104169181019190915285612c98565b92505f846004811115611590576115906146b1565b146115ce57625af7806115a48260b46147c3565b6115b190620151806147c3565b610100546115bf91906146c5565b6115c991906146c5565b6115e0565b625af780610100546115e091906146c5565b9150509250929050565b6115f26129e9565b61010154600160a81b900460ff161561161e5760405163d5a8211560e01b815260040160405180910390fd5b610101546001600160a01b03166116485760405163206d376f60e01b815260040160405180910390fd5b815f0361166857604051630a6428c360e11b815260040160405180910390fd5b805f0361168857604051630a6428c360e11b815260040160405180910390fd5b6116a133610101546001600160a01b0316903085612f32565b610100819055610101805461ffff60a01b191661010160a01b17905560408051838152602081018390527f5ba5bfb53e85b015ce3b9ccbb1c00fe1fbee62fe700c131b5835bed2982a73d091016111ff565b6001600160a01b037f000000000000000000000000dc79d2c13ec218049405836a74454952902ec42d16300361173b5760405162461bcd60e51b81526004016112539061472b565b7f000000000000000000000000dc79d2c13ec218049405836a74454952902ec42d6001600160a01b03166117835f80516020614a84833981519152546001600160a01b031690565b6001600160a01b0316146117a95760405162461bcd60e51b815260040161125390614777565b6117b282612a43565b6117be82826001612a76565b5050565b5f306001600160a01b037f000000000000000000000000dc79d2c13ec218049405836a74454952902ec42d16146118615760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401611253565b505f80516020614a8483398151915290565b61187b6129e9565b5f8281527f366700fa4a54fabf41470ae21330c7a9ced6ce535b281916c3ea8a91b225034d6020526040812080548392906118c09084906001600160801b031661470b565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505050565b6118f061289e565b61010154600160a01b900460ff16158061190b575061010054155b8061191857506101005442105b1561193657604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166119605760405163206d376f60e01b815260040160405180910390fd5b5f61196a85612f6a565b90505f611979828686866130bd565b610101546001600160801b0391909116915061199f906001600160a01b0316838361297f565b50506119ab6001606555565b50505050565b6119b96129e9565b61010154600160a01b900460ff16156119e55760405163f1a3368f60e01b815260040160405180910390fd5b610101546001600160a01b0316611a0f5760405163206d376f60e01b815260040160405180910390fd5b610101546117be906001600160a01b0316838361297f565b611a2f6129e9565b611a385f6131dc565b565b611a426129e9565b6101018054821515600160a01b0260ff60a01b199091161790556040517f7d9bc7474aa5661520727056d5036520e3004dfa67eebc8ea98dd139b044aae190610ba890831515815260200190565b611a986129e9565b61010055565b5f805b82811015611b05575f611acc86868685818110611ac057611ac0614684565b905060200201356112f1565b509050806001600160801b03165f03611ae55750611af3565b611aef818461470b565b9250505b80611afd816147da565b915050611aa1565b509392505050565b611b1561289e565b61010154600160a01b900460ff161580611b30575061010054155b80611b3d57506101005442105b15611b5b57604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b0316611b855760405163206d376f60e01b815260040160405180910390fd5b60fc546001600160a01b0316336001600160a01b031614611bb8576040516282b42960e81b815260040160405180910390fd5b5f611bc5858585856130bd565b610101546001600160801b03919091169150611beb906001600160a01b0316868361297f565b506119ab6001606555565b604080518082019091525f8152606060208201526101055f836004811115611c2057611c206146b1565b6004811115611c3157611c316146b1565b81526020019081526020015f206040518060400160405290815f820154815260200160018201805480602002602001604051908101604052809291908181526020018280548015611c9f57602002820191905f5260205f20905b815481526020019060010190808311611c8b575b5050505050815250509050919050565b611cb76129e9565b60fc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f82815b81811015611d3857858582818110611cf957611cf9614684565b9050602002810190611d0b91906147f2565b611d19906020810190614810565b611d249150846146c5565b925080611d30816147da565b915050611cdf565b50816001600160401b03811115611d5157611d5161420c565b604051908082528060200260200182016040528015611dce57816020015b60408051610140810182525f8082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282525f19909201910181611d6f5790505b5092505f805b828110156120d3575f878783818110611def57611def614684565b9050602002810190611e0191906147f2565b3590505f888884818110611e1757611e17614684565b9050602002810190611e2991906147f2565b611e37906020810190614810565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509394505050505b81518110156120bd575f80611e9885858581518110611e8b57611e8b614684565b60200260200101516112f1565b915091505f80611ec187878781518110611eb457611eb4614684565b60200260200101516120dd565b91509150604051806101400160405280888152602001878781518110611ee957611ee9614684565b60200260200101518152602001856001600160801b031681526020018481526020016101045f8a81526020019081526020015f205f898981518110611f3057611f30614684565b60209081029190910181015182528181019290925260409081015f908120546001600160801b031684528b815261010483529081208a5193909201928a908a908110611f7e57611f7e614684565b602002602001015181526020019081526020015f206001015f9054906101000a90046001600160801b03166001600160801b03168152602001836001600160801b031681526020018281526020016101045f8a81526020019081526020015f205f898981518110611ff157611ff1614684565b602002602001015181526020019081526020015f205f0160109054906101000a90046001600160801b03166001600160801b031681526020016101045f8a81526020019081526020015f205f89898151811061204f5761204f614684565b60209081029190910181015182528101919091526040015f2060010154600160801b90046001600160801b031690528c8a612089816147da565b9b508151811061209b5761209b614684565b60200260200101819052505050505080806120b5906147da565b915050611e6a565b50505080806120cb906147da565b915050611dd4565b5050505092915050565b610101545f908190600160a01b900460ff1615806120fc575061010054155b8061210957506101005442105b1561212757604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166121515760405163206d376f60e01b815260040160405180910390fd5b60fd54849081106121755760405163017e9c7d60e41b815260040160405180910390fd5b5f85815261010460209081526040808320878452825291829020825160808101845281546001600160801b038082168352600160801b918290048116948301949094526001909201548084169482019490945292041660608201526121d98161322d565b9350625af7806101005461143591906146c5565b60fd81815481106121fc575f80fd5b5f918252602090912001546001600160a01b0316905081565b61221d6129e9565b5f5b81811015610b25575f83838381811061223a5761223a614684565b9050608002015f013590505f84848481811061225857612258614684565b9050608002016020013590505f85858581811061227757612277614684565b905060800201604001602081019061228f9190614698565b90505f8686868181106122a4576122a4614684565b90506080020160600160208101906122bc9190614698565b5f94855261010460209081526040808720958752949052929093206001600160801b03928316600160801b02919092161790555060010161221f565b61230061289e565b61010154600160a01b900460ff16158061231b575061010054155b8061232857506101005442105b1561234657604051633c21f90f60e01b815260040160405180910390fd5b610101546001600160a01b03166123705760405163206d376f60e01b815260040160405180910390fd5b5f61237a84612f6a565b90505f6123b9828585808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506128f792505050565b610101546001600160801b039190911691506123df906001600160a01b0316838361297f565b5050610b256001606555565b6123f36129e9565b61010154600160b81b900460ff161561241f57604051639a8d50df60e01b815260040160405180910390fd5b610101805460ff60b81b1916600160b81b17905560fb80546001600160a01b03191690556040515f81527fef1cd24a01120da2689be4a7980f64da049419dcd5866a87bff7b5d978a5078c9060200160405180910390a1565b6124806129e9565b6001600160a01b0381166124e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611253565b6112ee816131dc565b6124f66129e9565b61010154600160a01b900460ff16156125225760405163f1a3368f60e01b815260040160405180910390fd5b808381146125435760405163a121188760e01b815260040160405180910390fd5b5f5b818110156126f9575f84848381811061256057612560614684565b905060200281019061257291906147f2565b612580906020810190614810565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509394505050505b8151811015612663576127108282815181106125d1576125d1614684565b602002602001015111156125f857604051630a6428c360e11b815260040160405180910390fd5b801561265b578161260a6001836146d8565b8151811061261a5761261a614684565b602002602001015182828151811061263457612634614684565b6020026020010151101561265b57604051630a6428c360e11b815260040160405180910390fd5b6001016125b3565b5084848381811061267657612676614684565b905060200281019061268891906147f2565b6101055f89898681811061269e5761269e614684565b90506020020160208101906126b391906143ca565b60048111156126c4576126c46146b1565b60048111156126d5576126d56146b1565b81526020019081526020015f2081816126ee9190614855565b505050600101612545565b505050505050565b5f54610100900460ff161580801561271f57505f54600160ff909116105b806127385750303b15801561273857505f5460ff166001145b61279b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611253565b5f805460ff1916600117905580156127bc575f805461ff0019166101001790555b6127c46132a4565b6127cc6132ca565b6127d46132f9565b60fe80546001600160a01b03199081166d76a84fef008cdabe6409d2fe638b1790915560ff805482166c447e69651d841bd8d104bed49317905561010180546001600160a01b03888116919093161790556040805160608101825286831681528583166020820152918416908201526128519060fd906003613f67565b508015612897575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6002606554036128f05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611253565b6002606555565b5f612902838361331f565b9050806001600160801b03165f0361292d576040516358c45ad560e01b815260040160405180910390fd5b604080516001600160801b03831681524260208201526001600160a01b038516917f7a61a2933ee34cf5cca59f8cd920eb077db0bd64d01b5f67c1387e2e4f0a81ec910160405180910390a292915050565b6040516001600160a01b038316602482015260448101829052610b2590849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613438565b6001606555565b60c9546001600160a01b03163314611a385760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611253565b60fb546001600160a01b0316336001600160a01b0316146112ee576040516282b42960e81b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612aa957610b258361350b565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612b03575060408051601f3d908101601f19168201909252612b009181019061490d565b60015b612b665760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401611253565b5f80516020614a848339815191528114612bd45760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401611253565b50610b258383836135a6565b610101545f90600160c01b90046001600160401b0316808203612c0557505f92915050565b6127108103612c3f5761010254612c3090625af78090600160401b90046001600160801b03166146c5565b421115612c3f57505f92915050565b825160408401516001600160801b0382161580612c6e5750816001600160801b0316816001600160801b031610155b15612c7d57505f949350505050565b612c8f612c89836135ca565b82613648565b95945050505050565b815160208301515f91906001600160801b0382161580612cca5750816001600160801b0316816001600160801b031610155b15612cd9575f92505050612f2c565b5f846004811115612cec57612cec6146b1565b03612d1c57625af78061010054612d0391906146c5565b421115612d14575f92505050612f2c565b509050612f2c565b5f6101055f866004811115612d3357612d336146b1565b6004811115612d4457612d446146b1565b81526020019081526020015f206040518060400160405290815f820154815260200160018201805480602002602001604051908101604052809291908181526020018280548015612db257602002820191905f5260205f20905b815481526020019060010190808311612d9e575b50505050508152505090505f8160200151519050805f03612de657604051630a6428c360e11b815260040160405180910390fd5b625af780612df58260b46147c3565b612e0290620151806147c3565b61010054612e1091906146c5565b612e1a91906146c5565b421115612e2d575f945050505050612f2c565b5f620151806101005442612e4191906146d8565b612e4b9190614938565b90505f612e5960b483614938565b90506002886004811115612e6f57612e6f6146b1565b148015612e7c575060b482105b15612e8f575f9650505050505050612f2c565b5f6004896004811115612ea457612ea46146b1565b14158015612eb3575060048210155b90505f60048a6004811115612eca57612eca6146b1565b148015612ed8575060088310155b90508180612ee35750805b15612f0157612ef28888613648565b98505050505050505050612f2c565b612f21612f1b87878b612f158860016146c5565b89613674565b88613648565b985050505050505050505b92915050565b6040516001600160a01b03808516602483015283166044820152606481018290526119ab9085906323b872dd60e01b906084016129ab565b5f6001600160a01b038216612f7f5733612f2c565b60ff545f906001600160a01b031663e839bd53336040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290861660248201525f6044820152606401602060405180830381865afa158015612fe3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613007919061494b565b90508015613016575090919050565b60fe546001600160a01b0316639c395bc2336040516001600160e01b031960e084901b1681526001600160a01b0391821660048201529086166024820152604401602060405180830381865afa158015613072573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613096919061494b565b9050806130b657604051632d618d8160e21b815260040160405180910390fd5b5090919050565b5f6130c9858585613712565b9050811561315f576001600160a01b0385165f908152610103602090815260408083208380528252808320815180830190925280546001600160801b038082168452600160801b90910416928201929092529091906131289082612c98565b90506001600160801b0381161561315c5781546001600160801b03600160801b808304821684018216029116178255918201915b50505b806001600160801b03165f03613188576040516358c45ad560e01b815260040160405180910390fd5b604080516001600160801b03831681524260208201526001600160a01b038716917f6bae97ad4b952cdee3720ed0ea228b5eb79d5adb4475c05d9f3f6539627d8e2a910160405180910390a2949350505050565b60c980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b602081015160608201515f91906001600160801b03821615806132625750816001600160801b0316816001600160801b031610155b1561327057505f9392505050565b625af7806101005461328291906146c5565b42111561329257505f9392505050565b61329c8282613648565b949350505050565b5f54610100900460ff166129e25760405162461bcd60e51b815260040161125390614966565b5f54610100900460ff166132f05760405162461bcd60e51b815260040161125390614966565b611a38336131dc565b5f54610100900460ff16611a385760405162461bcd60e51b815260040161125390614966565b5f805b8251811015613431576001600160a01b0384165f908152610103602052604081208451829086908590811061335957613359614684565b60200260200101516004811115613372576133726146b1565b6004811115613383576133836146b1565b815260208082019290925260409081015f908120825180840190935280546001600160801b038082168552600160801b90910416938301939093528651929350916133e891908790869081106133db576133db614684565b6020026020010151612c98565b90506001600160801b0381161561341c5781546001600160801b03600160801b808304821684018216029116178255928301925b50508080613429906147da565b915050613322565b5092915050565b5f61348c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139cf9092919063ffffffff16565b905080515f14806134ac5750808060200190518101906134ac919061494b565b610b255760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611253565b6001600160a01b0381163b6135785760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401611253565b5f80516020614a8483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6135af836139dd565b5f825111806135bb5750805b15610b25576119ab8383613a1c565b610102545f90600160401b90046001600160801b031642106136295761010154613624906127109061360c90600160c01b90046001600160401b0316856149b1565b6001600160801b031661361f9190614938565b613a41565b612f2c565b61010254612f2c906127109061360c906001600160401b0316856149b1565b5f816001600160801b0316836001600160801b0316111561366b5781830361366d565b5f5b9392505050565b84515f9083101561368657505f612c8f565b84831115613695575082612c8f565b5f8584146136c057866020015184815181106136b3576136b3614684565b60200260200101516136c4565b6127105b90506137078588602001516001876136dc91906146d8565b815181106136ec576136ec614684565b60200260200101518360b48761370291906149dc565b613a6a565b979650505050505050565b5f805b82811015611b0557365f85858481811061373157613731614684565b905060200281019061374391906149ef565b613751906020810190614810565b91509150365f87878681811061376957613769614684565b905060200281019061377b91906149ef565b613789906040810190614810565b91509150365f8989888181106137a1576137a1614684565b90506020028101906137b391906149ef565b6137c1906060810190614810565b90925090508483811415806137d65750808214155b156137f45760405163a121188760e01b815260040160405180910390fd5b5f8b8b8a81811061380757613807614684565b905060200281019061381991906149ef565b3590505f5b828110156139bb575f87878381811061383957613839614684565b905060200201602081019061384e91906143af565b156138ec576138768f848c8c8681811061386a5761386a614684565b90506020020135613b0a565b90506001600160801b038116156138ec575f8381526101046020526040812082918c8c868181106138a9576138a9614684565b602090810292909201358352508101919091526040015f2060010180546001600160801b031981166001600160801b0391821693909301169190911790559a8b019a5b8585838181106138fe576138fe614684565b905060200201602081019061391391906143af565b156139b25761393b8f848c8c8681811061392f5761392f614684565b90506020020135613c4a565b90506001600160801b038116156139b2575f8381526101046020526040812082918c8c8681811061396e5761396e614684565b602090810292909201358352508101919091526040015f2060010180546001600160801b03600160801b8083048216909401811690930292169190911790559a8b019a5b5060010161381e565b508860010198505050505050505050613715565b606061329c84845f85613d8a565b6139e68161350b565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061366d8383604051806060016040528060278152602001614aa460279139613e56565b5f600160801b8210613a665760405163ede341c760e01b815260040160405180910390fd5b5090565b5f815f03613a9c57613a95612710613a8b866001600160801b0389166147c3565b61361f9190614938565b905061329c565b612c8f60b461271084613aaf88886146d8565b613ac2906001600160801b038b166147c3565b613acc91906147c3565b613ad69190614938565b613ae09190614938565b612710613af6876001600160801b038a166147c3565b613b009190614938565b61361f91906146c5565b60fd545f9083908110613b305760405163017e9c7d60e41b815260040160405180910390fd5b846001600160a01b031660fd8581548110613b4d57613b4d614684565b5f918252602090912001546040516331a9108f60e11b8152600481018690526001600160a01b0390911690636352211e90602401602060405180830381865afa158015613b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bc09190614a03565b6001600160a01b031614613be6576040516282b42960e81b815260040160405180910390fd5b5f84815261010460209081526040808320868452825291829020825160808101845281546001600160801b038082168352600160801b91829004811694830194909452600190920154808416948201949094529204166060820152612c8f90612be0565b60fd545f9083908110613c705760405163017e9c7d60e41b815260040160405180910390fd5b846001600160a01b031660fd8581548110613c8d57613c8d614684565b5f918252602090912001546040516331a9108f60e11b8152600481018690526001600160a01b0390911690636352211e90602401602060405180830381865afa158015613cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d009190614a03565b6001600160a01b031614613d26576040516282b42960e81b815260040160405180910390fd5b5f84815261010460209081526040808320868452825291829020825160808101845281546001600160801b038082168352600160801b91829004811694830194909452600190920154808416948201949094529204166060820152612c8f9061322d565b606082471015613deb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611253565b5f80866001600160a01b03168587604051613e069190614a40565b5f6040518083038185875af1925050503d805f8114613e40576040519150601f19603f3d011682016040523d82523d5f602084013e613e45565b606091505b509150915061370787838387613eca565b60605f80856001600160a01b031685604051613e729190614a40565b5f60405180830381855af49150503d805f8114613eaa576040519150601f19603f3d011682016040523d82523d5f602084013e613eaf565b606091505b5091509150613ec086838387613eca565b9695505050505050565b60608315613f385782515f03613f31576001600160a01b0385163b613f315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611253565b508161329c565b61329c8383815115613f4d5781518083602001fd5b8060405162461bcd60e51b81526004016112539190614a51565b828054828255905f5260205f20908101928215613fba579160200282015b82811115613fba57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613f85565b50613a669291505b80821115613a66575f8155600101613fc2565b6001600160a01b03811681146112ee575f80fd5b5f8083601f840112613ff9575f80fd5b5081356001600160401b0381111561400f575f80fd5b6020830191508360208260051b8501011115614029575f80fd5b9250929050565b5f805f60408486031215614042575f80fd5b833561404d81613fd5565b925060208401356001600160401b03811115614067575f80fd5b61407386828701613fe9565b9497909650939450505050565b5f60208284031215614090575f80fd5b813561366d81613fd5565b80356001600160801b03811681146140b1575f80fd5b919050565b5f80604083850312156140c7575f80fd5b82356001600160401b03811681146140dd575f80fd5b91506140eb6020840161409b565b90509250929050565b5f805f805f8060608789031215614109575f80fd5b86356001600160401b038082111561411f575f80fd5b61412b8a838b01613fe9565b90985096506020890135915080821115614143575f80fd5b61414f8a838b01613fe9565b90965094506040890135915080821115614167575f80fd5b5061417489828a01613fe9565b979a9699509497509295939492505050565b5f805f60408486031215614198575f80fd5b8335925060208401356001600160401b03811115614067575f80fd5b5f80604083850312156141c5575f80fd5b50508035926020909101359150565b8035600581106140b1575f80fd5b5f80604083850312156141f3575f80fd5b82356141fe81613fd5565b91506140eb602084016141d4565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215614231575f80fd5b823561423c81613fd5565b915060208301356001600160401b0380821115614257575f80fd5b818501915085601f83011261426a575f80fd5b81358181111561427c5761427c61420c565b604051601f8201601f19908116603f011681019083821181831017156142a4576142a461420c565b816040528281528860208487010111156142bc575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156142ee575f80fd5b823591506140eb6020840161409b565b80151581146112ee575f80fd5b5f805f806060858703121561431e575f80fd5b843561432981613fd5565b935060208501356001600160401b03811115614343575f80fd5b61434f87828801613fe9565b9094509250506040850135614363816142fe565b939692955090935050565b5f806040838503121561437f575f80fd5b823561438a81613fd5565b946020939093013593505050565b5f602082840312156143a8575f80fd5b5035919050565b5f602082840312156143bf575f80fd5b813561366d816142fe565b5f602082840312156143da575f80fd5b61366d826141d4565b6020808252825182820152828101516040808401528051606084018190525f9291820190839060808601905b8083101561442f578351825292840192600192909201919084019061440f565b509695505050505050565b5f806020838503121561444b575f80fd5b82356001600160401b03811115614460575f80fd5b61446c85828601613fe9565b90969095509350505050565b602080825282518282018190525f919060409081850190868401855b82811015614521578151805185528681015187860152858101516001600160801b03908116878701526060808301519087015260808083015182169087015260a08083015182169087015260c08083015182169087015260e08083015190870152610100808301518216908701526101209182015116908501526101409093019290850190600101614494565b5091979650505050505050565b5f806020838503121561453f575f80fd5b82356001600160401b0380821115614555575f80fd5b818501915085601f830112614568575f80fd5b813581811115614576575f80fd5b8660208260071b850101111561458a575f80fd5b60209290920196919550909350505050565b5f805f80604085870312156145af575f80fd5b84356001600160401b03808211156145c5575f80fd5b6145d188838901613fe9565b909650945060208701359150808211156145e9575f80fd5b506145f687828801613fe9565b95989497509550505050565b5f805f8060808587031215614615575f80fd5b843561462081613fd5565b9350602085013561463081613fd5565b9250604085013561464081613fd5565b9150606085013561436381613fd5565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b0381811683821601908082111561343157613431614650565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156146a8575f80fd5b61366d8261409b565b634e487b7160e01b5f52602160045260245ffd5b80820180821115612f2c57612f2c614650565b81810381811115612f2c57612f2c614650565b6001600160801b0382811682821603908082111561343157613431614650565b6001600160801b0381811683821601908082111561343157613431614650565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b8082028115828204841417612f2c57612f2c614650565b5f600182016147eb576147eb614650565b5060010190565b5f8235603e19833603018112614806575f80fd5b9190910192915050565b5f808335601e19843603018112614825575f80fd5b8301803591506001600160401b0382111561483e575f80fd5b6020019150600581901b3603821315614029575f80fd5b813581556001808201602080850135601e19863603018112614875575f80fd5b850180356001600160401b0381111561488c575f80fd5b82820191508060051b36038213156148a2575f80fd5b600160401b8111156148b6576148b661420c565b8354818555808210156148e9575f8581528481208381019083015b808210156148e557828255908801906148d1565b5050505b505f93845260208420935b81811015610def578235858201559183019185016148f4565b5f6020828403121561491d575f80fd5b5051919050565b634e487b7160e01b5f52601260045260245ffd5b5f8261494657614946614924565b500490565b5f6020828403121561495b575f80fd5b815161366d816142fe565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160801b038181168382160280821691908281146149d4576149d4614650565b505092915050565b5f826149ea576149ea614924565b500690565b5f8235607e19833603018112614806575f80fd5b5f60208284031215614a13575f80fd5b815161366d81613fd5565b5f5b83811015614a38578181015183820152602001614a20565b50505f910152565b5f8251614806818460208701614a1e565b602081525f8251806020840152614a6f816040850160208701614a1e565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208edb9f3a17f4af48ff75923f9d90dfcc99c86889fa497046674e279890be8f5564736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.