Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
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 Source Code Verified (Exact Match)
Contract Name:
NftVault
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {INftVault, IApeCoinStaking, IERC721ReceiverUpgradeable, IDelegateRegistryV2} from "../interfaces/INftVault.sol"; import {IDelegationRegistry} from "../interfaces/IDelegationRegistry.sol"; import {ApeStakingLib} from "../libraries/ApeStakingLib.sol"; import {VaultLogic} from "./VaultLogic.sol"; contract NftVault is INftVault, OwnableUpgradeable, ReentrancyGuardUpgradeable { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet; using ApeStakingLib for IApeCoinStaking; VaultStorage internal _vaultStorage; modifier onlyApe(address nft_) { require( nft_ == _vaultStorage.bayc || nft_ == _vaultStorage.mayc || nft_ == _vaultStorage.bakc, "NftVault: not ape" ); _; } modifier onlyApeCaller() { require( msg.sender == _vaultStorage.bayc || msg.sender == _vaultStorage.mayc || msg.sender == _vaultStorage.bakc, "NftVault: caller not ape" ); _; } modifier onlyAuthorized() { require(_vaultStorage.authorized[msg.sender], "StNft: caller is not authorized"); _; } function initialize(IApeCoinStaking apeCoinStaking_, IDelegationRegistry delegationRegistry_) public initializer { __Ownable_init(); __ReentrancyGuard_init(); _vaultStorage.apeCoinStaking = apeCoinStaking_; _vaultStorage.delegationRegistry = delegationRegistry_; _vaultStorage.apeCoin = IERC20Upgradeable(_vaultStorage.apeCoinStaking.apeCoin()); _vaultStorage.bayc = address(_vaultStorage.apeCoinStaking.bayc()); _vaultStorage.mayc = address(_vaultStorage.apeCoinStaking.mayc()); _vaultStorage.bakc = address(_vaultStorage.apeCoinStaking.bakc()); _vaultStorage.apeCoin.approve(address(_vaultStorage.apeCoinStaking), type(uint256).max); } function onERC721Received( address, address, uint256, bytes calldata ) external view override onlyApeCaller returns (bytes4) { return IERC721ReceiverUpgradeable.onERC721Received.selector; } function stakerOf(address nft_, uint256 tokenId_) external view onlyApe(nft_) returns (address) { return VaultLogic._stakerOf(_vaultStorage, nft_, tokenId_); } function ownerOf(address nft_, uint256 tokenId_) external view onlyApe(nft_) returns (address) { return VaultLogic._ownerOf(_vaultStorage, nft_, tokenId_); } function refundOf(address nft_, address staker_) external view onlyApe(nft_) returns (Refund memory) { return _vaultStorage.refunds[nft_][staker_]; } function positionOf(address nft_, address staker_) external view onlyApe(nft_) returns (Position memory) { return _vaultStorage.positions[nft_][staker_]; } function pendingRewards(address nft_, address staker_) external view onlyApe(nft_) returns (uint256) { IApeCoinStaking.PoolWithoutTimeRange memory pool = _vaultStorage.apeCoinStaking.getNftPool(nft_); Position memory position = _vaultStorage.positions[nft_][staker_]; (uint256 rewardsSinceLastCalculated, ) = _vaultStorage.apeCoinStaking.getNftRewardsBy( nft_, pool.lastRewardedTimestampHour, ApeStakingLib.getPreviousTimestampHour() ); uint256 accumulatedRewardsPerShare = pool.accumulatedRewardsPerShare; if ( block.timestamp > pool.lastRewardedTimestampHour + ApeStakingLib.SECONDS_PER_HOUR && pool.stakedAmount != 0 ) { accumulatedRewardsPerShare = accumulatedRewardsPerShare + (rewardsSinceLastCalculated * ApeStakingLib.APE_COIN_PRECISION) / pool.stakedAmount; } return uint256(int256(position.stakedAmount * accumulatedRewardsPerShare) - position.rewardsDebt) / ApeStakingLib.APE_COIN_PRECISION; } function totalStakingNft(address nft_, address staker_) external view returns (uint256) { return _vaultStorage.stakingTokenIds[nft_][staker_].length(); } function stakingNftIdByIndex(address nft_, address staker_, uint256 index_) external view returns (uint256) { return _vaultStorage.stakingTokenIds[nft_][staker_].at(index_); } function isStaking(address nft_, address staker_, uint256 tokenId_) external view returns (bool) { return _vaultStorage.stakingTokenIds[nft_][staker_].contains(tokenId_); } function authorise(address addr_, bool authorized_) external override onlyOwner { _vaultStorage.authorized[addr_] = authorized_; } function setDelegateCash( address delegate_, address nft_, uint256[] calldata tokenIds_, bool value_ ) external override onlyAuthorized onlyApe(nft_) { require(delegate_ != address(0), "nftVault: invalid delegate"); uint256 tokenId_; for (uint256 i = 0; i < tokenIds_.length; i++) { tokenId_ = tokenIds_[i]; require( msg.sender == VaultLogic._ownerOf(_vaultStorage, nft_, tokenId_), "nftVault: only owner can delegate" ); _vaultStorage.delegationRegistry.delegateForToken(delegate_, nft_, tokenId_, value_); } } function getDelegateCashForToken( address nft_, uint256[] calldata tokenIds_ ) external view override returns (address[][] memory delegates) { delegates = new address[][](tokenIds_.length); uint256 tokenId_; for (uint256 i = 0; i < tokenIds_.length; i++) { tokenId_ = tokenIds_[i]; delegates[i] = _vaultStorage.delegationRegistry.getDelegatesForToken(address(this), nft_, tokenId_); } } function setDelegationRegistryV2Contract(address registryV2_) external onlyOwner { _vaultStorage.delegationRegistryV2 = IDelegateRegistryV2(registryV2_); } function setDelegateCashV2( address delegate_, address nft_, uint256[] calldata tokenIds_, bool value_ ) external override onlyAuthorized onlyApe(nft_) { require(delegate_ != address(0), "nftVault: invalid delegate"); uint256 tokenId_; for (uint256 i = 0; i < tokenIds_.length; i++) { tokenId_ = tokenIds_[i]; require( msg.sender == VaultLogic._ownerOf(_vaultStorage, nft_, tokenId_), "nftVault: only owner can delegate" ); _vaultStorage.delegationRegistryV2.delegateERC721(delegate_, nft_, tokenId_, "", value_); } } function getDelegateCashForTokenV2( address nft_, uint256[] calldata tokenIds_ ) external view override returns (address[][] memory delegates) { IDelegateRegistryV2.Delegation[] memory allDelegations = _vaultStorage .delegationRegistryV2 .getOutgoingDelegations(address(this)); delegates = new address[][](tokenIds_.length); uint256 tokenId_; for (uint256 i = 0; i < tokenIds_.length; i++) { tokenId_ = tokenIds_[i]; uint256 tokenDelegatesNum; for (uint256 j = 0; j < allDelegations.length; j++) { if (allDelegations[j].contract_ == nft_ && allDelegations[j].tokenId == tokenId_) { tokenDelegatesNum++; } } delegates[i] = new address[](tokenDelegatesNum); uint256 tokenDelegateIdx; for (uint256 j = 0; j < allDelegations.length; j++) { if (allDelegations[j].contract_ == nft_ && allDelegations[j].tokenId == tokenId_) { delegates[i][tokenDelegateIdx] = allDelegations[j].to; tokenDelegateIdx++; } } } } function depositNft( address nft_, uint256[] calldata tokenIds_, address staker_ ) external override onlyApe(nft_) onlyAuthorized nonReentrant { uint256 tokenId_; uint256 poolId_; IApeCoinStaking.Position memory position_; IApeCoinStaking.PairingStatus memory pairingStatus_; // transfer nft and set permission for (uint256 i = 0; i < tokenIds_.length; i++) { // block partially stake from official contract tokenId_ = tokenIds_[i]; position_ = _vaultStorage.apeCoinStaking.getNftPosition(nft_, tokenId_); require(position_.stakedAmount == 0, "nftVault: nft already staked"); if (nft_ == _vaultStorage.bayc || nft_ == _vaultStorage.mayc) { poolId_ = _vaultStorage.apeCoinStaking.getNftPoolId(nft_); pairingStatus_ = _vaultStorage.apeCoinStaking.mainToBakc(poolId_, tokenId_); // block bayc & mayc which already paired with bakc require(!pairingStatus_.isPaired, "nftVault: already paired with bakc"); } IERC721Upgradeable(nft_).safeTransferFrom(msg.sender, address(this), tokenIds_[i]); _vaultStorage.nfts[nft_][tokenIds_[i]] = NftStatus(msg.sender, staker_); } emit NftDeposited(nft_, msg.sender, staker_, tokenIds_); } function withdrawNft( address nft_, uint256[] calldata tokenIds_ ) external override onlyApe(nft_) onlyAuthorized nonReentrant { require(tokenIds_.length > 0, "nftVault: invalid tokenIds"); address staker_ = VaultLogic._stakerOf(_vaultStorage, nft_, tokenIds_[0]); if (nft_ == _vaultStorage.bayc || nft_ == _vaultStorage.mayc) { VaultLogic._refundSinglePool(_vaultStorage, nft_, tokenIds_); } else if (nft_ == _vaultStorage.bakc) { VaultLogic._refundPairingPool(_vaultStorage, tokenIds_); } // transfer nft to sender for (uint256 i = 0; i < tokenIds_.length; i++) { require( msg.sender == VaultLogic._ownerOf(_vaultStorage, nft_, tokenIds_[i]), "nftVault: caller must be nft owner" ); require( staker_ == VaultLogic._stakerOf(_vaultStorage, nft_, tokenIds_[i]), "nftVault: staker must be same" ); delete _vaultStorage.nfts[nft_][tokenIds_[i]]; // transfer nft IERC721Upgradeable(nft_).safeTransferFrom(address(this), msg.sender, tokenIds_[i]); } emit NftWithdrawn(nft_, msg.sender, staker_, tokenIds_); } function withdrawRefunds(address nft_) external override onlyApe(nft_) onlyAuthorized nonReentrant { Refund memory _refund = _vaultStorage.refunds[nft_][msg.sender]; uint256 amount = _refund.principal + _refund.reward; delete _vaultStorage.refunds[nft_][msg.sender]; _vaultStorage.apeCoin.transfer(msg.sender, amount); } function stakeBaycPool(IApeCoinStaking.SingleNft[] calldata nfts_) external override onlyAuthorized nonReentrant { address nft_ = _vaultStorage.bayc; uint256 totalStakedAmount = 0; IApeCoinStaking.SingleNft memory singleNft_; for (uint256 i = 0; i < nfts_.length; i++) { singleNft_ = nfts_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, singleNft_.tokenId), "nftVault: caller must be bayc staker" ); totalStakedAmount += singleNft_.amount; _vaultStorage.stakingTokenIds[nft_][msg.sender].add(singleNft_.tokenId); } _vaultStorage.apeCoin.transferFrom(msg.sender, address(this), totalStakedAmount); _vaultStorage.apeCoinStaking.depositBAYC(nfts_); VaultLogic._increasePosition(_vaultStorage, nft_, msg.sender, totalStakedAmount); emit SingleNftStaked(nft_, msg.sender, nfts_); } function unstakeBaycPool( IApeCoinStaking.SingleNft[] calldata nfts_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 principal, uint256 rewards) { address nft_ = _vaultStorage.bayc; IApeCoinStaking.SingleNft memory singleNft_; IApeCoinStaking.Position memory position_; for (uint256 i = 0; i < nfts_.length; i++) { singleNft_ = nfts_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, singleNft_.tokenId), "nftVault: caller must be nft staker" ); principal += singleNft_.amount; position_ = _vaultStorage.apeCoinStaking.getNftPosition(nft_, singleNft_.tokenId); if (position_.stakedAmount == singleNft_.amount) { _vaultStorage.stakingTokenIds[nft_][msg.sender].remove(singleNft_.tokenId); } } rewards = _vaultStorage.apeCoin.balanceOf(recipient_); _vaultStorage.apeCoinStaking.withdrawBAYC(nfts_, recipient_); rewards = _vaultStorage.apeCoin.balanceOf(recipient_) - rewards - principal; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } VaultLogic._decreasePosition(_vaultStorage, nft_, msg.sender, principal); emit SingleNftUnstaked(nft_, msg.sender, nfts_); } function claimBaycPool( uint256[] calldata tokenIds_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 rewards) { address nft_ = _vaultStorage.bayc; for (uint256 i = 0; i < tokenIds_.length; i++) { require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, tokenIds_[i]), "nftVault: caller must be nft staker" ); } rewards = _vaultStorage.apeCoin.balanceOf(address(recipient_)); _vaultStorage.apeCoinStaking.claimBAYC(tokenIds_, recipient_); rewards = _vaultStorage.apeCoin.balanceOf(recipient_) - rewards; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } emit SingleNftClaimed(nft_, msg.sender, tokenIds_, rewards); } function stakeMaycPool(IApeCoinStaking.SingleNft[] calldata nfts_) external override onlyAuthorized nonReentrant { address nft_ = _vaultStorage.mayc; uint256 totalApeCoinAmount = 0; IApeCoinStaking.SingleNft memory singleNft_; for (uint256 i = 0; i < nfts_.length; i++) { singleNft_ = nfts_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, singleNft_.tokenId), "nftVault: caller must be mayc staker" ); totalApeCoinAmount += singleNft_.amount; _vaultStorage.stakingTokenIds[nft_][msg.sender].add(singleNft_.tokenId); } _vaultStorage.apeCoin.transferFrom(msg.sender, address(this), totalApeCoinAmount); _vaultStorage.apeCoinStaking.depositMAYC(nfts_); VaultLogic._increasePosition(_vaultStorage, nft_, msg.sender, totalApeCoinAmount); emit SingleNftStaked(nft_, msg.sender, nfts_); } function unstakeMaycPool( IApeCoinStaking.SingleNft[] calldata nfts_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 principal, uint256 rewards) { address nft_ = _vaultStorage.mayc; IApeCoinStaking.SingleNft memory singleNft_; IApeCoinStaking.Position memory position_; for (uint256 i = 0; i < nfts_.length; i++) { singleNft_ = nfts_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, singleNft_.tokenId), "nftVault: caller must be nft staker" ); principal += singleNft_.amount; position_ = _vaultStorage.apeCoinStaking.getNftPosition(nft_, singleNft_.tokenId); if (position_.stakedAmount == singleNft_.amount) { _vaultStorage.stakingTokenIds[nft_][msg.sender].remove(singleNft_.tokenId); } } rewards = _vaultStorage.apeCoin.balanceOf(recipient_); _vaultStorage.apeCoinStaking.withdrawMAYC(nfts_, recipient_); rewards = _vaultStorage.apeCoin.balanceOf(recipient_) - rewards - principal; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } VaultLogic._decreasePosition(_vaultStorage, nft_, msg.sender, principal); emit SingleNftUnstaked(nft_, msg.sender, nfts_); } function claimMaycPool( uint256[] calldata tokenIds_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 rewards) { address nft_ = _vaultStorage.mayc; for (uint256 i = 0; i < tokenIds_.length; i++) { require( msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, tokenIds_[i]), "nftVault: caller must be nft staker" ); } rewards = _vaultStorage.apeCoin.balanceOf(recipient_); _vaultStorage.apeCoinStaking.claimMAYC(tokenIds_, recipient_); rewards = _vaultStorage.apeCoin.balanceOf(recipient_) - rewards; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } emit SingleNftClaimed(nft_, msg.sender, tokenIds_, rewards); } function stakeBakcPool( IApeCoinStaking.PairNftDepositWithAmount[] calldata baycPairs_, IApeCoinStaking.PairNftDepositWithAmount[] calldata maycPairs_ ) external override onlyAuthorized nonReentrant { uint256 totalStakedAmount = 0; IApeCoinStaking.PairNftDepositWithAmount memory pair; address nft_ = _vaultStorage.bakc; for (uint256 i = 0; i < baycPairs_.length; i++) { pair = baycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.bayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, pair.bakcTokenId), "nftVault: caller must be nft staker" ); totalStakedAmount += pair.amount; _vaultStorage.stakingTokenIds[nft_][msg.sender].add(pair.bakcTokenId); } for (uint256 i = 0; i < maycPairs_.length; i++) { pair = maycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.mayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, pair.bakcTokenId), "nftVault: caller must be nft staker" ); totalStakedAmount += pair.amount; _vaultStorage.stakingTokenIds[nft_][msg.sender].add(pair.bakcTokenId); } _vaultStorage.apeCoin.transferFrom(msg.sender, address(this), totalStakedAmount); _vaultStorage.apeCoinStaking.depositBAKC(baycPairs_, maycPairs_); VaultLogic._increasePosition(_vaultStorage, nft_, msg.sender, totalStakedAmount); emit PairedNftStaked(msg.sender, baycPairs_, maycPairs_); } function unstakeBakcPool( IApeCoinStaking.PairNftWithdrawWithAmount[] calldata baycPairs_, IApeCoinStaking.PairNftWithdrawWithAmount[] calldata maycPairs_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 principal, uint256 rewards) { address nft_ = _vaultStorage.bakc; IApeCoinStaking.Position memory position_; IApeCoinStaking.PairNftWithdrawWithAmount memory pair; for (uint256 i = 0; i < baycPairs_.length; i++) { pair = baycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.bayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, pair.bakcTokenId), "nftVault: caller must be nft staker" ); position_ = _vaultStorage.apeCoinStaking.getNftPosition(nft_, pair.bakcTokenId); principal += (pair.isUncommit ? position_.stakedAmount : pair.amount); if (pair.isUncommit) { _vaultStorage.stakingTokenIds[nft_][msg.sender].remove(pair.bakcTokenId); } } for (uint256 i = 0; i < maycPairs_.length; i++) { pair = maycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.mayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, pair.bakcTokenId), "nftVault: caller must be nft staker" ); position_ = _vaultStorage.apeCoinStaking.getNftPosition(nft_, pair.bakcTokenId); principal += (pair.isUncommit ? position_.stakedAmount : pair.amount); if (pair.isUncommit) { _vaultStorage.stakingTokenIds[nft_][msg.sender].remove(pair.bakcTokenId); } } rewards = _vaultStorage.apeCoin.balanceOf(address(this)); _vaultStorage.apeCoinStaking.withdrawBAKC(baycPairs_, maycPairs_); rewards = _vaultStorage.apeCoin.balanceOf(address(this)) - rewards - principal; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } VaultLogic._decreasePosition(_vaultStorage, nft_, msg.sender, principal); _vaultStorage.apeCoin.transfer(recipient_, principal + rewards); emit PairedNftUnstaked(msg.sender, baycPairs_, maycPairs_); } function claimBakcPool( IApeCoinStaking.PairNft[] calldata baycPairs_, IApeCoinStaking.PairNft[] calldata maycPairs_, address recipient_ ) external override onlyAuthorized nonReentrant returns (uint256 rewards) { address nft_ = _vaultStorage.bakc; IApeCoinStaking.PairNft memory pair; for (uint256 i = 0; i < baycPairs_.length; i++) { pair = baycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.bayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, nft_, pair.bakcTokenId), "nftVault: caller must be nft staker" ); } for (uint256 i = 0; i < maycPairs_.length; i++) { pair = maycPairs_[i]; require( msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.mayc, pair.mainTokenId) && msg.sender == VaultLogic._stakerOf(_vaultStorage, _vaultStorage.bakc, pair.bakcTokenId), "nftVault: caller must be nft staker" ); } rewards = _vaultStorage.apeCoin.balanceOf(recipient_); _vaultStorage.apeCoinStaking.claimBAKC(baycPairs_, maycPairs_, recipient_); rewards = _vaultStorage.apeCoin.balanceOf(recipient_) - rewards; if (rewards > 0) { VaultLogic._updateRewardsDebt(_vaultStorage, nft_, msg.sender, rewards); } emit PairedNftClaimed(msg.sender, baycPairs_, maycPairs_, rewards); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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.8.1) (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] * ``` * 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.8.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 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.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev 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 v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCastUpgradeable { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; interface IApeCoinStaking { struct SingleNft { uint32 tokenId; uint224 amount; } struct PairNft { uint128 mainTokenId; uint128 bakcTokenId; } struct PairNftDepositWithAmount { uint32 mainTokenId; uint32 bakcTokenId; uint184 amount; } struct PairNftWithdrawWithAmount { uint32 mainTokenId; uint32 bakcTokenId; uint184 amount; bool isUncommit; } struct Position { uint256 stakedAmount; int256 rewardsDebt; } struct Pool { uint48 lastRewardedTimestampHour; uint16 lastRewardsRangeIndex; uint96 stakedAmount; uint96 accumulatedRewardsPerShare; TimeRange[] timeRanges; } struct TimeRange { uint48 startTimestampHour; uint48 endTimestampHour; uint96 rewardsPerHour; uint96 capPerPosition; } struct PoolWithoutTimeRange { uint48 lastRewardedTimestampHour; uint16 lastRewardsRangeIndex; uint96 stakedAmount; uint96 accumulatedRewardsPerShare; } struct DashboardStake { uint256 poolId; uint256 tokenId; uint256 deposited; uint256 unclaimed; uint256 rewards24hr; DashboardPair pair; } struct DashboardPair { uint256 mainTokenId; uint256 mainTypePoolId; } struct PoolUI { uint256 poolId; uint256 stakedAmount; TimeRange currentTimeRange; } struct PairingStatus { uint248 tokenId; bool isPaired; } function mainToBakc(uint256 poolId_, uint256 mainTokenId_) external view returns (PairingStatus memory); function bakcToMain(uint256 poolId_, uint256 bakcTokenId_) external view returns (PairingStatus memory); function nftContracts(uint256 poolId_) external view returns (address); function rewardsBy(uint256 poolId_, uint256 from_, uint256 to_) external view returns (uint256, uint256); function apeCoin() external view returns (address); function getCurrentTimeRangeIndex(Pool memory pool_) external view returns (uint256); function getTimeRangeBy(uint256 poolId_, uint256 index_) external view returns (TimeRange memory); function getPoolsUI() external view returns (PoolUI memory, PoolUI memory, PoolUI memory, PoolUI memory); function getSplitStakes(address address_) external view returns (DashboardStake[] memory); function stakedTotal(address addr_) external view returns (uint256); function pools(uint256 poolId_) external view returns (PoolWithoutTimeRange memory); function nftPosition(uint256 poolId_, uint256 tokenId_) external view returns (Position memory); function addressPosition(address addr_) external view returns (Position memory); function pendingRewards(uint256 poolId_, address address_, uint256 tokenId_) external view returns (uint256); function depositBAYC(SingleNft[] calldata nfts_) external; function depositMAYC(SingleNft[] calldata nfts_) external; function depositBAKC( PairNftDepositWithAmount[] calldata baycPairs_, PairNftDepositWithAmount[] calldata maycPairs_ ) external; function depositSelfApeCoin(uint256 amount_) external; function claimSelfApeCoin() external; function claimBAYC(uint256[] calldata nfts_, address recipient_) external; function claimMAYC(uint256[] calldata nfts_, address recipient_) external; function claimBAKC(PairNft[] calldata baycPairs_, PairNft[] calldata maycPairs_, address recipient_) external; function withdrawBAYC(SingleNft[] calldata nfts_, address recipient_) external; function withdrawMAYC(SingleNft[] calldata nfts_, address recipient_) external; function withdrawBAKC( PairNftWithdrawWithAmount[] calldata baycPairs_, PairNftWithdrawWithAmount[] calldata maycPairs_ ) external; function withdrawSelfApeCoin(uint256 amount_) external; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity 0.8.18; /** * @title IDelegateRegistryV2 * @custom:version 2.0 * @custom:author foobar (0xfoobar) * @notice A standalone immutable registry storing delegated permissions from one address to another */ interface IDelegateRegistryV2 { /// @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; } /** * ----------- WRITE ----------- */ /** * @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); /** * ----------- ENUMERATIONS ----------- */ /** * @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 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); }
// SPDX-License-Identifier: CC0-1.0 pragma solidity 0.8.18; /** * @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); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {IERC721ReceiverUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; import {IApeCoinStaking} from "./IApeCoinStaking.sol"; import {IDelegationRegistry} from "../interfaces/IDelegationRegistry.sol"; import {IDelegateRegistryV2} from "../interfaces/IDelegateRegistryV2.sol"; interface INftVault is IERC721ReceiverUpgradeable { event NftDeposited(address indexed nft, address indexed owner, address indexed staker, uint256[] tokenIds); event NftWithdrawn(address indexed nft, address indexed owner, address indexed staker, uint256[] tokenIds); event SingleNftStaked(address indexed nft, address indexed staker, IApeCoinStaking.SingleNft[] nfts); event PairedNftStaked( address indexed staker, IApeCoinStaking.PairNftDepositWithAmount[] baycPairs, IApeCoinStaking.PairNftDepositWithAmount[] maycPairs ); event SingleNftUnstaked(address indexed nft, address indexed staker, IApeCoinStaking.SingleNft[] nfts); event PairedNftUnstaked( address indexed staker, IApeCoinStaking.PairNftWithdrawWithAmount[] baycPairs, IApeCoinStaking.PairNftWithdrawWithAmount[] maycPairs ); event SingleNftClaimed(address indexed nft, address indexed staker, uint256[] tokenIds, uint256 rewards); event PairedNftClaimed( address indexed staker, IApeCoinStaking.PairNft[] baycPairs, IApeCoinStaking.PairNft[] maycPairs, uint256 rewards ); struct NftStatus { address owner; address staker; } struct VaultStorage { // nft address => nft tokenId => nftStatus mapping(address => mapping(uint256 => NftStatus)) nfts; // nft address => staker address => refund mapping(address => mapping(address => Refund)) refunds; // nft address => staker address => position mapping(address => mapping(address => Position)) positions; // nft address => staker address => staking nft tokenId array mapping(address => mapping(address => EnumerableSetUpgradeable.UintSet)) stakingTokenIds; IApeCoinStaking apeCoinStaking; IERC20Upgradeable apeCoin; address bayc; address mayc; address bakc; IDelegationRegistry delegationRegistry; mapping(address => bool) authorized; IDelegateRegistryV2 delegationRegistryV2; } struct Refund { uint256 principal; uint256 reward; } struct Position { uint256 stakedAmount; int256 rewardsDebt; } function authorise(address addr_, bool authorized_) external; function stakerOf(address nft_, uint256 tokenId_) external view returns (address); function ownerOf(address nft_, uint256 tokenId_) external view returns (address); function refundOf(address nft_, address staker_) external view returns (Refund memory); function positionOf(address nft_, address staker_) external view returns (Position memory); function pendingRewards(address nft_, address staker_) external view returns (uint256); function totalStakingNft(address nft_, address staker_) external view returns (uint256); function stakingNftIdByIndex(address nft_, address staker_, uint256 index_) external view returns (uint256); function isStaking(address nft_, address staker_, uint256 tokenId_) external view returns (bool); // delegate.cash V1 function setDelegateCash(address delegate_, address nft_, uint256[] calldata tokenIds, bool value) external; function getDelegateCashForToken( address nft_, uint256[] calldata tokenIds_ ) external view returns (address[][] memory); // delegate.cash V2 function setDelegateCashV2(address delegate_, address nft_, uint256[] calldata tokenIds, bool value) external; function getDelegateCashForTokenV2( address nft_, uint256[] calldata tokenIds_ ) external view returns (address[][] memory); // deposit nft function depositNft(address nft_, uint256[] calldata tokenIds_, address staker_) external; // withdraw nft function withdrawNft(address nft_, uint256[] calldata tokenIds_) external; // staker withdraw ape coin function withdrawRefunds(address nft_) external; // stake function stakeBaycPool(IApeCoinStaking.SingleNft[] calldata nfts_) external; function stakeMaycPool(IApeCoinStaking.SingleNft[] calldata nfts_) external; function stakeBakcPool( IApeCoinStaking.PairNftDepositWithAmount[] calldata baycPairs_, IApeCoinStaking.PairNftDepositWithAmount[] calldata maycPairs_ ) external; // unstake function unstakeBaycPool( IApeCoinStaking.SingleNft[] calldata nfts_, address recipient_ ) external returns (uint256 principal, uint256 rewards); function unstakeMaycPool( IApeCoinStaking.SingleNft[] calldata nfts_, address recipient_ ) external returns (uint256 principal, uint256 rewards); function unstakeBakcPool( IApeCoinStaking.PairNftWithdrawWithAmount[] calldata baycPairs_, IApeCoinStaking.PairNftWithdrawWithAmount[] calldata maycPairs_, address recipient_ ) external returns (uint256 principal, uint256 rewards); // claim rewards function claimBaycPool(uint256[] calldata tokenIds_, address recipient_) external returns (uint256 rewards); function claimMaycPool(uint256[] calldata tokenIds_, address recipient_) external returns (uint256 rewards); function claimBakcPool( IApeCoinStaking.PairNft[] calldata baycPairs_, IApeCoinStaking.PairNft[] calldata maycPairs_, address recipient_ ) external returns (uint256 rewards); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import {IApeCoinStaking} from "../interfaces/IApeCoinStaking.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; library ApeStakingLib { uint256 internal constant APE_COIN_PRECISION = 1e18; uint256 internal constant SECONDS_PER_HOUR = 3600; uint256 internal constant SECONDS_PER_MINUTE = 60; uint256 internal constant APE_COIN_POOL_ID = 0; uint256 internal constant BAYC_POOL_ID = 1; uint256 internal constant MAYC_POOL_ID = 2; uint256 internal constant BAKC_POOL_ID = 3; function getCurrentTimeRange( IApeCoinStaking apeCoinStaking_, uint256 poolId ) internal view returns (IApeCoinStaking.TimeRange memory) { ( IApeCoinStaking.PoolUI memory apeCoinPoolUI, IApeCoinStaking.PoolUI memory baycPoolUI, IApeCoinStaking.PoolUI memory maycPoolUI, IApeCoinStaking.PoolUI memory bakcPoolUI ) = apeCoinStaking_.getPoolsUI(); if (poolId == apeCoinPoolUI.poolId) { return apeCoinPoolUI.currentTimeRange; } if (poolId == baycPoolUI.poolId) { return baycPoolUI.currentTimeRange; } if (poolId == maycPoolUI.poolId) { return maycPoolUI.currentTimeRange; } if (poolId == bakcPoolUI.poolId) { return bakcPoolUI.currentTimeRange; } revert("invalid pool id"); } function getNftPoolId(IApeCoinStaking apeCoinStaking_, address nft_) internal view returns (uint256) { if (nft_ == apeCoinStaking_.nftContracts(BAYC_POOL_ID)) { return BAYC_POOL_ID; } if (nft_ == apeCoinStaking_.nftContracts(MAYC_POOL_ID)) { return MAYC_POOL_ID; } if (nft_ == apeCoinStaking_.nftContracts(BAKC_POOL_ID)) { return BAKC_POOL_ID; } revert("invalid nft"); } function getNftPosition( IApeCoinStaking apeCoinStaking_, address nft_, uint256 tokenId_ ) internal view returns (IApeCoinStaking.Position memory) { return apeCoinStaking_.nftPosition(getNftPoolId(apeCoinStaking_, nft_), tokenId_); } function getNftPool( IApeCoinStaking apeCoinStaking_, address nft_ ) internal view returns (IApeCoinStaking.PoolWithoutTimeRange memory) { return apeCoinStaking_.pools(getNftPoolId(apeCoinStaking_, nft_)); } function getNftRewardsBy( IApeCoinStaking apeCoinStaking_, address nft_, uint256 from_, uint256 to_ ) internal view returns (uint256, uint256) { return apeCoinStaking_.rewardsBy(getNftPoolId(apeCoinStaking_, nft_), from_, to_); } function bayc(IApeCoinStaking apeCoinStaking_) internal view returns (IERC721) { return IERC721(apeCoinStaking_.nftContracts(BAYC_POOL_ID)); } function mayc(IApeCoinStaking apeCoinStaking_) internal view returns (IERC721) { return IERC721(apeCoinStaking_.nftContracts(MAYC_POOL_ID)); } function bakc(IApeCoinStaking apeCoinStaking_) internal view returns (IERC721) { return IERC721(apeCoinStaking_.nftContracts(BAKC_POOL_ID)); } function getPreviousTimestampHour() internal view returns (uint256) { return block.timestamp - (getMinute(block.timestamp) * 60 + getSecond(block.timestamp)); } function getMinute(uint256 timestamp) internal pure returns (uint256 minute) { uint256 secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } /// @notice the seconds (0 to 59) of a timestamp function getSecond(uint256 timestamp) internal pure returns (uint256 second) { second = timestamp % SECONDS_PER_MINUTE; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import {SafeCastUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import {IApeCoinStaking} from "../interfaces/IApeCoinStaking.sol"; import {INftVault} from "../interfaces/INftVault.sol"; import {ApeStakingLib} from "../libraries/ApeStakingLib.sol"; library VaultLogic { event SingleNftUnstaked(address indexed nft, address indexed staker, IApeCoinStaking.SingleNft[] nfts); event PairedNftUnstaked( address indexed staker, IApeCoinStaking.PairNftWithdrawWithAmount[] baycPairs, IApeCoinStaking.PairNftWithdrawWithAmount[] maycPairs ); using SafeCastUpgradeable for uint256; using SafeCastUpgradeable for uint248; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet; using ApeStakingLib for IApeCoinStaking; function _stakerOf( INftVault.VaultStorage storage _vaultStorage, address nft_, uint256 tokenId_ ) internal view returns (address) { return _vaultStorage.nfts[nft_][tokenId_].staker; } function _ownerOf( INftVault.VaultStorage storage _vaultStorage, address nft_, uint256 tokenId_ ) internal view returns (address) { return _vaultStorage.nfts[nft_][tokenId_].owner; } function _increasePosition( INftVault.VaultStorage storage _vaultStorage, address nft_, address staker_, uint256 stakedAmount_ ) internal { INftVault.Position storage position_ = _vaultStorage.positions[nft_][staker_]; position_.stakedAmount += stakedAmount_; position_.rewardsDebt += int256( stakedAmount_ * _vaultStorage.apeCoinStaking.getNftPool(nft_).accumulatedRewardsPerShare ); } function _decreasePosition( INftVault.VaultStorage storage _vaultStorage, address nft_, address staker_, uint256 stakedAmount_ ) internal { INftVault.Position storage position_ = _vaultStorage.positions[nft_][staker_]; position_.stakedAmount -= stakedAmount_; position_.rewardsDebt -= int256( stakedAmount_ * _vaultStorage.apeCoinStaking.getNftPool(nft_).accumulatedRewardsPerShare ); } function _updateRewardsDebt( INftVault.VaultStorage storage _vaultStorage, address nft_, address staker_, uint256 claimedRewardsAmount_ ) internal { INftVault.Position storage position_ = _vaultStorage.positions[nft_][staker_]; position_.rewardsDebt += int256(claimedRewardsAmount_ * ApeStakingLib.APE_COIN_PRECISION); } struct RefundSinglePoolVars { uint256 poolId; uint256 cachedBalance; uint256 tokenId; uint256 bakcTokenId; uint256 stakedAmount; // refunds address staker; uint256 totalPrincipal; uint256 totalReward; uint256 totalPairingPrincipal; uint256 totalPairingReward; // array uint256 singleNftIndex; uint256 singleNftSize; uint256 pairingNftIndex; uint256 pairingNftSize; } function _refundSinglePool( INftVault.VaultStorage storage _vaultStorage, address nft_, uint256[] calldata tokenIds_ ) external { require(nft_ == _vaultStorage.bayc || nft_ == _vaultStorage.mayc, "nftVault: not bayc or mayc"); require(tokenIds_.length > 0, "nftVault: invalid tokenIds"); RefundSinglePoolVars memory vars; IApeCoinStaking.PairingStatus memory pairingStatus; INftVault.Refund storage refund; vars.poolId = ApeStakingLib.BAYC_POOL_ID; if (nft_ == _vaultStorage.mayc) { vars.poolId = ApeStakingLib.MAYC_POOL_ID; } vars.cachedBalance = _vaultStorage.apeCoin.balanceOf(address(this)); vars.staker = _stakerOf(_vaultStorage, nft_, tokenIds_[0]); require(vars.staker != address(0), "nftVault: invalid staker"); // Calculate the nft array size for (uint256 i = 0; i < tokenIds_.length; i++) { vars.tokenId = tokenIds_[i]; require(msg.sender == _ownerOf(_vaultStorage, nft_, vars.tokenId), "nftVault: caller must be nft owner"); // make sure the bayc/mayc locked in valult require(address(this) == IERC721Upgradeable(nft_).ownerOf(vars.tokenId), "nftVault: invalid token id"); require(vars.staker == _stakerOf(_vaultStorage, nft_, vars.tokenId), "nftVault: staker must be same"); vars.stakedAmount = _vaultStorage.apeCoinStaking.nftPosition(vars.poolId, vars.tokenId).stakedAmount; // Still have ape coin staking in single pool if (vars.stakedAmount > 0) { vars.singleNftSize += 1; } pairingStatus = _vaultStorage.apeCoinStaking.mainToBakc(vars.poolId, vars.tokenId); vars.bakcTokenId = pairingStatus.tokenId; vars.stakedAmount = _vaultStorage .apeCoinStaking .nftPosition(ApeStakingLib.BAKC_POOL_ID, vars.bakcTokenId) .stakedAmount; // Still have ape coin staking in pairing pool if ( pairingStatus.isPaired && // make sure the bakc locked in valult IERC721Upgradeable(_vaultStorage.bakc).ownerOf(vars.bakcTokenId) == address(this) && vars.stakedAmount > 0 ) { vars.pairingNftSize += 1; } } if (vars.singleNftSize > 0) { IApeCoinStaking.SingleNft[] memory singleNfts_ = new IApeCoinStaking.SingleNft[](vars.singleNftSize); for (uint256 i = 0; i < tokenIds_.length; i++) { vars.tokenId = tokenIds_[i]; vars.stakedAmount = _vaultStorage.apeCoinStaking.nftPosition(vars.poolId, vars.tokenId).stakedAmount; if (vars.stakedAmount > 0) { vars.totalPrincipal += vars.stakedAmount; singleNfts_[vars.singleNftIndex] = IApeCoinStaking.SingleNft({ tokenId: vars.tokenId.toUint32(), amount: vars.stakedAmount.toUint224() }); vars.singleNftIndex += 1; _vaultStorage.stakingTokenIds[nft_][vars.staker].remove(vars.tokenId); } } if (nft_ == _vaultStorage.bayc) { _vaultStorage.apeCoinStaking.withdrawBAYC(singleNfts_, address(this)); } else { _vaultStorage.apeCoinStaking.withdrawMAYC(singleNfts_, address(this)); } vars.totalReward = _vaultStorage.apeCoin.balanceOf(address(this)) - vars.cachedBalance - vars.totalPrincipal; // refund ape coin for single nft refund = _vaultStorage.refunds[nft_][vars.staker]; refund.principal += vars.totalPrincipal; refund.reward += vars.totalReward; // update bayc&mayc position and debt if (vars.totalReward > 0) { _updateRewardsDebt(_vaultStorage, nft_, vars.staker, vars.totalReward); } _decreasePosition(_vaultStorage, nft_, vars.staker, vars.totalPrincipal); emit SingleNftUnstaked(nft_, vars.staker, singleNfts_); } if (vars.pairingNftSize > 0) { IApeCoinStaking.PairNftWithdrawWithAmount[] memory pairingNfts = new IApeCoinStaking.PairNftWithdrawWithAmount[](vars.pairingNftSize); IApeCoinStaking.PairNftWithdrawWithAmount[] memory emptyNfts; for (uint256 i = 0; i < tokenIds_.length; i++) { vars.tokenId = tokenIds_[i]; pairingStatus = _vaultStorage.apeCoinStaking.mainToBakc(vars.poolId, vars.tokenId); vars.bakcTokenId = pairingStatus.tokenId; vars.stakedAmount = _vaultStorage .apeCoinStaking .nftPosition(ApeStakingLib.BAKC_POOL_ID, vars.bakcTokenId) .stakedAmount; if ( pairingStatus.isPaired && // make sure the bakc locked in valult IERC721Upgradeable(_vaultStorage.bakc).ownerOf(vars.bakcTokenId) == address(this) && vars.stakedAmount > 0 ) { vars.totalPairingPrincipal += vars.stakedAmount; pairingNfts[vars.pairingNftIndex] = IApeCoinStaking.PairNftWithdrawWithAmount({ mainTokenId: vars.tokenId.toUint32(), bakcTokenId: vars.bakcTokenId.toUint32(), amount: vars.stakedAmount.toUint184(), isUncommit: true }); vars.pairingNftIndex += 1; _vaultStorage.stakingTokenIds[_vaultStorage.bakc][vars.staker].remove(vars.bakcTokenId); } } vars.cachedBalance = _vaultStorage.apeCoin.balanceOf(address(this)); if (nft_ == _vaultStorage.bayc) { _vaultStorage.apeCoinStaking.withdrawBAKC(pairingNfts, emptyNfts); emit PairedNftUnstaked(vars.staker, pairingNfts, emptyNfts); } else { _vaultStorage.apeCoinStaking.withdrawBAKC(emptyNfts, pairingNfts); emit PairedNftUnstaked(vars.staker, emptyNfts, pairingNfts); } vars.totalPairingReward = _vaultStorage.apeCoin.balanceOf(address(this)) - vars.cachedBalance - vars.totalPairingPrincipal; // refund ape coin for paring nft refund = _vaultStorage.refunds[_vaultStorage.bakc][vars.staker]; refund.principal += vars.totalPairingPrincipal; refund.reward += vars.totalPairingReward; // update bakc position and debt if (vars.totalPairingReward > 0) { _updateRewardsDebt(_vaultStorage, _vaultStorage.bakc, vars.staker, vars.totalPairingReward); } _decreasePosition(_vaultStorage, _vaultStorage.bakc, vars.staker, vars.totalPairingPrincipal); } } struct RefundPairingPoolVars { uint256 cachedBalance; uint256 tokenId; uint256 stakedAmount; // refund address staker; uint256 totalPrincipal; uint256 totalReward; // array uint256 baycIndex; uint256 baycSize; uint256 maycIndex; uint256 maycSize; } function _refundPairingPool(INftVault.VaultStorage storage _vaultStorage, uint256[] calldata tokenIds_) external { require(tokenIds_.length > 0, "nftVault: invalid tokenIds"); RefundPairingPoolVars memory vars; IApeCoinStaking.PairingStatus memory pairingStatus; vars.staker = _stakerOf(_vaultStorage, _vaultStorage.bakc, tokenIds_[0]); require(vars.staker != address(0), "nftVault: invalid staker"); vars.cachedBalance = _vaultStorage.apeCoin.balanceOf(address(this)); // Calculate the nft array size for (uint256 i = 0; i < tokenIds_.length; i++) { vars.tokenId = tokenIds_[i]; require( msg.sender == _ownerOf(_vaultStorage, _vaultStorage.bakc, vars.tokenId), "nftVault: caller must be nft owner" ); // make sure the bakc locked in valult require( address(this) == IERC721Upgradeable(_vaultStorage.bakc).ownerOf(vars.tokenId), "nftVault: invalid token id" ); require( vars.staker == _stakerOf(_vaultStorage, _vaultStorage.bakc, vars.tokenId), "nftVault: staker must be same" ); vars.stakedAmount = _vaultStorage .apeCoinStaking .nftPosition(ApeStakingLib.BAKC_POOL_ID, vars.tokenId) .stakedAmount; if (vars.stakedAmount > 0) { pairingStatus = _vaultStorage.apeCoinStaking.bakcToMain(vars.tokenId, ApeStakingLib.BAYC_POOL_ID); // make sure the bayc locked in valult if ( pairingStatus.isPaired && IERC721Upgradeable(_vaultStorage.bayc).ownerOf(pairingStatus.tokenId) == address(this) ) { vars.baycSize += 1; } else { pairingStatus = _vaultStorage.apeCoinStaking.bakcToMain(vars.tokenId, ApeStakingLib.MAYC_POOL_ID); // make sure the mayc locked in valult if ( pairingStatus.isPaired && IERC721Upgradeable(_vaultStorage.mayc).ownerOf(pairingStatus.tokenId) == address(this) ) { vars.maycSize += 1; } } } } if (vars.baycSize > 0 || vars.maycSize > 0) { IApeCoinStaking.PairNftWithdrawWithAmount[] memory baycNfts_ = new IApeCoinStaking.PairNftWithdrawWithAmount[](vars.baycSize); IApeCoinStaking.PairNftWithdrawWithAmount[] memory maycNfts_ = new IApeCoinStaking.PairNftWithdrawWithAmount[](vars.maycSize); for (uint256 i = 0; i < tokenIds_.length; i++) { vars.tokenId = tokenIds_[i]; vars.stakedAmount = _vaultStorage .apeCoinStaking .nftPosition(ApeStakingLib.BAKC_POOL_ID, vars.tokenId) .stakedAmount; if (vars.stakedAmount > 0) { pairingStatus = _vaultStorage.apeCoinStaking.bakcToMain(vars.tokenId, ApeStakingLib.BAYC_POOL_ID); // make sure the bayc locked in valult if ( pairingStatus.isPaired && IERC721Upgradeable(_vaultStorage.bayc).ownerOf(pairingStatus.tokenId) == address(this) ) { vars.totalPrincipal += vars.stakedAmount; baycNfts_[vars.baycIndex] = IApeCoinStaking.PairNftWithdrawWithAmount({ mainTokenId: pairingStatus.tokenId.toUint32(), bakcTokenId: vars.tokenId.toUint32(), amount: vars.stakedAmount.toUint184(), isUncommit: true }); vars.baycIndex += 1; _vaultStorage.stakingTokenIds[_vaultStorage.bakc][vars.staker].remove(vars.tokenId); } else { pairingStatus = _vaultStorage.apeCoinStaking.bakcToMain( vars.tokenId, ApeStakingLib.MAYC_POOL_ID ); // make sure the mayc locked in valult if ( pairingStatus.isPaired && IERC721Upgradeable(_vaultStorage.mayc).ownerOf(pairingStatus.tokenId) == address(this) ) { vars.totalPrincipal += vars.stakedAmount; maycNfts_[vars.maycIndex] = IApeCoinStaking.PairNftWithdrawWithAmount({ mainTokenId: pairingStatus.tokenId.toUint32(), bakcTokenId: vars.tokenId.toUint32(), amount: vars.stakedAmount.toUint184(), isUncommit: true }); vars.maycIndex += 1; _vaultStorage.stakingTokenIds[_vaultStorage.bakc][vars.staker].remove(vars.tokenId); } } } } _vaultStorage.apeCoinStaking.withdrawBAKC(baycNfts_, maycNfts_); vars.totalReward = _vaultStorage.apeCoin.balanceOf(address(this)) - vars.cachedBalance - vars.totalPrincipal; // refund ape coin for bakc INftVault.Refund storage _refund = _vaultStorage.refunds[_vaultStorage.bakc][vars.staker]; _refund.principal += vars.totalPrincipal; _refund.reward += vars.totalReward; // update bakc position and debt if (vars.totalReward > 0) { _updateRewardsDebt(_vaultStorage, _vaultStorage.bakc, vars.staker, vars.totalReward); } _decreasePosition(_vaultStorage, _vaultStorage.bakc, vars.staker, vars.totalPrincipal); emit PairedNftUnstaked(vars.staker, baycNfts_, maycNfts_); } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/stakednft/VaultLogic.sol": { "VaultLogic": "0xd058dcd7bd6db27eb2442304bc6135dda5f70124" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"NftDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"NftWithdrawn","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":true,"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"uint128","name":"mainTokenId","type":"uint128"},{"internalType":"uint128","name":"bakcTokenId","type":"uint128"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNft[]","name":"baycPairs","type":"tuple[]"},{"components":[{"internalType":"uint128","name":"mainTokenId","type":"uint128"},{"internalType":"uint128","name":"bakcTokenId","type":"uint128"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNft[]","name":"maycPairs","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"PairedNftClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNftDepositWithAmount[]","name":"baycPairs","type":"tuple[]"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNftDepositWithAmount[]","name":"maycPairs","type":"tuple[]"}],"name":"PairedNftStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"},{"internalType":"bool","name":"isUncommit","type":"bool"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNftWithdrawWithAmount[]","name":"baycPairs","type":"tuple[]"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"},{"internalType":"bool","name":"isUncommit","type":"bool"}],"indexed":false,"internalType":"struct IApeCoinStaking.PairNftWithdrawWithAmount[]","name":"maycPairs","type":"tuple[]"}],"name":"PairedNftUnstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"SingleNftClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"indexed":false,"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts","type":"tuple[]"}],"name":"SingleNftStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"indexed":false,"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts","type":"tuple[]"}],"name":"SingleNftUnstaked","type":"event"},{"inputs":[{"internalType":"address","name":"addr_","type":"address"},{"internalType":"bool","name":"authorized_","type":"bool"}],"name":"authorise","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"mainTokenId","type":"uint128"},{"internalType":"uint128","name":"bakcTokenId","type":"uint128"}],"internalType":"struct IApeCoinStaking.PairNft[]","name":"baycPairs_","type":"tuple[]"},{"components":[{"internalType":"uint128","name":"mainTokenId","type":"uint128"},{"internalType":"uint128","name":"bakcTokenId","type":"uint128"}],"internalType":"struct IApeCoinStaking.PairNft[]","name":"maycPairs_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"claimBakcPool","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"claimBaycPool","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"claimMaycPool","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"address","name":"staker_","type":"address"}],"name":"depositNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"getDelegateCashForToken","outputs":[{"internalType":"address[][]","name":"delegates","type":"address[][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"getDelegateCashForTokenV2","outputs":[{"internalType":"address[][]","name":"delegates","type":"address[][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IApeCoinStaking","name":"apeCoinStaking_","type":"address"},{"internalType":"contract IDelegationRegistry","name":"delegationRegistry_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"isStaking","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"}],"name":"positionOf","outputs":[{"components":[{"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"internalType":"int256","name":"rewardsDebt","type":"int256"}],"internalType":"struct INftVault.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"}],"name":"refundOf","outputs":[{"components":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"internalType":"struct INftVault.Refund","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate_","type":"address"},{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"bool","name":"value_","type":"bool"}],"name":"setDelegateCash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate_","type":"address"},{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"bool","name":"value_","type":"bool"}],"name":"setDelegateCashV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"registryV2_","type":"address"}],"name":"setDelegationRegistryV2Contract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"}],"internalType":"struct IApeCoinStaking.PairNftDepositWithAmount[]","name":"baycPairs_","type":"tuple[]"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"}],"internalType":"struct IApeCoinStaking.PairNftDepositWithAmount[]","name":"maycPairs_","type":"tuple[]"}],"name":"stakeBakcPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts_","type":"tuple[]"}],"name":"stakeBaycPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts_","type":"tuple[]"}],"name":"stakeMaycPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"stakerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"stakingNftIdByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"address","name":"staker_","type":"address"}],"name":"totalStakingNft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"},{"internalType":"bool","name":"isUncommit","type":"bool"}],"internalType":"struct IApeCoinStaking.PairNftWithdrawWithAmount[]","name":"baycPairs_","type":"tuple[]"},{"components":[{"internalType":"uint32","name":"mainTokenId","type":"uint32"},{"internalType":"uint32","name":"bakcTokenId","type":"uint32"},{"internalType":"uint184","name":"amount","type":"uint184"},{"internalType":"bool","name":"isUncommit","type":"bool"}],"internalType":"struct IApeCoinStaking.PairNftWithdrawWithAmount[]","name":"maycPairs_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"unstakeBakcPool","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"unstakeBaycPool","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"}],"internalType":"struct IApeCoinStaking.SingleNft[]","name":"nfts_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"unstakeMaycPool","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"withdrawNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nft_","type":"address"}],"name":"withdrawRefunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061575d80620000216000396000f3fe608060405234801561001057600080fd5b50600436106101e35760003560e01c806380ac82281161010f578063b74209d5116100a2578063e738c08c11610071578063e738c08c1461045f578063f2fde38b14610472578063f4e4304514610485578063f97b275c1461049857600080fd5b8063b74209d514610413578063c4eb20ef14610426578063d5d6e03a14610439578063dca866591461044c57600080fd5b8063a01ea1b4116100de578063a01ea1b4146103c7578063a04a2f8d146103da578063a168996b146103ed578063a198f6f41461040057600080fd5b806380ac822814610355578063892f928e146103685780638da5cb5b146103965780639a77b187146103a757600080fd5b80633c5569b6116101875780635a6c8fe0116101565780635a6c8fe0146103145780636617744b146103275780636fda09931461033a578063715018a61461034d57600080fd5b80633c5569b6146102c6578063485cc955146102d95780635523fa95146102ee57806356a0fd451461030157600080fd5b8063150b7a02116101c3578063150b7a02146102495780631f29d2dc1461027557806327f9bd13146102a057806339ef62ff146102b357600080fd5b806298deb6146101e8578062bf5b001461021557806301ec432314610228575b600080fd5b6101fb6101f636600461457b565b6104bb565b604080519283526020830191909152015b60405180910390f35b6101fb610223366004614642565b610a7b565b61023b610236366004614698565b610dee565b60405190815260200161020c565b61025c6102573660046146d1565b610e27565b6040516001600160e01b0319909116815260200161020c565b61028861028336600461476f565b610ec1565b6040516001600160a01b03909116815260200161020c565b6101fb6102ae366004614642565b610f39565b61023b6102c136600461479b565b611170565b61023b6102d4366004614820565b6111ab565b6102ec6102e7366004614698565b61141e565b005b6102ec6102fc366004614865565b6116d0565b61028861030f36600461476f565b6118c2565b6102ec6103223660046148d3565b611930565b6102ec610335366004614865565b611abd565b6102ec6103483660046148f0565b611c8d565b6102ec611cc0565b61023b610363366004614698565b611cd4565b61037b610376366004614698565b611e79565b6040805182518152602092830151928101929092520161020c565b6033546001600160a01b0316610288565b6103ba6103b536600461491e565b611f2d565b60405161020c9190614972565b6102ec6103d536600461491e565b612217565b6102ec6103e8366004614a05565b6126a4565b6103ba6103fb36600461491e565b612aa2565b61023b61040e366004614a6c565b612bcf565b6102ec610421366004614acd565b612f9a565b61023b610434366004614820565b61325b565b6102ec610447366004614acd565b6133a6565b6102ec61045a366004614b52565b6135ce565b6102ec61046d3660046148d3565b6139b6565b6102ec6104803660046148d3565b6139e0565b61037b610493366004614698565b613a59565b6104ab6104a636600461479b565b613b0d565b604051901515815260200161020c565b33600090815260a16020526040812054819060ff166104f55760405162461bcd60e51b81526004016104ec90614bbd565b60405180910390fd5b6104fd613b3e565b609f5460408051808201909152600080825260208201526001600160a01b039091169060408051608081018252600080825260208201819052918101829052606081019190915260005b898110156106ac578a8a8281811061056157610561614bf4565b9050608002018036038101906105779190614cec565b609d54815191935061059b916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156105e157506105cc609785846020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6105fd5760405162461bcd60e51b81526004016104ec90614d4d565b6020820151609b54610626916001600160a01b0390911690869063ffffffff90811690613bc316565b925081606001516106445781604001516001600160b81b0316610647565b82515b6106519087614da6565b955081606001511561069a576020808301516001600160a01b0386166000908152609a83526040808220338352909352919091206106989163ffffffff90811690613c5716565b505b806106a481614db9565b915050610547565b5060005b87811015610815578888828181106106ca576106ca614bf4565b9050608002018036038101906106e09190614cec565b609e548151919350610704916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b031614801561074a5750610735609785846020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6107665760405162461bcd60e51b81526004016104ec90614d4d565b6020820151609b5461078f916001600160a01b0390911690869063ffffffff90811690613bc316565b925081606001516107ad5781604001516001600160b81b03166107b0565b82515b6107ba9087614da6565b9550816060015115610803576020808301516001600160a01b0386166000908152609a83526040808220338352909352919091206108019163ffffffff90811690613c5716565b505b8061080d81614db9565b9150506106b0565b50609c546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561085e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108829190614dd2565b609b546040516326fb224960e01b81529195506001600160a01b0316906326fb2249906108b9908d908d908d908d90600401614e74565b600060405180830381600087803b1580156108d357600080fd5b505af11580156108e7573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81523060048201528893508792506001600160a01b03909116906370a0823190602401602060405180830381865afa158015610937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095b9190614dd2565b6109659190614ea6565b61096f9190614ea6565b93508315610984576109846097843387613c63565b6109916097843388613cbb565b609c546001600160a01b031663a9059cbb876109ad8789614da6565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156109f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1c9190614eb9565b50336001600160a01b03167fe5dd4a33d6e8891ae6b9b9ca8854301bee1e9b6f282415cf77603ba58f2d35028b8b8b8b604051610a5c9493929190614e74565b60405180910390a2505050610a716001606555565b9550959350505050565b33600090815260a16020526040812054819060ff16610aac5760405162461bcd60e51b81526004016104ec90614bbd565b610ab4613b3e565b609e546001600160a01b0316610ada604080518082019091526000808252602082015290565b604080518082019091526000808252602082015260005b87811015610c0e57888882818110610b0b57610b0b614bf4565b905060400201803603810190610b219190614eed565b9250610b39609785856000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b031614610b695760405162461bcd60e51b81526004016104ec90614d4d565b6020830151610b81906001600160e01b031687614da6565b8351609b54919750610ba8916001600160a01b031690869063ffffffff90811690613bc316565b915082602001516001600160e01b0316826000015103610bfc5782516001600160a01b0385166000908152609a602090815260408083203384529091529020610bfa9163ffffffff90811690613c5716565b505b80610c0681614db9565b915050610af1565b50609c546040516370a0823160e01b81526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa158015610c59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7d9190614dd2565b609b54604051637691e48360e11b81529195506001600160a01b03169063ed23c90690610cb2908b908b908b90600401614f7e565b600060405180830381600087803b158015610ccc57600080fd5b505af1158015610ce0573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b038a81166004830152899450889350909116906370a0823190602401602060405180830381865afa158015610d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d569190614dd2565b610d609190614ea6565b610d6a9190614ea6565b93508315610d7f57610d7f6097843387613c63565b610d8c6097843388613cbb565b336001600160a01b0316836001600160a01b03167f2a7470cabdc5637d04a07737768a7a78fad4c821d0de0ea8b8544dfe12427c398a8a604051610dd1929190614faa565b60405180910390a3505050610de66001606555565b935093915050565b6001600160a01b038083166000908152609a602090815260408083209385168352929052908120610e1e90613d46565b90505b92915050565b609d546000906001600160a01b0316331480610e4d5750609e546001600160a01b031633145b80610e625750609f546001600160a01b031633145b610eae5760405162461bcd60e51b815260206004820152601860248201527f4e66745661756c743a2063616c6c6572206e6f7420617065000000000000000060448201526064016104ec565b50630a85bd0160e11b5b95945050505050565b609d5460009083906001600160a01b0380831691161480610eef5750609e546001600160a01b038281169116145b80610f075750609f546001600160a01b038281169116145b610f235760405162461bcd60e51b81526004016104ec90614fbe565b610f2f60978585613d50565b91505b5092915050565b33600090815260a16020526040812054819060ff16610f6a5760405162461bcd60e51b81526004016104ec90614bbd565b610f72613b3e565b609d546001600160a01b0316610f98604080518082019091526000808252602082015290565b604080518082019091526000808252602082015260005b878110156110cc57888882818110610fc957610fc9614bf4565b905060400201803603810190610fdf9190614eed565b9250610ff7609785856000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146110275760405162461bcd60e51b81526004016104ec90614d4d565b602083015161103f906001600160e01b031687614da6565b8351609b54919750611066916001600160a01b031690869063ffffffff90811690613bc316565b915082602001516001600160e01b03168260000151036110ba5782516001600160a01b0385166000908152609a6020908152604080832033845290915290206110b89163ffffffff90811690613c5716565b505b806110c481614db9565b915050610faf565b50609c546040516370a0823160e01b81526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190614dd2565b609b5460405163aceb362960e01b81529195506001600160a01b03169063aceb362990610cb2908b908b908b90600401614f7e565b6001600160a01b038084166000908152609a6020908152604080832093861683529290529081206111a19083613d79565b90505b9392505050565b33600090815260a1602052604081205460ff166111da5760405162461bcd60e51b81526004016104ec90614bbd565b6111e2613b3e565b609d546001600160a01b031660005b8481101561125f5761121d60978388888581811061121157611211614bf4565b90506020020135613b97565b6001600160a01b0316336001600160a01b03161461124d5760405162461bcd60e51b81526004016104ec90614d4d565b8061125781614db9565b9150506111f1565b50609c546040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190614dd2565b609b5460405163b682e85960e01b81529193506001600160a01b03169063b682e859906113039088908890889060040161501b565b600060405180830381600087803b15801561131d57600080fd5b505af1158015611331573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b03878116600483015286945090911691506370a0823190602401602060405180830381865afa158015611381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a59190614dd2565b6113af9190614ea6565b915081156113c4576113c46097823385613c63565b336001600160a01b0316816001600160a01b03167fad95cc123bbb3335e10eb45354da192c0db46c8383bcc925c1f9dd9848b6001e87878660405161140b9392919061502f565b60405180910390a3506111a46001606555565b600054610100900460ff161580801561143e5750600054600160ff909116105b806114585750303b158015611458575060005460ff166001145b6114bb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104ec565b6000805460ff1916600117905580156114de576000805461ff0019166101001790555b6114e6613d85565b6114ee613db4565b609b80546001600160a01b038086166001600160a01b0319928316811790935560a08054918616919092161790556040805163563d6cdd60e11b8152905163ac7ad9ba916004818101926020929091908290030181865afa158015611557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157b919061505e565b609c80546001600160a01b0319166001600160a01b03928316179055609b546115a49116613de3565b609d80546001600160a01b0319166001600160a01b03928316179055609b546115cd9116613e50565b609e80546001600160a01b0319166001600160a01b03928316179055609b546115f69116613e80565b609f80546001600160a01b0319166001600160a01b03928316179055609c54609b5460405163095ea7b360e01b81529083166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015611660573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116849190614eb9565b5080156116cb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b33600090815260a1602052604090205460ff166116ff5760405162461bcd60e51b81526004016104ec90614bbd565b609d5484906001600160a01b038083169116148061172a5750609e546001600160a01b038281169116145b806117425750609f546001600160a01b038281169116145b61175e5760405162461bcd60e51b81526004016104ec90614fbe565b6001600160a01b0386166117b45760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c69642064656c656761746500000000000060448201526064016104ec565b6000805b848110156118b8578585828181106117d2576117d2614bf4565b9050602002013591506117e760978884613d50565b6001600160a01b0316336001600160a01b0316146118175760405162461bcd60e51b81526004016104ec9061507b565b60a25460405163b18e2bbb60e01b81526001600160a01b038a811660048301528981166024830152604482018590526000606483015286151560848301529091169063b18e2bbb9060a4016020604051808303816000875af1158015611881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a59190614dd2565b50806118b081614db9565b9150506117b8565b5050505050505050565b609d5460009083906001600160a01b03808316911614806118f05750609e546001600160a01b038281169116145b806119085750609f546001600160a01b038281169116145b6119245760405162461bcd60e51b81526004016104ec90614fbe565b610f2f60978585613b97565b609d5481906001600160a01b038083169116148061195b5750609e546001600160a01b038281169116145b806119735750609f546001600160a01b038281169116145b61198f5760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166119be5760405162461bcd60e51b81526004016104ec90614bbd565b6119c6613b3e565b6001600160a01b0382166000908152609860209081526040808320338452825280832081518083019092528054808352600190910154928201839052909291611a0e91614da6565b6001600160a01b03858116600090815260986020908152604080832033808552925280832083815560010192909255609c54915163a9059cbb60e01b8152600481019190915260248101849052929350169063a9059cbb906044016020604051808303816000875af1158015611a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aac9190614eb9565b505050611ab96001606555565b5050565b33600090815260a1602052604090205460ff16611aec5760405162461bcd60e51b81526004016104ec90614bbd565b609d5484906001600160a01b0380831691161480611b175750609e546001600160a01b038281169116145b80611b2f5750609f546001600160a01b038281169116145b611b4b5760405162461bcd60e51b81526004016104ec90614fbe565b6001600160a01b038616611ba15760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c69642064656c656761746500000000000060448201526064016104ec565b6000805b848110156118b857858582818110611bbf57611bbf614bf4565b905060200201359150611bd460978884613d50565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b81526004016104ec9061507b565b60a05460405163537a5c3d60e01b81526001600160a01b038a8116600483015289811660248301526044820185905286151560648301529091169063537a5c3d90608401600060405180830381600087803b158015611c6257600080fd5b505af1158015611c76573d6000803e3d6000fd5b505050508080611c8590614db9565b915050611ba5565b611c95613eb0565b6001600160a01b0391909116600090815260a160205260409020805460ff1916911515919091179055565b611cc8613eb0565b611cd26000613f0a565b565b609d5460009083906001600160a01b0380831691161480611d025750609e546001600160a01b038281169116145b80611d1a5750609f546001600160a01b038281169116145b611d365760405162461bcd60e51b81526004016104ec90614fbe565b609b54600090611d4f906001600160a01b031686613f5c565b6001600160a01b0380871660009081526099602090815260408083209389168352928152828220835180850190945280548452600101549083015282519293509091611dbb90889065ffffffffffff16611da7613ff8565b609b546001600160a01b0316929190614030565b50606084015184519192506001600160601b031690611de590610e109065ffffffffffff16614da6565b42118015611dff575060408401516001600160601b031615155b15611e3b5760408401516001600160601b0316611e24670de0b6b3a7640000846150bc565b611e2e91906150e9565b611e389082614da6565b90505b670de0b6b3a76400008360200151828560000151611e5991906150bc565b611e6391906150fd565b611e6d91906150e9565b98975050505050505050565b6040805180820190915260008082526020820152609d5483906001600160a01b0380831691161480611eb85750609e546001600160a01b038281169116145b80611ed05750609f546001600160a01b038281169116145b611eec5760405162461bcd60e51b81526004016104ec90614fbe565b50506001600160a01b039182166000908152609960209081526040808320939094168252918252829020825180840190935280548352600101549082015290565b60a2546040516328a92f4d60e11b81523060048201526060916000916001600160a01b03909116906351525e9a90602401600060405180830381865afa158015611f7b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611fa39190810190615140565b9050826001600160401b03811115611fbd57611fbd614c0a565b604051908082528060200260200182016040528015611ff057816020015b6060815260200190600190039081611fdb5790505b5091506000805b8481101561220d5785858281811061201157612011614bf4565b905060200201359150600080600090505b84518110156120aa57886001600160a01b031685828151811061204757612047614bf4565b6020026020010151608001516001600160a01b031614801561208557508385828151811061207757612077614bf4565b602002602001015160a00151145b15612098578161209481614db9565b9250505b806120a281614db9565b915050612022565b50806001600160401b038111156120c3576120c3614c0a565b6040519080825280602002602001820160405280156120ec578160200160208202803683370190505b508583815181106120ff576120ff614bf4565b60209081029190910101526000805b85518110156121f757896001600160a01b031686828151811061213357612133614bf4565b6020026020010151608001516001600160a01b031614801561217157508486828151811061216357612163614bf4565b602002602001015160a00151145b156121e55785818151811061218857612188614bf4565b6020026020010151602001518785815181106121a6576121a6614bf4565b602002602001015183815181106121bf576121bf614bf4565b6001600160a01b0390921660209283029190910190910152816121e181614db9565b9250505b806121ef81614db9565b91505061210e565b505050808061220590614db9565b915050611ff7565b5050509392505050565b609d5483906001600160a01b03808316911614806122425750609e546001600160a01b038281169116145b8061225a5750609f546001600160a01b038281169116145b6122765760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166122a55760405162461bcd60e51b81526004016104ec90614bbd565b6122ad613b3e565b816122fa5760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c696420746f6b656e49647300000000000060448201526064016104ec565b60006123156097868686600081811061121157611211614bf4565b609d549091506001600160a01b03868116911614806123415750609e546001600160a01b038681169116145b156123b957604051632b56690d60e01b815273d058dcd7bd6db27eb2442304bc6135dda5f7012490632b56690d906123849060979089908990899060040161524d565b60006040518083038186803b15801561239c57600080fd5b505af41580156123b0573d6000803e3d6000fd5b5050505061243c565b609f546001600160a01b039081169086160361243c5760405163209401b560e11b815273d058dcd7bd6db27eb2442304bc6135dda5f7012490634128036a9061240b9060979088908890600401615282565b60006040518083038186803b15801561242357600080fd5b505af4158015612437573d6000803e3d6000fd5b505050505b60005b8381101561263b5761246b60978787878581811061245f5761245f614bf4565b90506020020135613d50565b6001600160a01b0316336001600160a01b0316146124d65760405162461bcd60e51b815260206004820152602260248201527f6e66745661756c743a2063616c6c6572206d757374206265206e6674206f776e60448201526132b960f11b60648201526084016104ec565b6124ee60978787878581811061121157611211614bf4565b6001600160a01b0316826001600160a01b03161461254e5760405162461bcd60e51b815260206004820152601d60248201527f6e66745661756c743a207374616b6572206d7573742062652073616d6500000060448201526064016104ec565b6001600160a01b03861660009081526097602052604081209086868481811061257957612579614bf4565b6020908102929092013583525081019190915260400160002080546001600160a01b031990811682556001909101805490911690556001600160a01b0386166342842e0e30338888868181106125d1576125d1614bf4565b905060200201356040518463ffffffff1660e01b81526004016125f69392919061529c565b600060405180830381600087803b15801561261057600080fd5b505af1158015612624573d6000803e3d6000fd5b50505050808061263390614db9565b91505061243f565b50806001600160a01b0316336001600160a01b0316866001600160a01b03167f1027039dd42454c88e1ee31b26b4ec90b0b5b87696e51f9dcdcb9a7ea9fdf66f878760405161268b9291906152c0565b60405180910390a45061269e6001606555565b50505050565b609d5484906001600160a01b03808316911614806126cf5750609e546001600160a01b038281169116145b806126e75750609f546001600160a01b038281169116145b6127035760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166127325760405162461bcd60e51b81526004016104ec90614bbd565b61273a613b3e565b60008061275a604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015260005b87811015612a355788888281811061278b5761278b614bf4565b609b546020909102929092013596506127b0916001600160a01b031690508b87613bc3565b8051909350156128025760405162461bcd60e51b815260206004820152601c60248201527f6e66745661756c743a206e667420616c7265616479207374616b65640000000060448201526064016104ec565b609d546001600160a01b038b81169116148061282b5750609e546001600160a01b038b81169116145b1561291857609b54612846906001600160a01b03168b6140c6565b609b5460405162c13e2360e61b815260048101839052602481018890529195506001600160a01b03169063304f88c0906044016040805180830381865afa158015612895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b991906152d4565b91508160200151156129185760405162461bcd60e51b815260206004820152602260248201527f6e66745661756c743a20616c72656164792070616972656420776974682062616044820152616b6360f01b60648201526084016104ec565b896001600160a01b03166342842e0e33308c8c8681811061293b5761293b614bf4565b905060200201356040518463ffffffff1660e01b81526004016129609392919061529c565b600060405180830381600087803b15801561297a57600080fd5b505af115801561298e573d6000803e3d6000fd5b50506040805180820182523381526001600160a01b038b8116602080840191909152908f166000908152609790915291822090935091508b8b858181106129d7576129d7614bf4565b6020908102929092013583525081810192909252604001600020825181546001600160a01b03199081166001600160a01b03928316178355939092015160019091018054909316911617905580612a2d81614db9565b915050612771565b50856001600160a01b0316336001600160a01b03168a6001600160a01b03167f89bdad4dcd6b4c2725002d1ed53dc73e8f882576622ade4ab6dc57550c5f541a8b8b604051612a859291906152c0565b60405180910390a450505050612a9b6001606555565b5050505050565b6060816001600160401b03811115612abc57612abc614c0a565b604051908082528060200260200182016040528015612aef57816020015b6060815260200190600190039081612ada5790505b5090506000805b83811015612bc657848482818110612b1057612b10614bf4565b60a054604051631221156b60e01b81526020909202939093013594506001600160a01b0390921691631221156b9150612b519030908a90879060040161529c565b600060405180830381865afa158015612b6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b969190810190615315565b838281518110612ba857612ba8614bf4565b60200260200101819052508080612bbe90614db9565b915050612af6565b50509392505050565b33600090815260a1602052604081205460ff16612bfe5760405162461bcd60e51b81526004016104ec90614bbd565b612c06613b3e565b609f5460408051808201909152600080825260208201526001600160a01b039091169060005b87811015612cfa57888882818110612c4657612c46614bf4565b905060400201803603810190612c5c91906153ba565b609d548151919350612c83916097916001600160a01b0316906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316148015612ccc5750612cb760978484602001516001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316145b612ce85760405162461bcd60e51b81526004016104ec90614d4d565b80612cf281614db9565b915050612c2c565b5060005b85811015612ddc57868682818110612d1857612d18614bf4565b905060400201803603810190612d2e91906153ba565b609e548151919350612d55916097916001600160a01b0316906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316148015612dae5750609f546020830151612d99916097916001600160a01b03909116906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316145b612dca5760405162461bcd60e51b81526004016104ec90614d4d565b80612dd481614db9565b915050612cfe565b50609c546040516370a0823160e01b81526001600160a01b038681166004830152909116906370a0823190602401602060405180830381865afa158015612e27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e4b9190614dd2565b609b546040516303fafd2560e11b81529194506001600160a01b0316906307f5fa4a90612e84908b908b908b908b908b9060040161543d565b600060405180830381600087803b158015612e9e57600080fd5b505af1158015612eb2573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b03888116600483015287945090911691506370a0823190602401602060405180830381865afa158015612f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f269190614dd2565b612f309190614ea6565b92508215612f4557612f456097833386613c63565b336001600160a01b03167f359f9a3961795346f7f440d092fb9d342afb8e02b55959716f9d730db1bb02f08989898988604051612f8695949392919061547f565b60405180910390a25050610eb86001606555565b33600090815260a1602052604090205460ff16612fc95760405162461bcd60e51b81526004016104ec90614bbd565b612fd1613b3e565b609d546001600160a01b03166000612ff9604080518082019091526000808252602082015290565b60005b848110156131175785858281811061301657613016614bf4565b90506040020180360381019061302c9190614eed565b9150613044609785846000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146130b05760405162461bcd60e51b8152602060048201526024808201527f6e66745661756c743a2063616c6c6572206d757374206265206261796320737460448201526330b5b2b960e11b60648201526084016104ec565b60208201516130c8906001600160e01b031684614da6565b82516001600160a01b0386166000908152609a602090815260408083203384529091529020919450613104919063ffffffff9081169061429a16565b508061310f81614db9565b915050612ffc565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061314c9033903090879060040161529c565b6020604051808303816000875af115801561316b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318f9190614eb9565b50609b546040516346583a0560e01b81526001600160a01b03909116906346583a05906131c29088908890600401614faa565b600060405180830381600087803b1580156131dc57600080fd5b505af11580156131f0573d6000803e3d6000fd5b5050505061320160978433856142a6565b336001600160a01b0316836001600160a01b03167f2c9b881f0a9073f196214688cd6329c4b6f020b4550467107b786e2fe7d225bc8787604051613246929190614faa565b60405180910390a3505050611ab96001606555565b33600090815260a1602052604081205460ff1661328a5760405162461bcd60e51b81526004016104ec90614bbd565b613292613b3e565b609e546001600160a01b031660005b84811015613303576132c160978388888581811061121157611211614bf4565b6001600160a01b0316336001600160a01b0316146132f15760405162461bcd60e51b81526004016104ec90614d4d565b806132fb81614db9565b9150506132a1565b50609c546040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa15801561334e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133729190614dd2565b609b546040516257a26360e81b81529193506001600160a01b0316906357a26300906113039088908890889060040161501b565b33600090815260a1602052604090205460ff166133d55760405162461bcd60e51b81526004016104ec90614bbd565b6133dd613b3e565b609e546001600160a01b03166000613405604080518082019091526000808252602082015290565b60005b848110156135235785858281811061342257613422614bf4565b9050604002018036038101906134389190614eed565b9150613450609785846000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146134bc5760405162461bcd60e51b8152602060048201526024808201527f6e66745661756c743a2063616c6c6572206d757374206265206d61796320737460448201526330b5b2b960e11b60648201526084016104ec565b60208201516134d4906001600160e01b031684614da6565b82516001600160a01b0386166000908152609a602090815260408083203384529091529020919450613510919063ffffffff9081169061429a16565b508061351b81614db9565b915050613408565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906135589033903090879060040161529c565b6020604051808303816000875af1158015613577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359b9190614eb9565b50609b54604051638ecbffa760e01b81526001600160a01b0390911690638ecbffa7906131c29088908890600401614faa565b33600090815260a1602052604090205460ff166135fd5760405162461bcd60e51b81526004016104ec90614bbd565b613605613b3e565b60408051606081018252600080825260208201819052918101829052609f546001600160a01b031660005b868110156137505787878281811061364a5761364a614bf4565b90506060020180360381019061366091906154b9565b609d548151919450613684916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156136ca57506136b5609783856020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6136e65760405162461bcd60e51b81526004016104ec90614d4d565b60408301516136fe906001600160b81b031685614da6565b6020808501516001600160a01b0385166000908152609a835260408082203383529093529190912091955061373d919063ffffffff9081169061429a16565b508061374881614db9565b915050613630565b5060005b848110156138745785858281811061376e5761376e614bf4565b90506060020180360381019061378491906154b9565b609e5481519194506137a8916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156137ee57506137d9609783856020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b61380a5760405162461bcd60e51b81526004016104ec90614d4d565b6040830151613822906001600160b81b031685614da6565b6020808501516001600160a01b0385166000908152609a8352604080822033835290935291909120919550613861919063ffffffff9081169061429a16565b508061386c81614db9565b915050613754565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906138a99033903090889060040161529c565b6020604051808303816000875af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614eb9565b50609b5460405163d346cbd960e01b81526001600160a01b039091169063d346cbd990613923908a908a908a908a9060040161558d565b600060405180830381600087803b15801561393d57600080fd5b505af1158015613951573d6000803e3d6000fd5b5050505061396260978233866142a6565b336001600160a01b03167f48265d3cee57f46b491ced0cebc5303c321890575e424108082d86d6b2f071c5888888886040516139a1949392919061558d565b60405180910390a250505061269e6001606555565b6139be613eb0565b60a280546001600160a01b0319166001600160a01b0392909216919091179055565b6139e8613eb0565b6001600160a01b038116613a4d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104ec565b613a5681613f0a565b50565b6040805180820190915260008082526020820152609d5483906001600160a01b0380831691161480613a985750609e546001600160a01b038281169116145b80613ab05750609f546001600160a01b038281169116145b613acc5760405162461bcd60e51b81526004016104ec90614fbe565b50506001600160a01b039182166000908152609860209081526040808320939094168252918252829020825180840190935280548352600101549082015290565b6001600160a01b038084166000908152609a6020908152604080832093861683529290529081206111a19083614317565b600260655403613b905760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104ec565b6002606555565b6001600160a01b0391821660009081526020938452604080822092825291909352909120600101541690565b6040805180820190915260008082526020820152836001600160a01b03166398ada4a2613bf086866140c6565b846040518363ffffffff1660e01b8152600401613c17929190918252602082015260400190565b6040805180830381865afa158015613c33573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a191906155b4565b6000610e1e838361432f565b6001600160a01b0380841660009081526002860160209081526040808320938616835292905220613c9c670de0b6b3a7640000836150bc565b816001016000828254613caf91906155e6565b90915550505050505050565b6001600160a01b03808416600090815260028601602090815260408083209386168352929052908120805490918391839190613cf8908490614ea6565b90915550506004850154613d15906001600160a01b031685613f5c565b60600151613d2c906001600160601b0316836150bc565b816001016000828254613caf91906150fd565b6001606555565b6000610e21825490565b6001600160a01b0391821660009081526020938452604080822092825291909352909120541690565b6000610e1e8383614422565b600054610100900460ff16613dac5760405162461bcd60e51b81526004016104ec9061560e565b611cd261444c565b600054610100900460ff16613ddb5760405162461bcd60e51b81526004016104ec9061560e565b611cd261447c565b6040516305da6c1560e11b8152600160048201526000906001600160a01b03831690630bb4d82a906024015b602060405180830381865afa158015613e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e21919061505e565b6040516305da6c1560e11b8152600260048201526000906001600160a01b03831690630bb4d82a90602401613e0f565b6040516305da6c1560e11b8152600360048201526000906001600160a01b03831690630bb4d82a90602401613e0f565b6033546001600160a01b03163314611cd25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104ec565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080516080810182526000808252602082018190529181018290526060810191909152826001600160a01b031663ac4afa38613f9985856140c6565b6040518263ffffffff1660e01b8152600401613fb791815260200190565b608060405180830381865afa158015613fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1e9190615670565b6000614003426144a3565b61400c426144b0565b61401790603c6150bc565b6140219190614da6565b61402b9042614ea6565b905090565b600080856001600160a01b031663d7464ee961404c88886140c6565b6040516001600160e01b031960e084901b168152600481019190915260248101879052604481018690526064016040805180830381865afa158015614095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b991906156d9565b9150915094509492505050565b6040516305da6c1560e11b8152600160048201526000906001600160a01b03841690630bb4d82a90602401602060405180830381865afa15801561410e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614132919061505e565b6001600160a01b0316826001600160a01b03160361415257506001610e21565b6040516305da6c1560e11b8152600260048201526001600160a01b03841690630bb4d82a90602401602060405180830381865afa158015614197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141bb919061505e565b6001600160a01b0316826001600160a01b0316036141db57506002610e21565b6040516305da6c1560e11b8152600360048201526001600160a01b03841690630bb4d82a90602401602060405180830381865afa158015614220573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614244919061505e565b6001600160a01b0316826001600160a01b03160361426457506003610e21565b60405162461bcd60e51b815260206004820152600b60248201526a1a5b9d985b1a59081b999d60aa1b60448201526064016104ec565b6000610e1e83836144cc565b6001600160a01b038084166000908152600286016020908152604080832093861683529290529081208054909183918391906142e3908490614da6565b90915550506004850154614300906001600160a01b031685613f5c565b60600151613c9c906001600160601b0316836150bc565b60008181526001830160205260408120541515610e1e565b60008181526001830160205260408120548015614418576000614353600183614ea6565b855490915060009061436790600190614ea6565b90508181146143cc57600086600001828154811061438757614387614bf4565b90600052602060002001549050808760000184815481106143aa576143aa614bf4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806143dd576143dd6156fd565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610e21565b6000915050610e21565b600082600001828154811061443957614439614bf4565b9060005260206000200154905092915050565b600054610100900460ff166144735760405162461bcd60e51b81526004016104ec9061560e565b611cd233613f0a565b600054610100900460ff16613d3f5760405162461bcd60e51b81526004016104ec9061560e565b6000610e21603c83615713565b6000806144bf610e1084615713565b90506111a4603c826150e9565b600081815260018301602052604081205461451357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610e21565b506000610e21565b60008083601f84011261452d57600080fd5b5081356001600160401b0381111561454457600080fd5b6020830191508360208260071b850101111561455f57600080fd5b9250929050565b6001600160a01b0381168114613a5657600080fd5b60008060008060006060868803121561459357600080fd5b85356001600160401b03808211156145aa57600080fd5b6145b689838a0161451b565b909750955060208801359150808211156145cf57600080fd5b506145dc8882890161451b565b90945092505060408601356145f081614566565b809150509295509295909350565b60008083601f84011261461057600080fd5b5081356001600160401b0381111561462757600080fd5b6020830191508360208260061b850101111561455f57600080fd5b60008060006040848603121561465757600080fd5b83356001600160401b0381111561466d57600080fd5b614679868287016145fe565b909450925050602084013561468d81614566565b809150509250925092565b600080604083850312156146ab57600080fd5b82356146b681614566565b915060208301356146c681614566565b809150509250929050565b6000806000806000608086880312156146e957600080fd5b85356146f481614566565b9450602086013561470481614566565b93506040860135925060608601356001600160401b038082111561472757600080fd5b818801915088601f83011261473b57600080fd5b81358181111561474a57600080fd5b89602082850101111561475c57600080fd5b9699959850939650602001949392505050565b6000806040838503121561478257600080fd5b823561478d81614566565b946020939093013593505050565b6000806000606084860312156147b057600080fd5b83356147bb81614566565b925060208401356147cb81614566565b929592945050506040919091013590565b60008083601f8401126147ee57600080fd5b5081356001600160401b0381111561480557600080fd5b6020830191508360208260051b850101111561455f57600080fd5b60008060006040848603121561483557600080fd5b83356001600160401b0381111561484b57600080fd5b614679868287016147dc565b8015158114613a5657600080fd5b60008060008060006080868803121561487d57600080fd5b853561488881614566565b9450602086013561489881614566565b935060408601356001600160401b038111156148b357600080fd5b6148bf888289016147dc565b90945092505060608601356145f081614857565b6000602082840312156148e557600080fd5b81356111a481614566565b6000806040838503121561490357600080fd5b823561490e81614566565b915060208301356146c681614857565b60008060006040848603121561493357600080fd5b833561493e81614566565b925060208401356001600160401b0381111561495957600080fd5b614965868287016147dc565b9497909650939450505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156149f757888603603f19018552825180518088529088019088880190845b818110156149e15783516001600160a01b03168352928a0192918a01916001016149bc565b509097505050938601939186019160010161499a565b509398975050505050505050565b60008060008060608587031215614a1b57600080fd5b8435614a2681614566565b935060208501356001600160401b03811115614a4157600080fd5b614a4d878288016147dc565b9094509250506040850135614a6181614566565b939692955090935050565b600080600080600060608688031215614a8457600080fd5b85356001600160401b0380821115614a9b57600080fd5b614aa789838a016145fe565b90975095506020880135915080821115614ac057600080fd5b506145dc888289016145fe565b60008060208385031215614ae057600080fd5b82356001600160401b03811115614af657600080fd5b614b02858286016145fe565b90969095509350505050565b60008083601f840112614b2057600080fd5b5081356001600160401b03811115614b3757600080fd5b60208301915083602060608302850101111561455f57600080fd5b60008060008060408587031215614b6857600080fd5b84356001600160401b0380821115614b7f57600080fd5b614b8b88838901614b0e565b90965094506020870135915080821115614ba457600080fd5b50614bb187828801614b0e565b95989497509550505050565b6020808252601f908201527f53744e66743a2063616c6c6572206973206e6f7420617574686f72697a656400604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715614c4257614c42614c0a565b60405290565b604080519081016001600160401b0381118282101715614c4257614c42614c0a565b60405160e081016001600160401b0381118282101715614c4257614c42614c0a565b604051601f8201601f191681016001600160401b0381118282101715614cb457614cb4614c0a565b604052919050565b803563ffffffff81168114614cd057600080fd5b919050565b80356001600160b81b0381168114614cd057600080fd5b600060808284031215614cfe57600080fd5b614d06614c20565b614d0f83614cbc565b8152614d1d60208401614cbc565b6020820152614d2e60408401614cd5565b60408201526060830135614d4181614857565b60608201529392505050565b60208082526023908201527f6e66745661756c743a2063616c6c6572206d757374206265206e66742073746160408201526235b2b960e91b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e2157610e21614d90565b600060018201614dcb57614dcb614d90565b5060010190565b600060208284031215614de457600080fd5b5051919050565b8183526000602080850194508260005b85811015614e695763ffffffff80614e1284614cbc565b16885280614e21858501614cbc565b16888501525060406001600160b81b03614e3c848301614cd5565b1690880152606082810135614e5081614857565b1515908801526080968701969190910190600101614dfb565b509495945050505050565b604081526000614e88604083018688614deb565b8281036020840152614e9b818587614deb565b979650505050505050565b81810381811115610e2157610e21614d90565b600060208284031215614ecb57600080fd5b81516111a481614857565b80356001600160e01b0381168114614cd057600080fd5b600060408284031215614eff57600080fd5b614f07614c48565b614f1083614cbc565b8152614f1e60208401614ed6565b60208201529392505050565b8183526000602080850194508260005b85811015614e695763ffffffff614f5083614cbc565b1687526001600160e01b03614f66838501614ed6565b16878401526040968701969190910190600101614f3a565b604081526000614f92604083018587614f2a565b905060018060a01b0383166020830152949350505050565b6020815260006111a1602083018486614f2a565b6020808252601190820152704e66745661756c743a206e6f742061706560781b604082015260600190565b81835260006001600160fb1b0383111561500257600080fd5b8260051b80836020870137939093016020019392505050565b604081526000614f92604083018587614fe9565b604081526000615043604083018587614fe9565b9050826020830152949350505050565b8051614cd081614566565b60006020828403121561507057600080fd5b81516111a481614566565b60208082526021908201527f6e66745661756c743a206f6e6c79206f776e65722063616e2064656c656761746040820152606560f81b606082015260800190565b8082028115828204841417610e2157610e21614d90565b634e487b7160e01b600052601260045260246000fd5b6000826150f8576150f86150d3565b500490565b8181036000831280158383131683831282161715610f3257610f32614d90565b60006001600160401b0382111561513657615136614c0a565b5060051b60200190565b6000602080838503121561515357600080fd5b82516001600160401b0381111561516957600080fd5b8301601f8101851361517a57600080fd5b805161518d6151888261511d565b614c8c565b81815260e091820283018401918482019190888411156151ac57600080fd5b938501935b838510156152415780858a0312156151c95760008081fd5b6151d1614c6a565b8551600681106151e15760008081fd5b81526151ee868801615053565b8782015260406151ff818801615053565b9082015260608681015190820152608061521a818801615053565b9082015260a0868101519082015260c08087015190820152835293840193918501916151b1565b50979650505050505050565b8481526001600160a01b03841660208201526060604082018190526000906152789083018486614fe9565b9695505050505050565b838152604060208201526000610eb8604083018486614fe9565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020815260006111a1602083018486614fe9565b6000604082840312156152e657600080fd5b6152ee614c48565b82516001600160f81b038116811461530557600080fd5b81526020830151614f1e81614857565b6000602080838503121561532857600080fd5b82516001600160401b0381111561533e57600080fd5b8301601f8101851361534f57600080fd5b805161535d6151888261511d565b81815260059190911b8201830190838101908783111561537c57600080fd5b928401925b82841015614e9b57835161539481614566565b82529284019290840190615381565b80356001600160801b0381168114614cd057600080fd5b6000604082840312156153cc57600080fd5b6153d4614c48565b6153dd836153a3565b8152614f1e602084016153a3565b8183526000602080850194508260005b85811015614e69576001600160801b0380615415846153a3565b168852806154248585016153a3565b16888501525060409687019691909101906001016153fb565b6060815260006154516060830187896153eb565b82810360208401526154648186886153eb565b91505060018060a01b03831660408301529695505050505050565b6060815260006154936060830187896153eb565b82810360208401526154a68186886153eb565b9150508260408301529695505050505050565b6000606082840312156154cb57600080fd5b604051606081018181106001600160401b03821117156154ed576154ed614c0a565b6040526154f983614cbc565b815261550760208401614cbc565b602082015261551860408401614cd5565b60408201529392505050565b8183526000602080850194508260005b85811015614e695763ffffffff8061554b84614cbc565b1688528061555a858501614cbc565b16888501525060406001600160b81b03615575848301614cd5565b16908801526060968701969190910190600101615534565b6040815260006155a1604083018688615524565b8281036020840152614e9b818587615524565b6000604082840312156155c657600080fd5b6155ce614c48565b82518152602083015160208201528091505092915050565b808201828112600083128015821682158216171561560657615606614d90565b505092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b80516001600160601b0381168114614cd057600080fd5b60006080828403121561568257600080fd5b61568a614c20565b825165ffffffffffff811681146156a057600080fd5b8152602083015161ffff811681146156b757600080fd5b60208201526156c860408401615659565b6040820152614d4160608401615659565b600080604083850312156156ec57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fd5b600082615722576157226150d3565b50069056fea26469706673582212200e6349938cf432519f33e28838ed53aaa97d7fad048caf8aea20bb7de0cd180364736f6c63430008120033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101e35760003560e01c806380ac82281161010f578063b74209d5116100a2578063e738c08c11610071578063e738c08c1461045f578063f2fde38b14610472578063f4e4304514610485578063f97b275c1461049857600080fd5b8063b74209d514610413578063c4eb20ef14610426578063d5d6e03a14610439578063dca866591461044c57600080fd5b8063a01ea1b4116100de578063a01ea1b4146103c7578063a04a2f8d146103da578063a168996b146103ed578063a198f6f41461040057600080fd5b806380ac822814610355578063892f928e146103685780638da5cb5b146103965780639a77b187146103a757600080fd5b80633c5569b6116101875780635a6c8fe0116101565780635a6c8fe0146103145780636617744b146103275780636fda09931461033a578063715018a61461034d57600080fd5b80633c5569b6146102c6578063485cc955146102d95780635523fa95146102ee57806356a0fd451461030157600080fd5b8063150b7a02116101c3578063150b7a02146102495780631f29d2dc1461027557806327f9bd13146102a057806339ef62ff146102b357600080fd5b806298deb6146101e8578062bf5b001461021557806301ec432314610228575b600080fd5b6101fb6101f636600461457b565b6104bb565b604080519283526020830191909152015b60405180910390f35b6101fb610223366004614642565b610a7b565b61023b610236366004614698565b610dee565b60405190815260200161020c565b61025c6102573660046146d1565b610e27565b6040516001600160e01b0319909116815260200161020c565b61028861028336600461476f565b610ec1565b6040516001600160a01b03909116815260200161020c565b6101fb6102ae366004614642565b610f39565b61023b6102c136600461479b565b611170565b61023b6102d4366004614820565b6111ab565b6102ec6102e7366004614698565b61141e565b005b6102ec6102fc366004614865565b6116d0565b61028861030f36600461476f565b6118c2565b6102ec6103223660046148d3565b611930565b6102ec610335366004614865565b611abd565b6102ec6103483660046148f0565b611c8d565b6102ec611cc0565b61023b610363366004614698565b611cd4565b61037b610376366004614698565b611e79565b6040805182518152602092830151928101929092520161020c565b6033546001600160a01b0316610288565b6103ba6103b536600461491e565b611f2d565b60405161020c9190614972565b6102ec6103d536600461491e565b612217565b6102ec6103e8366004614a05565b6126a4565b6103ba6103fb36600461491e565b612aa2565b61023b61040e366004614a6c565b612bcf565b6102ec610421366004614acd565b612f9a565b61023b610434366004614820565b61325b565b6102ec610447366004614acd565b6133a6565b6102ec61045a366004614b52565b6135ce565b6102ec61046d3660046148d3565b6139b6565b6102ec6104803660046148d3565b6139e0565b61037b610493366004614698565b613a59565b6104ab6104a636600461479b565b613b0d565b604051901515815260200161020c565b33600090815260a16020526040812054819060ff166104f55760405162461bcd60e51b81526004016104ec90614bbd565b60405180910390fd5b6104fd613b3e565b609f5460408051808201909152600080825260208201526001600160a01b039091169060408051608081018252600080825260208201819052918101829052606081019190915260005b898110156106ac578a8a8281811061056157610561614bf4565b9050608002018036038101906105779190614cec565b609d54815191935061059b916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156105e157506105cc609785846020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6105fd5760405162461bcd60e51b81526004016104ec90614d4d565b6020820151609b54610626916001600160a01b0390911690869063ffffffff90811690613bc316565b925081606001516106445781604001516001600160b81b0316610647565b82515b6106519087614da6565b955081606001511561069a576020808301516001600160a01b0386166000908152609a83526040808220338352909352919091206106989163ffffffff90811690613c5716565b505b806106a481614db9565b915050610547565b5060005b87811015610815578888828181106106ca576106ca614bf4565b9050608002018036038101906106e09190614cec565b609e548151919350610704916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b031614801561074a5750610735609785846020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6107665760405162461bcd60e51b81526004016104ec90614d4d565b6020820151609b5461078f916001600160a01b0390911690869063ffffffff90811690613bc316565b925081606001516107ad5781604001516001600160b81b03166107b0565b82515b6107ba9087614da6565b9550816060015115610803576020808301516001600160a01b0386166000908152609a83526040808220338352909352919091206108019163ffffffff90811690613c5716565b505b8061080d81614db9565b9150506106b0565b50609c546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561085e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108829190614dd2565b609b546040516326fb224960e01b81529195506001600160a01b0316906326fb2249906108b9908d908d908d908d90600401614e74565b600060405180830381600087803b1580156108d357600080fd5b505af11580156108e7573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81523060048201528893508792506001600160a01b03909116906370a0823190602401602060405180830381865afa158015610937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095b9190614dd2565b6109659190614ea6565b61096f9190614ea6565b93508315610984576109846097843387613c63565b6109916097843388613cbb565b609c546001600160a01b031663a9059cbb876109ad8789614da6565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156109f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1c9190614eb9565b50336001600160a01b03167fe5dd4a33d6e8891ae6b9b9ca8854301bee1e9b6f282415cf77603ba58f2d35028b8b8b8b604051610a5c9493929190614e74565b60405180910390a2505050610a716001606555565b9550959350505050565b33600090815260a16020526040812054819060ff16610aac5760405162461bcd60e51b81526004016104ec90614bbd565b610ab4613b3e565b609e546001600160a01b0316610ada604080518082019091526000808252602082015290565b604080518082019091526000808252602082015260005b87811015610c0e57888882818110610b0b57610b0b614bf4565b905060400201803603810190610b219190614eed565b9250610b39609785856000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b031614610b695760405162461bcd60e51b81526004016104ec90614d4d565b6020830151610b81906001600160e01b031687614da6565b8351609b54919750610ba8916001600160a01b031690869063ffffffff90811690613bc316565b915082602001516001600160e01b0316826000015103610bfc5782516001600160a01b0385166000908152609a602090815260408083203384529091529020610bfa9163ffffffff90811690613c5716565b505b80610c0681614db9565b915050610af1565b50609c546040516370a0823160e01b81526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa158015610c59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7d9190614dd2565b609b54604051637691e48360e11b81529195506001600160a01b03169063ed23c90690610cb2908b908b908b90600401614f7e565b600060405180830381600087803b158015610ccc57600080fd5b505af1158015610ce0573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b038a81166004830152899450889350909116906370a0823190602401602060405180830381865afa158015610d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d569190614dd2565b610d609190614ea6565b610d6a9190614ea6565b93508315610d7f57610d7f6097843387613c63565b610d8c6097843388613cbb565b336001600160a01b0316836001600160a01b03167f2a7470cabdc5637d04a07737768a7a78fad4c821d0de0ea8b8544dfe12427c398a8a604051610dd1929190614faa565b60405180910390a3505050610de66001606555565b935093915050565b6001600160a01b038083166000908152609a602090815260408083209385168352929052908120610e1e90613d46565b90505b92915050565b609d546000906001600160a01b0316331480610e4d5750609e546001600160a01b031633145b80610e625750609f546001600160a01b031633145b610eae5760405162461bcd60e51b815260206004820152601860248201527f4e66745661756c743a2063616c6c6572206e6f7420617065000000000000000060448201526064016104ec565b50630a85bd0160e11b5b95945050505050565b609d5460009083906001600160a01b0380831691161480610eef5750609e546001600160a01b038281169116145b80610f075750609f546001600160a01b038281169116145b610f235760405162461bcd60e51b81526004016104ec90614fbe565b610f2f60978585613d50565b91505b5092915050565b33600090815260a16020526040812054819060ff16610f6a5760405162461bcd60e51b81526004016104ec90614bbd565b610f72613b3e565b609d546001600160a01b0316610f98604080518082019091526000808252602082015290565b604080518082019091526000808252602082015260005b878110156110cc57888882818110610fc957610fc9614bf4565b905060400201803603810190610fdf9190614eed565b9250610ff7609785856000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146110275760405162461bcd60e51b81526004016104ec90614d4d565b602083015161103f906001600160e01b031687614da6565b8351609b54919750611066916001600160a01b031690869063ffffffff90811690613bc316565b915082602001516001600160e01b03168260000151036110ba5782516001600160a01b0385166000908152609a6020908152604080832033845290915290206110b89163ffffffff90811690613c5716565b505b806110c481614db9565b915050610faf565b50609c546040516370a0823160e01b81526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190614dd2565b609b5460405163aceb362960e01b81529195506001600160a01b03169063aceb362990610cb2908b908b908b90600401614f7e565b6001600160a01b038084166000908152609a6020908152604080832093861683529290529081206111a19083613d79565b90505b9392505050565b33600090815260a1602052604081205460ff166111da5760405162461bcd60e51b81526004016104ec90614bbd565b6111e2613b3e565b609d546001600160a01b031660005b8481101561125f5761121d60978388888581811061121157611211614bf4565b90506020020135613b97565b6001600160a01b0316336001600160a01b03161461124d5760405162461bcd60e51b81526004016104ec90614d4d565b8061125781614db9565b9150506111f1565b50609c546040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190614dd2565b609b5460405163b682e85960e01b81529193506001600160a01b03169063b682e859906113039088908890889060040161501b565b600060405180830381600087803b15801561131d57600080fd5b505af1158015611331573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b03878116600483015286945090911691506370a0823190602401602060405180830381865afa158015611381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a59190614dd2565b6113af9190614ea6565b915081156113c4576113c46097823385613c63565b336001600160a01b0316816001600160a01b03167fad95cc123bbb3335e10eb45354da192c0db46c8383bcc925c1f9dd9848b6001e87878660405161140b9392919061502f565b60405180910390a3506111a46001606555565b600054610100900460ff161580801561143e5750600054600160ff909116105b806114585750303b158015611458575060005460ff166001145b6114bb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104ec565b6000805460ff1916600117905580156114de576000805461ff0019166101001790555b6114e6613d85565b6114ee613db4565b609b80546001600160a01b038086166001600160a01b0319928316811790935560a08054918616919092161790556040805163563d6cdd60e11b8152905163ac7ad9ba916004818101926020929091908290030181865afa158015611557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157b919061505e565b609c80546001600160a01b0319166001600160a01b03928316179055609b546115a49116613de3565b609d80546001600160a01b0319166001600160a01b03928316179055609b546115cd9116613e50565b609e80546001600160a01b0319166001600160a01b03928316179055609b546115f69116613e80565b609f80546001600160a01b0319166001600160a01b03928316179055609c54609b5460405163095ea7b360e01b81529083166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015611660573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116849190614eb9565b5080156116cb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b33600090815260a1602052604090205460ff166116ff5760405162461bcd60e51b81526004016104ec90614bbd565b609d5484906001600160a01b038083169116148061172a5750609e546001600160a01b038281169116145b806117425750609f546001600160a01b038281169116145b61175e5760405162461bcd60e51b81526004016104ec90614fbe565b6001600160a01b0386166117b45760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c69642064656c656761746500000000000060448201526064016104ec565b6000805b848110156118b8578585828181106117d2576117d2614bf4565b9050602002013591506117e760978884613d50565b6001600160a01b0316336001600160a01b0316146118175760405162461bcd60e51b81526004016104ec9061507b565b60a25460405163b18e2bbb60e01b81526001600160a01b038a811660048301528981166024830152604482018590526000606483015286151560848301529091169063b18e2bbb9060a4016020604051808303816000875af1158015611881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a59190614dd2565b50806118b081614db9565b9150506117b8565b5050505050505050565b609d5460009083906001600160a01b03808316911614806118f05750609e546001600160a01b038281169116145b806119085750609f546001600160a01b038281169116145b6119245760405162461bcd60e51b81526004016104ec90614fbe565b610f2f60978585613b97565b609d5481906001600160a01b038083169116148061195b5750609e546001600160a01b038281169116145b806119735750609f546001600160a01b038281169116145b61198f5760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166119be5760405162461bcd60e51b81526004016104ec90614bbd565b6119c6613b3e565b6001600160a01b0382166000908152609860209081526040808320338452825280832081518083019092528054808352600190910154928201839052909291611a0e91614da6565b6001600160a01b03858116600090815260986020908152604080832033808552925280832083815560010192909255609c54915163a9059cbb60e01b8152600481019190915260248101849052929350169063a9059cbb906044016020604051808303816000875af1158015611a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aac9190614eb9565b505050611ab96001606555565b5050565b33600090815260a1602052604090205460ff16611aec5760405162461bcd60e51b81526004016104ec90614bbd565b609d5484906001600160a01b0380831691161480611b175750609e546001600160a01b038281169116145b80611b2f5750609f546001600160a01b038281169116145b611b4b5760405162461bcd60e51b81526004016104ec90614fbe565b6001600160a01b038616611ba15760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c69642064656c656761746500000000000060448201526064016104ec565b6000805b848110156118b857858582818110611bbf57611bbf614bf4565b905060200201359150611bd460978884613d50565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b81526004016104ec9061507b565b60a05460405163537a5c3d60e01b81526001600160a01b038a8116600483015289811660248301526044820185905286151560648301529091169063537a5c3d90608401600060405180830381600087803b158015611c6257600080fd5b505af1158015611c76573d6000803e3d6000fd5b505050508080611c8590614db9565b915050611ba5565b611c95613eb0565b6001600160a01b0391909116600090815260a160205260409020805460ff1916911515919091179055565b611cc8613eb0565b611cd26000613f0a565b565b609d5460009083906001600160a01b0380831691161480611d025750609e546001600160a01b038281169116145b80611d1a5750609f546001600160a01b038281169116145b611d365760405162461bcd60e51b81526004016104ec90614fbe565b609b54600090611d4f906001600160a01b031686613f5c565b6001600160a01b0380871660009081526099602090815260408083209389168352928152828220835180850190945280548452600101549083015282519293509091611dbb90889065ffffffffffff16611da7613ff8565b609b546001600160a01b0316929190614030565b50606084015184519192506001600160601b031690611de590610e109065ffffffffffff16614da6565b42118015611dff575060408401516001600160601b031615155b15611e3b5760408401516001600160601b0316611e24670de0b6b3a7640000846150bc565b611e2e91906150e9565b611e389082614da6565b90505b670de0b6b3a76400008360200151828560000151611e5991906150bc565b611e6391906150fd565b611e6d91906150e9565b98975050505050505050565b6040805180820190915260008082526020820152609d5483906001600160a01b0380831691161480611eb85750609e546001600160a01b038281169116145b80611ed05750609f546001600160a01b038281169116145b611eec5760405162461bcd60e51b81526004016104ec90614fbe565b50506001600160a01b039182166000908152609960209081526040808320939094168252918252829020825180840190935280548352600101549082015290565b60a2546040516328a92f4d60e11b81523060048201526060916000916001600160a01b03909116906351525e9a90602401600060405180830381865afa158015611f7b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611fa39190810190615140565b9050826001600160401b03811115611fbd57611fbd614c0a565b604051908082528060200260200182016040528015611ff057816020015b6060815260200190600190039081611fdb5790505b5091506000805b8481101561220d5785858281811061201157612011614bf4565b905060200201359150600080600090505b84518110156120aa57886001600160a01b031685828151811061204757612047614bf4565b6020026020010151608001516001600160a01b031614801561208557508385828151811061207757612077614bf4565b602002602001015160a00151145b15612098578161209481614db9565b9250505b806120a281614db9565b915050612022565b50806001600160401b038111156120c3576120c3614c0a565b6040519080825280602002602001820160405280156120ec578160200160208202803683370190505b508583815181106120ff576120ff614bf4565b60209081029190910101526000805b85518110156121f757896001600160a01b031686828151811061213357612133614bf4565b6020026020010151608001516001600160a01b031614801561217157508486828151811061216357612163614bf4565b602002602001015160a00151145b156121e55785818151811061218857612188614bf4565b6020026020010151602001518785815181106121a6576121a6614bf4565b602002602001015183815181106121bf576121bf614bf4565b6001600160a01b0390921660209283029190910190910152816121e181614db9565b9250505b806121ef81614db9565b91505061210e565b505050808061220590614db9565b915050611ff7565b5050509392505050565b609d5483906001600160a01b03808316911614806122425750609e546001600160a01b038281169116145b8061225a5750609f546001600160a01b038281169116145b6122765760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166122a55760405162461bcd60e51b81526004016104ec90614bbd565b6122ad613b3e565b816122fa5760405162461bcd60e51b815260206004820152601a60248201527f6e66745661756c743a20696e76616c696420746f6b656e49647300000000000060448201526064016104ec565b60006123156097868686600081811061121157611211614bf4565b609d549091506001600160a01b03868116911614806123415750609e546001600160a01b038681169116145b156123b957604051632b56690d60e01b815273d058dcd7bd6db27eb2442304bc6135dda5f7012490632b56690d906123849060979089908990899060040161524d565b60006040518083038186803b15801561239c57600080fd5b505af41580156123b0573d6000803e3d6000fd5b5050505061243c565b609f546001600160a01b039081169086160361243c5760405163209401b560e11b815273d058dcd7bd6db27eb2442304bc6135dda5f7012490634128036a9061240b9060979088908890600401615282565b60006040518083038186803b15801561242357600080fd5b505af4158015612437573d6000803e3d6000fd5b505050505b60005b8381101561263b5761246b60978787878581811061245f5761245f614bf4565b90506020020135613d50565b6001600160a01b0316336001600160a01b0316146124d65760405162461bcd60e51b815260206004820152602260248201527f6e66745661756c743a2063616c6c6572206d757374206265206e6674206f776e60448201526132b960f11b60648201526084016104ec565b6124ee60978787878581811061121157611211614bf4565b6001600160a01b0316826001600160a01b03161461254e5760405162461bcd60e51b815260206004820152601d60248201527f6e66745661756c743a207374616b6572206d7573742062652073616d6500000060448201526064016104ec565b6001600160a01b03861660009081526097602052604081209086868481811061257957612579614bf4565b6020908102929092013583525081019190915260400160002080546001600160a01b031990811682556001909101805490911690556001600160a01b0386166342842e0e30338888868181106125d1576125d1614bf4565b905060200201356040518463ffffffff1660e01b81526004016125f69392919061529c565b600060405180830381600087803b15801561261057600080fd5b505af1158015612624573d6000803e3d6000fd5b50505050808061263390614db9565b91505061243f565b50806001600160a01b0316336001600160a01b0316866001600160a01b03167f1027039dd42454c88e1ee31b26b4ec90b0b5b87696e51f9dcdcb9a7ea9fdf66f878760405161268b9291906152c0565b60405180910390a45061269e6001606555565b50505050565b609d5484906001600160a01b03808316911614806126cf5750609e546001600160a01b038281169116145b806126e75750609f546001600160a01b038281169116145b6127035760405162461bcd60e51b81526004016104ec90614fbe565b33600090815260a1602052604090205460ff166127325760405162461bcd60e51b81526004016104ec90614bbd565b61273a613b3e565b60008061275a604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015260005b87811015612a355788888281811061278b5761278b614bf4565b609b546020909102929092013596506127b0916001600160a01b031690508b87613bc3565b8051909350156128025760405162461bcd60e51b815260206004820152601c60248201527f6e66745661756c743a206e667420616c7265616479207374616b65640000000060448201526064016104ec565b609d546001600160a01b038b81169116148061282b5750609e546001600160a01b038b81169116145b1561291857609b54612846906001600160a01b03168b6140c6565b609b5460405162c13e2360e61b815260048101839052602481018890529195506001600160a01b03169063304f88c0906044016040805180830381865afa158015612895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b991906152d4565b91508160200151156129185760405162461bcd60e51b815260206004820152602260248201527f6e66745661756c743a20616c72656164792070616972656420776974682062616044820152616b6360f01b60648201526084016104ec565b896001600160a01b03166342842e0e33308c8c8681811061293b5761293b614bf4565b905060200201356040518463ffffffff1660e01b81526004016129609392919061529c565b600060405180830381600087803b15801561297a57600080fd5b505af115801561298e573d6000803e3d6000fd5b50506040805180820182523381526001600160a01b038b8116602080840191909152908f166000908152609790915291822090935091508b8b858181106129d7576129d7614bf4565b6020908102929092013583525081810192909252604001600020825181546001600160a01b03199081166001600160a01b03928316178355939092015160019091018054909316911617905580612a2d81614db9565b915050612771565b50856001600160a01b0316336001600160a01b03168a6001600160a01b03167f89bdad4dcd6b4c2725002d1ed53dc73e8f882576622ade4ab6dc57550c5f541a8b8b604051612a859291906152c0565b60405180910390a450505050612a9b6001606555565b5050505050565b6060816001600160401b03811115612abc57612abc614c0a565b604051908082528060200260200182016040528015612aef57816020015b6060815260200190600190039081612ada5790505b5090506000805b83811015612bc657848482818110612b1057612b10614bf4565b60a054604051631221156b60e01b81526020909202939093013594506001600160a01b0390921691631221156b9150612b519030908a90879060040161529c565b600060405180830381865afa158015612b6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b969190810190615315565b838281518110612ba857612ba8614bf4565b60200260200101819052508080612bbe90614db9565b915050612af6565b50509392505050565b33600090815260a1602052604081205460ff16612bfe5760405162461bcd60e51b81526004016104ec90614bbd565b612c06613b3e565b609f5460408051808201909152600080825260208201526001600160a01b039091169060005b87811015612cfa57888882818110612c4657612c46614bf4565b905060400201803603810190612c5c91906153ba565b609d548151919350612c83916097916001600160a01b0316906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316148015612ccc5750612cb760978484602001516001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316145b612ce85760405162461bcd60e51b81526004016104ec90614d4d565b80612cf281614db9565b915050612c2c565b5060005b85811015612ddc57868682818110612d1857612d18614bf4565b905060400201803603810190612d2e91906153ba565b609e548151919350612d55916097916001600160a01b0316906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316148015612dae5750609f546020830151612d99916097916001600160a01b03909116906001600160801b0316613b97565b6001600160a01b0316336001600160a01b0316145b612dca5760405162461bcd60e51b81526004016104ec90614d4d565b80612dd481614db9565b915050612cfe565b50609c546040516370a0823160e01b81526001600160a01b038681166004830152909116906370a0823190602401602060405180830381865afa158015612e27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e4b9190614dd2565b609b546040516303fafd2560e11b81529194506001600160a01b0316906307f5fa4a90612e84908b908b908b908b908b9060040161543d565b600060405180830381600087803b158015612e9e57600080fd5b505af1158015612eb2573d6000803e3d6000fd5b5050609c546040516370a0823160e01b81526001600160a01b03888116600483015287945090911691506370a0823190602401602060405180830381865afa158015612f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f269190614dd2565b612f309190614ea6565b92508215612f4557612f456097833386613c63565b336001600160a01b03167f359f9a3961795346f7f440d092fb9d342afb8e02b55959716f9d730db1bb02f08989898988604051612f8695949392919061547f565b60405180910390a25050610eb86001606555565b33600090815260a1602052604090205460ff16612fc95760405162461bcd60e51b81526004016104ec90614bbd565b612fd1613b3e565b609d546001600160a01b03166000612ff9604080518082019091526000808252602082015290565b60005b848110156131175785858281811061301657613016614bf4565b90506040020180360381019061302c9190614eed565b9150613044609785846000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146130b05760405162461bcd60e51b8152602060048201526024808201527f6e66745661756c743a2063616c6c6572206d757374206265206261796320737460448201526330b5b2b960e11b60648201526084016104ec565b60208201516130c8906001600160e01b031684614da6565b82516001600160a01b0386166000908152609a602090815260408083203384529091529020919450613104919063ffffffff9081169061429a16565b508061310f81614db9565b915050612ffc565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061314c9033903090879060040161529c565b6020604051808303816000875af115801561316b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318f9190614eb9565b50609b546040516346583a0560e01b81526001600160a01b03909116906346583a05906131c29088908890600401614faa565b600060405180830381600087803b1580156131dc57600080fd5b505af11580156131f0573d6000803e3d6000fd5b5050505061320160978433856142a6565b336001600160a01b0316836001600160a01b03167f2c9b881f0a9073f196214688cd6329c4b6f020b4550467107b786e2fe7d225bc8787604051613246929190614faa565b60405180910390a3505050611ab96001606555565b33600090815260a1602052604081205460ff1661328a5760405162461bcd60e51b81526004016104ec90614bbd565b613292613b3e565b609e546001600160a01b031660005b84811015613303576132c160978388888581811061121157611211614bf4565b6001600160a01b0316336001600160a01b0316146132f15760405162461bcd60e51b81526004016104ec90614d4d565b806132fb81614db9565b9150506132a1565b50609c546040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa15801561334e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133729190614dd2565b609b546040516257a26360e81b81529193506001600160a01b0316906357a26300906113039088908890889060040161501b565b33600090815260a1602052604090205460ff166133d55760405162461bcd60e51b81526004016104ec90614bbd565b6133dd613b3e565b609e546001600160a01b03166000613405604080518082019091526000808252602082015290565b60005b848110156135235785858281811061342257613422614bf4565b9050604002018036038101906134389190614eed565b9150613450609785846000015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316146134bc5760405162461bcd60e51b8152602060048201526024808201527f6e66745661756c743a2063616c6c6572206d757374206265206d61796320737460448201526330b5b2b960e11b60648201526084016104ec565b60208201516134d4906001600160e01b031684614da6565b82516001600160a01b0386166000908152609a602090815260408083203384529091529020919450613510919063ffffffff9081169061429a16565b508061351b81614db9565b915050613408565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906135589033903090879060040161529c565b6020604051808303816000875af1158015613577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359b9190614eb9565b50609b54604051638ecbffa760e01b81526001600160a01b0390911690638ecbffa7906131c29088908890600401614faa565b33600090815260a1602052604090205460ff166135fd5760405162461bcd60e51b81526004016104ec90614bbd565b613605613b3e565b60408051606081018252600080825260208201819052918101829052609f546001600160a01b031660005b868110156137505787878281811061364a5761364a614bf4565b90506060020180360381019061366091906154b9565b609d548151919450613684916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156136ca57506136b5609783856020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b6136e65760405162461bcd60e51b81526004016104ec90614d4d565b60408301516136fe906001600160b81b031685614da6565b6020808501516001600160a01b0385166000908152609a835260408082203383529093529190912091955061373d919063ffffffff9081169061429a16565b508061374881614db9565b915050613630565b5060005b848110156138745785858281811061376e5761376e614bf4565b90506060020180360381019061378491906154b9565b609e5481519194506137a8916097916001600160a01b03169063ffffffff16613b97565b6001600160a01b0316336001600160a01b03161480156137ee57506137d9609783856020015163ffffffff16613b97565b6001600160a01b0316336001600160a01b0316145b61380a5760405162461bcd60e51b81526004016104ec90614d4d565b6040830151613822906001600160b81b031685614da6565b6020808501516001600160a01b0385166000908152609a8352604080822033835290935291909120919550613861919063ffffffff9081169061429a16565b508061386c81614db9565b915050613754565b50609c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906138a99033903090889060040161529c565b6020604051808303816000875af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614eb9565b50609b5460405163d346cbd960e01b81526001600160a01b039091169063d346cbd990613923908a908a908a908a9060040161558d565b600060405180830381600087803b15801561393d57600080fd5b505af1158015613951573d6000803e3d6000fd5b5050505061396260978233866142a6565b336001600160a01b03167f48265d3cee57f46b491ced0cebc5303c321890575e424108082d86d6b2f071c5888888886040516139a1949392919061558d565b60405180910390a250505061269e6001606555565b6139be613eb0565b60a280546001600160a01b0319166001600160a01b0392909216919091179055565b6139e8613eb0565b6001600160a01b038116613a4d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104ec565b613a5681613f0a565b50565b6040805180820190915260008082526020820152609d5483906001600160a01b0380831691161480613a985750609e546001600160a01b038281169116145b80613ab05750609f546001600160a01b038281169116145b613acc5760405162461bcd60e51b81526004016104ec90614fbe565b50506001600160a01b039182166000908152609860209081526040808320939094168252918252829020825180840190935280548352600101549082015290565b6001600160a01b038084166000908152609a6020908152604080832093861683529290529081206111a19083614317565b600260655403613b905760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104ec565b6002606555565b6001600160a01b0391821660009081526020938452604080822092825291909352909120600101541690565b6040805180820190915260008082526020820152836001600160a01b03166398ada4a2613bf086866140c6565b846040518363ffffffff1660e01b8152600401613c17929190918252602082015260400190565b6040805180830381865afa158015613c33573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a191906155b4565b6000610e1e838361432f565b6001600160a01b0380841660009081526002860160209081526040808320938616835292905220613c9c670de0b6b3a7640000836150bc565b816001016000828254613caf91906155e6565b90915550505050505050565b6001600160a01b03808416600090815260028601602090815260408083209386168352929052908120805490918391839190613cf8908490614ea6565b90915550506004850154613d15906001600160a01b031685613f5c565b60600151613d2c906001600160601b0316836150bc565b816001016000828254613caf91906150fd565b6001606555565b6000610e21825490565b6001600160a01b0391821660009081526020938452604080822092825291909352909120541690565b6000610e1e8383614422565b600054610100900460ff16613dac5760405162461bcd60e51b81526004016104ec9061560e565b611cd261444c565b600054610100900460ff16613ddb5760405162461bcd60e51b81526004016104ec9061560e565b611cd261447c565b6040516305da6c1560e11b8152600160048201526000906001600160a01b03831690630bb4d82a906024015b602060405180830381865afa158015613e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e21919061505e565b6040516305da6c1560e11b8152600260048201526000906001600160a01b03831690630bb4d82a90602401613e0f565b6040516305da6c1560e11b8152600360048201526000906001600160a01b03831690630bb4d82a90602401613e0f565b6033546001600160a01b03163314611cd25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104ec565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080516080810182526000808252602082018190529181018290526060810191909152826001600160a01b031663ac4afa38613f9985856140c6565b6040518263ffffffff1660e01b8152600401613fb791815260200190565b608060405180830381865afa158015613fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1e9190615670565b6000614003426144a3565b61400c426144b0565b61401790603c6150bc565b6140219190614da6565b61402b9042614ea6565b905090565b600080856001600160a01b031663d7464ee961404c88886140c6565b6040516001600160e01b031960e084901b168152600481019190915260248101879052604481018690526064016040805180830381865afa158015614095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b991906156d9565b9150915094509492505050565b6040516305da6c1560e11b8152600160048201526000906001600160a01b03841690630bb4d82a90602401602060405180830381865afa15801561410e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614132919061505e565b6001600160a01b0316826001600160a01b03160361415257506001610e21565b6040516305da6c1560e11b8152600260048201526001600160a01b03841690630bb4d82a90602401602060405180830381865afa158015614197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141bb919061505e565b6001600160a01b0316826001600160a01b0316036141db57506002610e21565b6040516305da6c1560e11b8152600360048201526001600160a01b03841690630bb4d82a90602401602060405180830381865afa158015614220573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614244919061505e565b6001600160a01b0316826001600160a01b03160361426457506003610e21565b60405162461bcd60e51b815260206004820152600b60248201526a1a5b9d985b1a59081b999d60aa1b60448201526064016104ec565b6000610e1e83836144cc565b6001600160a01b038084166000908152600286016020908152604080832093861683529290529081208054909183918391906142e3908490614da6565b90915550506004850154614300906001600160a01b031685613f5c565b60600151613c9c906001600160601b0316836150bc565b60008181526001830160205260408120541515610e1e565b60008181526001830160205260408120548015614418576000614353600183614ea6565b855490915060009061436790600190614ea6565b90508181146143cc57600086600001828154811061438757614387614bf4565b90600052602060002001549050808760000184815481106143aa576143aa614bf4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806143dd576143dd6156fd565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610e21565b6000915050610e21565b600082600001828154811061443957614439614bf4565b9060005260206000200154905092915050565b600054610100900460ff166144735760405162461bcd60e51b81526004016104ec9061560e565b611cd233613f0a565b600054610100900460ff16613d3f5760405162461bcd60e51b81526004016104ec9061560e565b6000610e21603c83615713565b6000806144bf610e1084615713565b90506111a4603c826150e9565b600081815260018301602052604081205461451357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610e21565b506000610e21565b60008083601f84011261452d57600080fd5b5081356001600160401b0381111561454457600080fd5b6020830191508360208260071b850101111561455f57600080fd5b9250929050565b6001600160a01b0381168114613a5657600080fd5b60008060008060006060868803121561459357600080fd5b85356001600160401b03808211156145aa57600080fd5b6145b689838a0161451b565b909750955060208801359150808211156145cf57600080fd5b506145dc8882890161451b565b90945092505060408601356145f081614566565b809150509295509295909350565b60008083601f84011261461057600080fd5b5081356001600160401b0381111561462757600080fd5b6020830191508360208260061b850101111561455f57600080fd5b60008060006040848603121561465757600080fd5b83356001600160401b0381111561466d57600080fd5b614679868287016145fe565b909450925050602084013561468d81614566565b809150509250925092565b600080604083850312156146ab57600080fd5b82356146b681614566565b915060208301356146c681614566565b809150509250929050565b6000806000806000608086880312156146e957600080fd5b85356146f481614566565b9450602086013561470481614566565b93506040860135925060608601356001600160401b038082111561472757600080fd5b818801915088601f83011261473b57600080fd5b81358181111561474a57600080fd5b89602082850101111561475c57600080fd5b9699959850939650602001949392505050565b6000806040838503121561478257600080fd5b823561478d81614566565b946020939093013593505050565b6000806000606084860312156147b057600080fd5b83356147bb81614566565b925060208401356147cb81614566565b929592945050506040919091013590565b60008083601f8401126147ee57600080fd5b5081356001600160401b0381111561480557600080fd5b6020830191508360208260051b850101111561455f57600080fd5b60008060006040848603121561483557600080fd5b83356001600160401b0381111561484b57600080fd5b614679868287016147dc565b8015158114613a5657600080fd5b60008060008060006080868803121561487d57600080fd5b853561488881614566565b9450602086013561489881614566565b935060408601356001600160401b038111156148b357600080fd5b6148bf888289016147dc565b90945092505060608601356145f081614857565b6000602082840312156148e557600080fd5b81356111a481614566565b6000806040838503121561490357600080fd5b823561490e81614566565b915060208301356146c681614857565b60008060006040848603121561493357600080fd5b833561493e81614566565b925060208401356001600160401b0381111561495957600080fd5b614965868287016147dc565b9497909650939450505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156149f757888603603f19018552825180518088529088019088880190845b818110156149e15783516001600160a01b03168352928a0192918a01916001016149bc565b509097505050938601939186019160010161499a565b509398975050505050505050565b60008060008060608587031215614a1b57600080fd5b8435614a2681614566565b935060208501356001600160401b03811115614a4157600080fd5b614a4d878288016147dc565b9094509250506040850135614a6181614566565b939692955090935050565b600080600080600060608688031215614a8457600080fd5b85356001600160401b0380821115614a9b57600080fd5b614aa789838a016145fe565b90975095506020880135915080821115614ac057600080fd5b506145dc888289016145fe565b60008060208385031215614ae057600080fd5b82356001600160401b03811115614af657600080fd5b614b02858286016145fe565b90969095509350505050565b60008083601f840112614b2057600080fd5b5081356001600160401b03811115614b3757600080fd5b60208301915083602060608302850101111561455f57600080fd5b60008060008060408587031215614b6857600080fd5b84356001600160401b0380821115614b7f57600080fd5b614b8b88838901614b0e565b90965094506020870135915080821115614ba457600080fd5b50614bb187828801614b0e565b95989497509550505050565b6020808252601f908201527f53744e66743a2063616c6c6572206973206e6f7420617574686f72697a656400604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715614c4257614c42614c0a565b60405290565b604080519081016001600160401b0381118282101715614c4257614c42614c0a565b60405160e081016001600160401b0381118282101715614c4257614c42614c0a565b604051601f8201601f191681016001600160401b0381118282101715614cb457614cb4614c0a565b604052919050565b803563ffffffff81168114614cd057600080fd5b919050565b80356001600160b81b0381168114614cd057600080fd5b600060808284031215614cfe57600080fd5b614d06614c20565b614d0f83614cbc565b8152614d1d60208401614cbc565b6020820152614d2e60408401614cd5565b60408201526060830135614d4181614857565b60608201529392505050565b60208082526023908201527f6e66745661756c743a2063616c6c6572206d757374206265206e66742073746160408201526235b2b960e91b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e2157610e21614d90565b600060018201614dcb57614dcb614d90565b5060010190565b600060208284031215614de457600080fd5b5051919050565b8183526000602080850194508260005b85811015614e695763ffffffff80614e1284614cbc565b16885280614e21858501614cbc565b16888501525060406001600160b81b03614e3c848301614cd5565b1690880152606082810135614e5081614857565b1515908801526080968701969190910190600101614dfb565b509495945050505050565b604081526000614e88604083018688614deb565b8281036020840152614e9b818587614deb565b979650505050505050565b81810381811115610e2157610e21614d90565b600060208284031215614ecb57600080fd5b81516111a481614857565b80356001600160e01b0381168114614cd057600080fd5b600060408284031215614eff57600080fd5b614f07614c48565b614f1083614cbc565b8152614f1e60208401614ed6565b60208201529392505050565b8183526000602080850194508260005b85811015614e695763ffffffff614f5083614cbc565b1687526001600160e01b03614f66838501614ed6565b16878401526040968701969190910190600101614f3a565b604081526000614f92604083018587614f2a565b905060018060a01b0383166020830152949350505050565b6020815260006111a1602083018486614f2a565b6020808252601190820152704e66745661756c743a206e6f742061706560781b604082015260600190565b81835260006001600160fb1b0383111561500257600080fd5b8260051b80836020870137939093016020019392505050565b604081526000614f92604083018587614fe9565b604081526000615043604083018587614fe9565b9050826020830152949350505050565b8051614cd081614566565b60006020828403121561507057600080fd5b81516111a481614566565b60208082526021908201527f6e66745661756c743a206f6e6c79206f776e65722063616e2064656c656761746040820152606560f81b606082015260800190565b8082028115828204841417610e2157610e21614d90565b634e487b7160e01b600052601260045260246000fd5b6000826150f8576150f86150d3565b500490565b8181036000831280158383131683831282161715610f3257610f32614d90565b60006001600160401b0382111561513657615136614c0a565b5060051b60200190565b6000602080838503121561515357600080fd5b82516001600160401b0381111561516957600080fd5b8301601f8101851361517a57600080fd5b805161518d6151888261511d565b614c8c565b81815260e091820283018401918482019190888411156151ac57600080fd5b938501935b838510156152415780858a0312156151c95760008081fd5b6151d1614c6a565b8551600681106151e15760008081fd5b81526151ee868801615053565b8782015260406151ff818801615053565b9082015260608681015190820152608061521a818801615053565b9082015260a0868101519082015260c08087015190820152835293840193918501916151b1565b50979650505050505050565b8481526001600160a01b03841660208201526060604082018190526000906152789083018486614fe9565b9695505050505050565b838152604060208201526000610eb8604083018486614fe9565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020815260006111a1602083018486614fe9565b6000604082840312156152e657600080fd5b6152ee614c48565b82516001600160f81b038116811461530557600080fd5b81526020830151614f1e81614857565b6000602080838503121561532857600080fd5b82516001600160401b0381111561533e57600080fd5b8301601f8101851361534f57600080fd5b805161535d6151888261511d565b81815260059190911b8201830190838101908783111561537c57600080fd5b928401925b82841015614e9b57835161539481614566565b82529284019290840190615381565b80356001600160801b0381168114614cd057600080fd5b6000604082840312156153cc57600080fd5b6153d4614c48565b6153dd836153a3565b8152614f1e602084016153a3565b8183526000602080850194508260005b85811015614e69576001600160801b0380615415846153a3565b168852806154248585016153a3565b16888501525060409687019691909101906001016153fb565b6060815260006154516060830187896153eb565b82810360208401526154648186886153eb565b91505060018060a01b03831660408301529695505050505050565b6060815260006154936060830187896153eb565b82810360208401526154a68186886153eb565b9150508260408301529695505050505050565b6000606082840312156154cb57600080fd5b604051606081018181106001600160401b03821117156154ed576154ed614c0a565b6040526154f983614cbc565b815261550760208401614cbc565b602082015261551860408401614cd5565b60408201529392505050565b8183526000602080850194508260005b85811015614e695763ffffffff8061554b84614cbc565b1688528061555a858501614cbc565b16888501525060406001600160b81b03615575848301614cd5565b16908801526060968701969190910190600101615534565b6040815260006155a1604083018688615524565b8281036020840152614e9b818587615524565b6000604082840312156155c657600080fd5b6155ce614c48565b82518152602083015160208201528091505092915050565b808201828112600083128015821682158216171561560657615606614d90565b505092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b80516001600160601b0381168114614cd057600080fd5b60006080828403121561568257600080fd5b61568a614c20565b825165ffffffffffff811681146156a057600080fd5b8152602083015161ffff811681146156b757600080fd5b60208201526156c860408401615659565b6040820152614d4160608401615659565b600080604083850312156156ec57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fd5b600082615722576157226150d3565b50069056fea26469706673582212200e6349938cf432519f33e28838ed53aaa97d7fad048caf8aea20bb7de0cd180364736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.