Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 48 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Charge Sunse... | 18982221 | 391 days ago | IN | 0 ETH | 0.00062789 | ||||
Toggle Emissions | 18982210 | 391 days ago | IN | 0 ETH | 0.00112976 | ||||
Withdraw Tokens | 18982180 | 391 days ago | IN | 0 ETH | 0.00136528 | ||||
Emergency Withdr... | 18982180 | 391 days ago | IN | 0 ETH | 0.07850729 | ||||
Emergency Withdr... | 18982161 | 391 days ago | IN | 0 ETH | 0.07644858 | ||||
Deposit | 18982135 | 391 days ago | IN | 0 ETH | 0.00797208 | ||||
Deposit | 18982051 | 391 days ago | IN | 0 ETH | 0.04521117 | ||||
Deposit | 18981384 | 391 days ago | IN | 0 ETH | 0.00397343 | ||||
Deposit | 18981383 | 391 days ago | IN | 0 ETH | 0.00707797 | ||||
Deposit | 18981373 | 391 days ago | IN | 0 ETH | 0.01267656 | ||||
Deposit | 18981219 | 391 days ago | IN | 0 ETH | 0.06783554 | ||||
Deposit | 18981139 | 391 days ago | IN | 0 ETH | 0.01179311 | ||||
Deposit | 18980928 | 391 days ago | IN | 0 ETH | 0.0137174 | ||||
Deposit | 18980838 | 391 days ago | IN | 0 ETH | 0.04037301 | ||||
Deposit | 18980823 | 391 days ago | IN | 0 ETH | 0.02932699 | ||||
Deposit | 18980457 | 391 days ago | IN | 0 ETH | 0.01061281 | ||||
Deposit | 18979945 | 391 days ago | IN | 0 ETH | 0.01043064 | ||||
Deposit | 18979844 | 391 days ago | IN | 0 ETH | 0.01267856 | ||||
Deposit | 18979514 | 391 days ago | IN | 0 ETH | 0.01248103 | ||||
Deposit | 18979502 | 391 days ago | IN | 0 ETH | 0.01357954 | ||||
Deposit | 18979404 | 391 days ago | IN | 0 ETH | 0.02349904 | ||||
Deposit | 18978963 | 391 days ago | IN | 0 ETH | 0.05799461 | ||||
Deposit | 18978938 | 391 days ago | IN | 0 ETH | 0.01114703 | ||||
Deposit | 18978923 | 391 days ago | IN | 0 ETH | 0.01745776 | ||||
Deposit | 18978902 | 391 days ago | IN | 0 ETH | 0.0097106 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
StreetsOfMiladyCharging
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./ChargedERC721APosition.sol"; // _____ __ __ // / ___// /_________ ___ / /______ // \__ \/ __/ ___/ _ \/ _ \/ __/ ___/ // ___/ / /_/ / / __/ __/ /_(__ ) // /____/\__/_/_ \___/\___/\__/____/ // ____ / __/ // / __ \/ /_ // / /_/ / __/ // \____/_/____ __ __ // / |/ (_) /___ _____/ /_ __ // / /|_/ / / / __ `/ __ / / / / // / / / / / / /_/ / /_/ / /_/ / // /_/ /_/_/_/\__,_/\__,_/\__, / // /____/ // // OFFICIAL SANKO GAMES NFT CHARGING CONTRACT contract StreetsOfMiladyCharging is ChargedERC721APosition { constructor( IERC721A _erc721Address, IERC20 _erc20Address, uint256[] memory _rates, bytes32[] memory _merkleRoots ) ChargedERC721APosition(_erc721Address, _erc20Address, _rates, _merkleRoots) {} function contractURI() public pure returns (string memory) { string memory json = unicode'{"name": "Charged Streets of Milady","description":"Sanko official ©️"}'; return string.concat("data:application/json;utf8,", json); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@chiru/interfaces/IERC721A.sol"; import "@openzeppelin/access/Ownable.sol"; import "./interfaces/IChargedSankoNFT.sol"; import "@openzeppelin/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/token/ERC20/IERC20.sol"; import "@openzeppelin/security/ReentrancyGuard.sol"; import "@openzeppelin/utils/cryptography/MerkleProof.sol"; import "@solady/utils/LibString.sol"; struct WithdrawRequest { uint16[] tokenIndexes; uint256 unlockTimestamp; } struct ChargedPosition { uint256 claimedAt; uint256 combinedEmissionRate; uint16[] tokenIds; } abstract contract ChargedERC721APosition is Ownable, IERC721Receiver, IChargedSankoNFT, ReentrancyGuard { event ClaimedRewards( address indexed person, uint16[] tokenIds, uint256 amount, uint256 claimedAt ); event FailedToClaimRewards( address indexed person, uint16[] tokenIds, uint256 amount, uint256 claimedAt ); event Deposit(address indexed person, uint16[] tokenIds); event WithdrawRequested(address indexed person, uint16[] tokenIndexes); event Withdraw(address indexed person, uint16[] tokenIndexes); event WithdrawalCancelled(address indexed user, uint16[] tokenIndexes); /// @notice Contract addresses IERC721A public erc721Address; IERC20 public erc20Address; /// @notice Consts uint256 public LOCKING_PERIOD = 14 days; uint256 public UNBONDING_PERCENTAGE = 5e17; uint256 private BASIS_DIVISOR = 1e18; uint256 private emission_curve = 1e18; /// @notice Track the deposit and claim state of tokens mapping(address => ChargedPosition) public charged; mapping(address => WithdrawRequest) public withdraws; mapping(uint256 => bytes32) private merkleRoots; mapping(uint256 => uint256) public rewardRate; mapping(uint256 => uint256) public rarity; /// @notice Date at which point rewards will no longer accrue uint256 public chargeSunset; /// @notice contract deploys paused so that rewards and merkle roots can be set bool public pauseTokenEmissions = false; /// @notice Token not owned error TokenNotOwned(uint256 tokenId); /// @notice Token non-existent error TokenNonExistent(uint256 tokenId); /// @notice Tokens are experiencing the unbonding duration. error UnbondingInProgress(address user); /// @notice Tokens are bonded and must request withdraw. error TokensBonded(address user); /// @notice Using a non-zero value error NonZeroValue(); constructor( IERC721A _erc721Address, IERC20 _erc20Address, uint256[] memory _rates, bytes32[] memory _merkleRoots ) { erc721Address = _erc721Address; erc20Address = _erc20Address; chargeSunset = block.timestamp + 365 days; require( _rates.length == _merkleRoots.length, "merkle roots and rates length mismatch" ); for (uint256 i = 0; i < _rates.length; i++) { rewardRate[i] = _rates[i]; } for (uint256 i = 0; i < _merkleRoots.length; i++) { merkleRoots[i] = _merkleRoots[i]; } } /** * @notice Track deposits of an account * @dev returns the rarity of the token * @return rarityIndex */ function tokenRarity(uint16 id) external view returns (uint256 rarityIndex) { return rarity[id]; } function setRarity(uint256 _tokenId, uint256 _rarity) external onlyOwner { rarity[_tokenId] = _rarity; } function setLockingPeriod(uint256 _lockingPeriod) public onlyOwner { LOCKING_PERIOD = _lockingPeriod; } function setBatchRarity(uint16[] calldata _tokenIds, uint256 _rarity) external onlyOwner { for (uint256 i = 0; i < _tokenIds.length; i++) { uint256 tokenId = _tokenIds[i]; rarity[tokenId] = _rarity; } } /** * @notice Calculates the rewards for specific tokens under an address * @param account - account to check * @return rewards */ function calculateRewards(address account) external view returns (uint256 rewards) { return _calculateRewards(account); } function _calculateRewards(address user) private view returns (uint256) { if (charged[user].combinedEmissionRate == 0) { return 0; } if (charged[user].claimedAt > block.timestamp) { return 0; } if (emission_curve != BASIS_DIVISOR) { return ( (charged[user].combinedEmissionRate) * emission_curve * ( ( block.timestamp < chargeSunset ? block.timestamp : chargeSunset ) - charged[user].claimedAt ) ) / BASIS_DIVISOR; } else { return ( (charged[user].combinedEmissionRate) * ( ( block.timestamp < chargeSunset ? block.timestamp : chargeSunset ) - charged[user].claimedAt ) ); } } function saveCombinedEmissionRate() internal { charged[msg.sender].combinedEmissionRate = calculateCombinedEmissionRate(msg.sender); } function calculateCombinedEmissionRate(address user) public view returns (uint256 rate) { uint256 combinedRewardRate = 0; uint256 combinedRewardRateReduction = 0; uint16[] memory tokenIds = charged[user].tokenIds; for (uint256 i = 0; i < tokenIds.length; i++) { combinedRewardRate += _findRate(tokenIds[i]); } uint256 unlock = withdraws[user].unlockTimestamp; if (unlock != 0) { for (uint256 i = 0; i < withdraws[user].tokenIndexes.length; i++) { combinedRewardRateReduction += _findRate(tokenIds[withdraws[user].tokenIndexes[i]]); } combinedRewardRateReduction = ( combinedRewardRateReduction * UNBONDING_PERCENTAGE ) / BASIS_DIVISOR; if (combinedRewardRate < combinedRewardRateReduction) { return 0; } return combinedRewardRate - combinedRewardRateReduction; } else { return combinedRewardRate; } } /** * @param tokenId - The id where you want to find the rate * @return rate - The rate */ function findRate(uint16 tokenId) external view returns (uint256 rate) { return _findRate(tokenId); } function _findRate(uint16 tokenId) private view returns (uint256 rate) { if (tokenId == 0) { return 0; } uint256 rarityIndex = this.tokenRarity(tokenId); return (rewardRate[rarityIndex]) / (365 days); } function charges(address user) external view returns (ChargedPosition memory) { return charged[user]; } function withdrawInfo(address user) external view returns (WithdrawRequest memory) { return withdraws[user]; } /** * @notice Claim the rewards for the tokens */ function claimRewards() external { _claimRewards(); } function _claimRewards() private nonReentrant { require(pauseTokenEmissions == false); if (charged[msg.sender].claimedAt == block.timestamp) { return; } uint256 reward = _calculateRewards(msg.sender); charged[msg.sender].claimedAt = block.timestamp; if (reward > 0) { if (_safeTransferRewards(msg.sender, reward)) { emit ClaimedRewards( msg.sender, charged[msg.sender].tokenIds, reward, block.timestamp ); } else { emit FailedToClaimRewards( msg.sender, charged[msg.sender].tokenIds, reward, block.timestamp ); revert("failed to claim rewards"); } } } /** * @notice Deposit tokens into the contract * @param tokenIds - Array of token ids to charge */ function deposit( uint16[] calldata tokenIds, uint8[] calldata rarities, bytes32[][] calldata proofs ) external { _claimRewards(); require(tokenIds.length == rarities.length, "arguments length mismatch"); require(tokenIds.length == proofs.length, "arguments length mismatch"); if (charged[msg.sender].tokenIds.length == 0) { charged[msg.sender].tokenIds = tokenIds; for (uint256 i; i < tokenIds.length; i++) { if (erc721Address.ownerOf(tokenIds[i]) != msg.sender) { revert TokenNotOwned(tokenIds[i]); } // prove that the token is of the provided rarity bytes32 leaf = keccak256( bytes.concat( keccak256(abi.encode(tokenIds[i], rarities[i])) ) ); require( MerkleProof.verify( proofs[i], merkleRoots[rarities[i]], leaf ), "InvalidMerkleProof" ); if (rarity[tokenIds[i]] != 0) { rarity[tokenIds[i]] = rarities[i]; } erc721Address.safeTransferFrom( msg.sender, address(this), tokenIds[i], "" ); } } else { for (uint256 i; i < tokenIds.length; i++) { if (erc721Address.ownerOf(tokenIds[i]) != msg.sender) { revert TokenNotOwned(tokenIds[i]); } // prove that the token is of the provided rarity bytes32 leaf = keccak256( bytes.concat( keccak256(abi.encode(tokenIds[i], rarities[i])) ) ); require( MerkleProof.verify( proofs[i], merkleRoots[rarities[i]], leaf ), "InvalidMerkleProof" ); if (rarity[tokenIds[i]] != 0) { rarity[tokenIds[i]] = rarities[i]; } charged[msg.sender].tokenIds.push(tokenIds[i]); erc721Address.safeTransferFrom( msg.sender, address(this), tokenIds[i], "" ); } } saveCombinedEmissionRate(); emit Deposit(msg.sender, tokenIds); } /** * @notice Withdraw tokens from the contract */ function withdraw() external { require(withdraws[msg.sender].tokenIndexes.length > 0); _claimRewards(); uint256 unlock = withdraws[msg.sender].unlockTimestamp; if (unlock >= block.timestamp) { revert UnbondingInProgress(msg.sender); } uint16[] storage tokenIndexes = withdraws[msg.sender].tokenIndexes; for (uint256 i; i < tokenIndexes.length; i++) { uint256 tokenIndex = tokenIndexes[i]; uint256 tokenId = charged[msg.sender].tokenIds[tokenIndex]; delete charged[msg.sender].tokenIds[tokenIndexes[i]]; erc721Address.safeTransferFrom( address(this), msg.sender, tokenId, "" ); } delete withdraws[msg.sender].unlockTimestamp; saveCombinedEmissionRate(); emit Withdraw(msg.sender, tokenIndexes); } /** * @notice Withdraw all tokens from the contract */ function withdrawAll() public { require(withdraws[msg.sender].tokenIndexes.length > 0); _claimRewards(); uint256 unlock = withdraws[msg.sender].unlockTimestamp; uint16[] storage tokenIds = charged[msg.sender].tokenIds; if (unlock >= block.timestamp) { revert UnbondingInProgress(msg.sender); } for (uint256 i = 0; i < tokenIds.length; i++) { uint16 tokenId = tokenIds[i]; if (tokenId != 0) { erc721Address.safeTransferFrom( address(this), msg.sender, tokenId, "" ); } } delete charged[msg.sender]; delete withdraws[msg.sender]; saveCombinedEmissionRate(); } /** * @notice admin to eject tokens from the contract just in case something happens and NFTs are stuck! no rewards are claimed. */ function emergencyWithdraw(address charger) external onlyOwner { uint16[] memory tokenIds = charged[charger].tokenIds; for (uint256 i; i < tokenIds.length; i++) { uint256 tokenId = tokenIds[i]; if (tokenId != 0) { erc721Address.safeTransferFrom( address(this), charger, tokenId, "" ); } } charged[charger].combinedEmissionRate = calculateCombinedEmissionRate(charger); emit Withdraw(charger, tokenIds); } /** * @notice admin to eject tokens from the contract just in case something happens and NFTs are stuck! no rewards are claimed. */ function emergencyWithdraw(uint16[] memory tokenIds) external onlyOwner { for (uint256 i = 0; i < tokenIds.length; i++) { uint256 tokenId = tokenIds[i]; if (tokenId != 0) { erc721Address.safeTransferFrom( address(this), msg.sender, tokenId, "" ); } } emit Withdraw(msg.sender, tokenIds); } /** * @notice Modify rewards (in case of stolen nfts or other reasons) */ function emergencyRecalculateRewards(address user, uint256 rewards) external onlyOwner { charged[user].combinedEmissionRate = rewards; } /** * @notice Withdraw tokens from the contract */ function requestWithdraw(uint16[] memory tokenIndexes) external { _claimRewards(); require( tokenIndexes.length <= charged[msg.sender].tokenIds.length, "requesting more tokens than owned" ); require(tokenIndexes.length > 0, "requesting zero tokens"); if (withdraws[msg.sender].unlockTimestamp != 0) { revert UnbondingInProgress(msg.sender); } uint16[] memory chargedTokens = charged[msg.sender].tokenIds; for (uint256 i = 0; i < tokenIndexes.length; i++) { require( chargedTokens[tokenIndexes[i]] != 0, "requesting zero token withdraw" ); } withdraws[msg.sender].tokenIndexes = tokenIndexes; withdraws[msg.sender].unlockTimestamp = block.timestamp + LOCKING_PERIOD; saveCombinedEmissionRate(); emit WithdrawRequested(msg.sender, tokenIndexes); } /** * @notice Cancel the withdrawal request for specified tokens */ function cancelWithdrawal() external { // Reset the unlock timestamp _claimRewards(); delete withdraws[msg.sender]; saveCombinedEmissionRate(); emit WithdrawalCancelled(msg.sender, charged[msg.sender].tokenIds); } /** * @notice Withdraw tokens from the charging contract * @param amount - Amount in wei to withdraw */ function withdrawTokens(uint256 amount) external onlyOwner { _safeTransferRewards(msg.sender, amount); } /** * @dev Issues tokens only if there is a sufficient balance in the contract * @param recipient - receiving address * @param amount - amount in wei to transfer */ function _safeTransferRewards(address recipient, uint256 amount) private returns (bool) { uint256 balance = erc20Address.balanceOf(address(this)); if (amount <= balance) { erc20Address.transfer(recipient, amount); return true; } else { return false; } } /** * @dev Modify the ERC20 token being emitted * @param _newErc20Address - address of token to emit */ function setErc20Address(IERC20 _newErc20Address) external onlyOwner { erc20Address = _newErc20Address; } /** * @dev Modify the ERC721 contract address * @param _newErc721Address - new erc721 address */ function setERC721Address(IERC721A _newErc721Address) external onlyOwner { erc721Address = _newErc721Address; } /** * @dev Update the rates * @param index - the index of the new rate * @param rate - the new rate */ function updateRewardRate(uint256 index, uint256 rate) external onlyOwner { rewardRate[index] = rate; } /** * @dev Update the rates * @param _rates - the new rate */ function setRewardRate(uint256[] memory _rates) external onlyOwner { for (uint256 i = 0; i < _rates.length; i++) { rewardRate[i] = _rates[i]; } } function setMerkleRoots(bytes32[] memory _merkleRoots) external onlyOwner { for (uint256 i = 0; i < _merkleRoots.length; i++) { merkleRoots[i] = _merkleRoots[i]; } } /** * @dev Toggle pausing the emissions */ function toggleEmissions() external onlyOwner { pauseTokenEmissions = !pauseTokenEmissions; } function getTotalChargedTokens(address user) public view returns (uint256 totalCharged) { uint256 total = 0; for (uint256 i = 0; i < charged[user].tokenIds.length; i++) { if (charged[user].tokenIds[i] != 0) { total++; } } return total; } // This function may return zeroes along with charged tokens function tokensOfOwner(address user) public view returns (uint16[] memory tokenIds) { return charged[user].tokenIds; } /** * @dev Receive ERC721 tokens */ function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) { return IERC721Receiver.onERC721Received.selector; } function setTokenAddress(address _tokenAddress) external override onlyOwner { erc20Address = IERC20(_tokenAddress); } function setEmissionCurve(uint256 _emissionCurve) public onlyOwner { emission_curve = _emissionCurve; } function setChargeSunset(uint256 _chargeSunset) public onlyOwner { chargeSunset = _chargeSunset; } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721A.sol';
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.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 Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IChargedSankoNFT { function setTokenAddress(address _tokenAddress) external; function tokensOfOwner(address account) external view returns (uint16[] memory); function findRate(uint16 tokenId) external view returns (uint256 rate); function calculateRewards(address account) external view returns (uint256 rewards); function claimRewards() external; function deposit( uint16[] calldata tokenIds, uint8[] calldata rarities, bytes32[][] calldata proofs ) external; function withdraw() external; function requestWithdraw(uint16[] calldata tokenIndexes) external; function tokenRarity(uint16 tokenId) external view returns (uint256 rarity); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(uint256(-value)); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`. For short strings up to 32 bytes. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let x := and(b, add(not(b), 1)) let r := or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x))))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behaviour is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behaviour is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of ERC721A. */ interface IERC721A { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables * (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, * checking first that contract recipients are aware of the ERC721 protocol * to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move * this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external payable; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Transfers `tokenId` from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} * whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external payable; /** * @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 payable; /** * @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); // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); // ============================================================= // IERC2309 // ============================================================= /** * @dev Emitted when tokens in `fromTokenId` to `toTokenId` * (inclusive) is transferred from `from` to `to`, as defined in the * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. * * See {_mintERC2309} for more details. */ event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "@solmate/=lib/solmate/src/", "@chiru/=lib/ERC721A/contracts/", "@solady/=lib/solady/src/", "@trig/=lib/solidity-trigonometry/src/", "@camelot/=lib/periphery/contracts/", "@camelot-core/=lib/core/contracts/", "@manifoldxyz/libraries-solidity/=lib/caviar/lib/royalty-registry-solidity/lib/libraries-solidity/", "@openzeppelin/contracts-upgradeable/=lib/caviar/lib/royalty-registry-solidity/lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/caviar/lib/royalty-registry-solidity/lib/openzeppelin-contracts/contracts/", "ERC721A/=lib/ERC721A/contracts/", "caviar/=lib/caviar/", "core/=lib/core/contracts/", "create2-helpers/=lib/caviar/lib/royalty-registry-solidity/lib/create2-helpers/", "create2-scripts/=lib/caviar/lib/royalty-registry-solidity/lib/create2-helpers/script/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "libraries-solidity/=lib/caviar/lib/royalty-registry-solidity/lib/libraries-solidity/contracts/", "openzeppelin-contracts-upgradeable/=lib/caviar/lib/royalty-registry-solidity/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "oracle/=lib/caviar/lib/oracle/contracts/", "periphery/=lib/periphery/contracts/", "prb-math/=lib/solidity-trigonometry/lib/prb-math/contracts/", "reservoir-oracle/=lib/caviar/lib/oracle/contracts/", "royalty-registry-solidity/=lib/caviar/lib/royalty-registry-solidity/", "solady/=lib/solady/", "solidity-trigonometry/=lib/solidity-trigonometry/src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC721A","name":"_erc721Address","type":"address"},{"internalType":"contract IERC20","name":"_erc20Address","type":"address"},{"internalType":"uint256[]","name":"_rates","type":"uint256[]"},{"internalType":"bytes32[]","name":"_merkleRoots","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NonZeroValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenNonExistent","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenNotOwned","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"TokensBonded","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"UnbondingInProgress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"person","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimedAt","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"person","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"person","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimedAt","type":"uint256"}],"name":"FailedToClaimRewards","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":"person","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIndexes","type":"uint16[]"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"person","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIndexes","type":"uint16[]"}],"name":"WithdrawRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint16[]","name":"tokenIndexes","type":"uint16[]"}],"name":"WithdrawalCancelled","type":"event"},{"inputs":[],"name":"LOCKING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNBONDING_PERCENTAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"calculateCombinedEmissionRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calculateRewards","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chargeSunset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"charged","outputs":[{"internalType":"uint256","name":"claimedAt","type":"uint256"},{"internalType":"uint256","name":"combinedEmissionRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"charges","outputs":[{"components":[{"internalType":"uint256","name":"claimedAt","type":"uint256"},{"internalType":"uint256","name":"combinedEmissionRate","type":"uint256"},{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"internalType":"struct ChargedPosition","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"},{"internalType":"uint8[]","name":"rarities","type":"uint8[]"},{"internalType":"bytes32[][]","name":"proofs","type":"bytes32[][]"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"emergencyRecalculateRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"charger","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"erc20Address","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721Address","outputs":[{"internalType":"contract IERC721A","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"}],"name":"findRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getTotalChargedTokens","outputs":[{"internalType":"uint256","name":"totalCharged","type":"uint256"}],"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":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseTokenEmissions","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rarity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIndexes","type":"uint16[]"}],"name":"requestWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_tokenIds","type":"uint16[]"},{"internalType":"uint256","name":"_rarity","type":"uint256"}],"name":"setBatchRarity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chargeSunset","type":"uint256"}],"name":"setChargeSunset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC721A","name":"_newErc721Address","type":"address"}],"name":"setERC721Address","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_emissionCurve","type":"uint256"}],"name":"setEmissionCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_newErc20Address","type":"address"}],"name":"setErc20Address","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockingPeriod","type":"uint256"}],"name":"setLockingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_merkleRoots","type":"bytes32[]"}],"name":"setMerkleRoots","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_rarity","type":"uint256"}],"name":"setRarity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_rates","type":"uint256[]"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"setTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleEmissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"id","type":"uint16"}],"name":"tokenRarity","outputs":[{"internalType":"uint256","name":"rarityIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"updateRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"withdrawInfo","outputs":[{"components":[{"internalType":"uint16[]","name":"tokenIndexes","type":"uint16[]"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"}],"internalType":"struct WithdrawRequest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdraws","outputs":[{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052621275006004556706f05b59d3b20000600555670de0b6b3a76400006006819055600755600e805460ff191690553480156200003f57600080fd5b50604051620036f6380380620036f683398101604081905262000062916200030a565b838383836200007133620001bb565b60018055600280546001600160a01b038087166001600160a01b0319928316179092556003805492861692909116919091179055620000b5426301e13380620003fd565b600d5580518251146200011d5760405162461bcd60e51b815260206004820152602660248201527f6d65726b6c6520726f6f747320616e64207261746573206c656e677468206d696044820152650e6dac2e8c6d60d31b606482015260840160405180910390fd5b60005b825181101562000164578281815181106200013f576200013f62000425565b6020908102919091018101516000838152600b90925260409091205560010162000120565b5060005b8151811015620001ac5781818151811062000187576200018762000425565b6020908102919091018101516000838152600a90925260409091205560010162000168565b5050505050505050506200043b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200022157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562000265576200026562000224565b604052919050565b60006001600160401b0382111562000289576200028962000224565b5060051b60200190565b600082601f830112620002a557600080fd5b81516020620002be620002b8836200026d565b6200023a565b8083825260208201915060208460051b870101935086841115620002e157600080fd5b602086015b84811015620002ff5780518352918301918301620002e6565b509695505050505050565b600080600080608085870312156200032157600080fd5b84516200032e816200020b565b8094505060208086015162000343816200020b565b60408701519094506001600160401b03808211156200036157600080fd5b818801915088601f8301126200037657600080fd5b815162000387620002b8826200026d565b81815260059190911b8301840190848101908b831115620003a757600080fd5b938501935b82851015620003c757845182529385019390850190620003ac565b60608b01519097509450505080831115620003e157600080fd5b5050620003f18782880162000293565b91505092959194509250565b808201808211156200041f57634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052603260045260246000fd5b6132ab806200044b6000396000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c806364ab86751161015c578063bc07aa64116100ce578063e2fb6e3111610087578063e2fb6e31146105c1578063e8a3d485146105e1578063e984d794146105f6578063ee0dd5d614610609578063f2fde38b1461061c578063fcd1af011461062f57600080fd5b8063bc07aa6414610542578063bd28cc1714610555578063c0f05d8014610568578063c27a20d21461057b578063c88b863c1461058e578063cea01962146105a157600080fd5b80638b58c569116101205780638b58c569146104cf5780638da5cb5b146104ef5780639a03d9a314610500578063a56dade214610513578063b2a2b72214610526578063b32534cf1461052f57600080fd5b806364ab8675146104795780636ff1c9bc1461048c578063715018a61461049f5780638462151c146104a7578063853828b6146104c757600080fd5b8063372500ab116101f55780634d9f92c2116101b95780634d9f92c2146103c3578063518051c4146103ff57806351e5b6721461042357806352c84fe7146104365780635773d778146104495780636186938a1461046657600080fd5b8063372500ab146103875780633c76f6bd1461038f5780633ccfd60b1461039857806348179ee5146103a05780634a39fa801461033b57600080fd5b8063226112801161024757806322611280146103085780632352a8641461031057806326a4e8d21461033b57806326b321d11461034e578063276184ae14610361578063315a095d1461037457600080fd5b806307b25bba146102845780630ea230de146102a0578063150b7a02146102b357806319a249a8146102eb5780631db2b99d146102f5575b600080fd5b61028d60055481565b6040519081526020015b60405180910390f35b61028d6102ae366004612702565b61064f565b6102d26102c136600461271f565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610297565b6102f36106e8565b005b6102f361030336600461283b565b610704565b6102f36107f7565b600254610323906001600160a01b031681565b6040516001600160a01b039091168152602001610297565b6102f3610349366004612702565b610879565b6102f361035c3660046128d8565b6108a3565b600354610323906001600160a01b031681565b6102f36103823660046128d8565b6108b0565b6102f36108c6565b61028d600d5481565b6102f36108d0565b61028d6103ae366004612702565b60096020526000908152604090206001015481565b6103ea6103d1366004612702565b6008602052600090815260409020805460019091015482565b60408051928352602083019190915201610297565b61028d61040d3660046128f1565b61ffff166000908152600c602052604090205490565b6102f361043136600461290c565b610b1f565b6102f3610444366004612984565b610b46565b600e546104569060ff1681565b6040519015158152602001610297565b61028d6104743660046128f1565b6113ab565b61028d610487366004612702565b6113bc565b6102f361049a366004612702565b6113c7565b6102f3611561565b6104ba6104b5366004612702565b611573565b6040516102979190612a1e565b6102f361160a565b61028d6104dd3660046128d8565b600c6020526000908152604090205481565b6000546001600160a01b0316610323565b6102f361050e366004612702565b61177e565b61028d610521366004612702565b6117a8565b61028d60045481565b6102f361053d366004612a66565b611992565b6102f3610550366004612a88565b6119ac565b6102f361056336600461283b565b6119f6565b6102f36105763660046128d8565b611c92565b6102f3610589366004612b0e565b611c9f565b6102f361059c3660046128d8565b611cff565b61028d6105af3660046128d8565b600b6020526000908152604090205481565b6105d46105cf366004612702565b611d0c565b6040516102979190612b9a565b6105e9611dc5565b6040516102979190612bf0565b6102f3610604366004612a66565b611e0a565b6102f3610617366004612a88565b611e24565b6102f361062a366004612702565b611e6e565b61064261063d366004612702565b611ee7565b6040516102979190612c23565b600080805b6001600160a01b0384166000908152600860205260409020600201548110156106e1576001600160a01b03841660009081526008602052604090206002018054829081106106a4576106a4612c5a565b60009182526020909120601082040154600f9091166002026101000a900461ffff16156106d957816106d581612c86565b9250505b600101610654565b5092915050565b6106f0611fbf565b600e805460ff19811660ff90911615179055565b61070c611fbf565b60005b81518110156107b257600082828151811061072c5761072c612c5a565b602002602001015161ffff169050806000146107a957600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde9061077690309033908690600401612c9f565b600060405180830381600087803b15801561079057600080fd5b505af11580156107a4573d6000803e3d6000fd5b505050505b5060010161070f565b50336001600160a01b03167ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e20826040516107ec9190612a1e565b60405180910390a250565b6107ff612019565b33600090815260096020526040812090610819828261259d565b6001820160009055505061082b612173565b336000818152600860205260409081902090517ffb0fa2c910642b32b54a3cb67e087132deb00fe0e5d488e7ce5f43b4991f70899161086f9160029091019061300d565b60405180910390a2565b610881611fbf565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6108ab611fbf565b600455565b6108b8611fbf565b6108c23382612191565b5050565b6108ce612019565b565b336000908152600960205260409020546108e957600080fd5b6108f1612019565b3360009081526009602052604090206001015442811061092b57604051632fac778f60e21b81523360048201526024015b60405180910390fd5b336000908152600960205260408120905b8154811015610abe57600082828154811061095957610959612c5a565b6000918252602080832060108304015433845260089091526040832060029081018054600f9094169091026101000a90910461ffff16935090839081106109a2576109a2612c5a565b6000918252602080832060108304015433845260089091526040909220865461ffff6002600f90941684026101000a90940493909316935001908590859081106109ee576109ee612c5a565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1681548110610a2657610a26612c5a565b600091825260209091206010820401805461ffff6002600f90941684026101000a021916905554604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde90610a7e90309033908690600401612c9f565b600060405180830381600087803b158015610a9857600080fd5b505af1158015610aac573d6000803e3d6000fd5b50506001909401935061093c92505050565b5033600090815260096020526040812060010155610ada612173565b336001600160a01b03167ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e2082604051610b13919061300d565b60405180910390a25050565b610b27611fbf565b6001600160a01b03909116600090815260086020526040902060010155565b610b4e612019565b848314610b995760405162461bcd60e51b81526020600482015260196024820152780c2e4ceeadacadce8e640d8cadccee8d040dad2e6dac2e8c6d603b1b6044820152606401610922565b848114610be45760405162461bcd60e51b81526020600482015260196024820152780c2e4ceeadacadce8e640d8cadccee8d040dad2e6dac2e8c6d603b1b6044820152606401610922565b336000908152600860205260408120600201549003610fe157336000908152600860205260409020610c1a9060020187876125c2565b5060005b85811015610fdb5760025433906001600160a01b0316636352211e898985818110610c4b57610c4b612c5a565b9050602002016020810190610c6091906128f1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190613020565b6001600160a01b031614610d1857868682818110610ce357610ce3612c5a565b9050602002016020810190610cf891906128f1565b604051635b50a3cf60e11b815261ffff9091166004820152602401610922565b6000878783818110610d2c57610d2c612c5a565b9050602002016020810190610d4191906128f1565b868684818110610d5357610d53612c5a565b9050602002016020810190610d68919061303d565b6040805161ffff909316602084015260ff9091169082015260600160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610e53848484818110610dcd57610dcd612c5a565b9050602002810190610ddf9190613060565b808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250600a935091508a90508987818110610e2657610e26612c5a565b9050602002016020810190610e3b919061303d565b60ff1681526020019081526020016000205483612297565b610e945760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b226b2b935b632a83937b7b360711b6044820152606401610922565b600c6000898985818110610eaa57610eaa612c5a565b9050602002016020810190610ebf91906128f1565b61ffff16815260200190815260200160002054600014610f4457858583818110610eeb57610eeb612c5a565b9050602002016020810190610f00919061303d565b60ff16600c60008a8a86818110610f1957610f19612c5a565b9050602002016020810190610f2e91906128f1565b61ffff1681526020810191909152604001600020555b6002546001600160a01b031663b88d4fde33308b8b87818110610f6957610f69612c5a565b9050602002016020810190610f7e91906128f1565b6040518463ffffffff1660e01b8152600401610f9c939291906130aa565b600060405180830381600087803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b505060019093019250610c1e915050565b50611358565b60005b858110156113565760025433906001600160a01b0316636352211e89898581811061101157611011612c5a565b905060200201602081019061102691906128f1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015611065573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110899190613020565b6001600160a01b0316146110a957868682818110610ce357610ce3612c5a565b60008787838181106110bd576110bd612c5a565b90506020020160208101906110d291906128f1565b8686848181106110e4576110e4612c5a565b90506020020160208101906110f9919061303d565b6040805161ffff909316602084015260ff9091169082015260600160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120905061115e848484818110610dcd57610dcd612c5a565b61119f5760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b226b2b935b632a83937b7b360711b6044820152606401610922565b600c60008989858181106111b5576111b5612c5a565b90506020020160208101906111ca91906128f1565b61ffff1681526020019081526020016000205460001461124f578585838181106111f6576111f6612c5a565b905060200201602081019061120b919061303d565b60ff16600c60008a8a8681811061122457611224612c5a565b905060200201602081019061123991906128f1565b61ffff1681526020810191909152604001600020555b33600090815260086020526040902060020188888481811061127357611273612c5a565b905060200201602081019061128891906128f1565b8154600181018355600092835260209092206010830401805461ffff9283166002600f90951685026101000a90810293021916919091179055546001600160a01b031663b88d4fde33308b8b878181106112e4576112e4612c5a565b90506020020160208101906112f991906128f1565b6040518463ffffffff1660e01b8152600401611317939291906130aa565b600060405180830381600087803b15801561133157600080fd5b505af1158015611345573d6000803e3d6000fd5b505060019093019250610fe4915050565b505b611360612173565b336001600160a01b03167f29ac78bc3dcd88143fb4d2986027c15f05c86c7adec8521f8df902c854c0f5c1878760405161139b9291906130e0565b60405180910390a2505050505050565b60006113b6826122ad565b92915050565b60006113b682612351565b6113cf611fbf565b6001600160a01b03811660009081526008602090815260408083206002018054825181850281018501909352808352919290919083018282801561145a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114215790505b5050505050905060005b815181101561150757600082828151811061148157611481612c5a565b602002602001015161ffff169050806000146114fe57600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde906114cb90309088908690600401612c9f565b600060405180830381600087803b1580156114e557600080fd5b505af11580156114f9573d6000803e3d6000fd5b505050505b50600101611464565b50611511826117a8565b6001600160a01b038316600081815260086020526040908190206001019290925590517ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e2090610b13908490612a1e565b611569611fbf565b6108ce6000612485565b6001600160a01b0381166000908152600860209081526040918290206002018054835181840281018401909452808452606093928301828280156115fe57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116115c55790505b50505050509050919050565b3360009081526009602052604090205461162357600080fd5b61162b612019565b33600090815260096020908152604080832060010154600890925290912060020142821061166e57604051632fac778f60e21b8152336004820152602401610922565b60005b815481101561172857600082828154811061168e5761168e612c5a565b60009182526020909120601082040154600f9091166002026101000a900461ffff169050801561171f57600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde906116ec903090339086906004016130aa565b600060405180830381600087803b15801561170657600080fd5b505af115801561171a573d6000803e3d6000fd5b505050505b50600101611671565b503360009081526008602052604081208181556001810182905590611750600283018261259d565b50503360009081526009602052604081209061176c828261259d565b600182016000905550506108c2612173565b611786611fbf565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116600090815260086020908152604080832060020180548251818502810185019093528083528493849384939092909183018282801561183857602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116117ff5790505b5050505050905060005b81518110156118815761186d82828151811061186057611860612c5a565b60200260200101516122ad565b6118779085613127565b9350600101611842565b506001600160a01b03851660009081526009602052604090206001015480156119885760005b6001600160a01b038716600090815260096020526040902054811015611943576001600160a01b0387166000908152600960205260409020805461192f918591849081106118f7576118f7612c5a565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff168151811061186057611860612c5a565b6119399085613127565b93506001016118a7565b50600654600554611954908561313a565b61195e9190613151565b9250828410156119745750600095945050505050565b61197e8385613173565b9695505050505050565b5091949350505050565b61199a611fbf565b6000918252600b602052604090912055565b6119b4611fbf565b60005b81518110156108c2578181815181106119d2576119d2612c5a565b6020908102919091018101516000838152600a9092526040909120556001016119b7565b6119fe612019565b3360009081526008602052604090206002015481511115611a6b5760405162461bcd60e51b815260206004820152602160248201527f72657175657374696e67206d6f726520746f6b656e73207468616e206f776e656044820152601960fa1b6064820152608401610922565b6000815111611ab55760405162461bcd60e51b815260206004820152601660248201527572657175657374696e67207a65726f20746f6b656e7360501b6044820152606401610922565b3360009081526009602052604090206001015415611ae857604051632fac778f60e21b8152336004820152602401610922565b33600090815260086020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611b315790505b5050505050905060005b8251811015611c0f5781838281518110611b9057611b90612c5a565b602002602001015161ffff1681518110611bac57611bac612c5a565b602002602001015161ffff16600003611c075760405162461bcd60e51b815260206004820152601e60248201527f72657175657374696e67207a65726f20746f6b656e20776974686472617700006044820152606401610922565b600101611b74565b503360009081526009602090815260409091208351611c309285019061266f565b50600454611c3e9042613127565b33600090815260096020526040902060010155611c59612173565b336001600160a01b03167f83edb46098d7facbf9ea0441339f25f8bba07cf211f4047cd2d8bef7747452e983604051610b139190612a1e565b611c9a611fbf565b600755565b611ca7611fbf565b60005b82811015611cf9576000848483818110611cc657611cc6612c5a565b9050602002016020810190611cdb91906128f1565b61ffff166000908152600c6020526040902083905550600101611caa565b50505050565b611d07611fbf565b600d55565b6040805180820182526060808252600060208084018290526001600160a01b0386168252600981529084902084518154928302810184018652948501828152939493909284928491840182828015611dab57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611d725790505b505050505081526020016001820154815250509050919050565b606060006040518060800160405280604a815260200161322c604a9139905080604051602001611df59190613186565b60405160208183030381529060405291505090565b611e12611fbf565b6000918252600c602052604090912055565b611e2c611fbf565b60005b81518110156108c257818181518110611e4a57611e4a612c5a565b6020908102919091018101516000838152600b909252604090912055600101611e2f565b611e76611fbf565b6001600160a01b038116611edb5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610922565b611ee481612485565b50565b611f0b60405180606001604052806000815260200160008152602001606081525090565b6001600160a01b03821660009081526008602090815260409182902082516060810184528154815260018201548184015260028201805485518186028101860187528181529295939493860193830182828015611faf57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611f765790505b5050505050815250509050919050565b6000546001600160a01b031633146108ce5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610922565b6120216124d5565b600e5460ff161561203157600080fd5b33600090815260086020526040902054421461216a57600061205233612351565b33600090815260086020526040902042905590508015612168576120763382612191565b156120d057336000818152600860205260409081902090517fa713cedec5f3f717911608ee42ed2c7a49db9b06305a7f817990cce586575acd916120c391600290910190859042906131cb565b60405180910390a2612168565b336000818152600860205260409081902090517fbc42de6c6966c6186e5cc495ff9dbd3510cfb473c3bb08480c93d6dd493d79009161211891600290910190859042906131cb565b60405180910390a260405162461bcd60e51b815260206004820152601760248201527f6661696c656420746f20636c61696d20726577617264730000000000000000006044820152606401610922565b505b6108ce60018055565b61217c336117a8565b33600090815260086020526040902060010155565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156121de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220291906131f0565b905080831161228d5760035460405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690529091169063a9059cbb906044016020604051808303816000875af115801561225e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122829190613209565b5060019150506113b6565b5060009392505050565b6000826122a4858461252e565b14949350505050565b60008161ffff166000036122c357506000919050565b604051631460147160e21b815261ffff83166004820152600090309063518051c490602401602060405180830381865afa158015612305573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232991906131f0565b6000818152600b602052604090205490915061234a906301e1338090613151565b9392505050565b6001600160a01b038116600090815260086020526040812060010154810361237b57506000919050565b6001600160a01b0382166000908152600860205260409020544210156123a357506000919050565b60065460075414612424576006546001600160a01b038316600090815260086020526040902054600d5442106123db57600d546123dd565b425b6123e79190613173565b6007546001600160a01b038516600090815260086020526040902060010154612410919061313a565b61241a919061313a565b6113b69190613151565b6001600160a01b038216600090815260086020526040902054600d54421061244e57600d54612450565b425b61245a9190613173565b6001600160a01b0383166000908152600860205260409020600101546113b6919061313a565b919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6002600154036125275760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610922565b6002600155565b600081815b84518110156125695761255f8286838151811061255257612552612c5a565b6020026020010151612571565b9150600101612533565b509392505050565b600081831061258d57600082815260208490526040902061234a565b5060009182526020526040902090565b50805460008255600f016010900490600052602060002090810190611ee491906126d8565b82805482825590600052602060002090600f0160109004810192821561265f5791602002820160005b8382111561262f57833561ffff1683826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026125eb565b801561265d5782816101000a81549061ffff021916905560020160208160010104928301926001030261262f565b505b5061266b9291506126d8565b5090565b82805482825590600052602060002090600f0160109004810192821561265f5791602002820160005b8382111561262f57835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302612698565b5b8082111561266b57600081556001016126d9565b6001600160a01b0381168114611ee457600080fd5b60006020828403121561271457600080fd5b813561234a816126ed565b60008060008060006080868803121561273757600080fd5b8535612742816126ed565b94506020860135612752816126ed565b935060408601359250606086013567ffffffffffffffff8082111561277657600080fd5b818801915088601f83011261278a57600080fd5b81358181111561279957600080fd5b8960208285010111156127ab57600080fd5b9699959850939650602001949392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156127fd576127fd6127be565b604052919050565b600067ffffffffffffffff82111561281f5761281f6127be565b5060051b60200190565b803561ffff8116811461248057600080fd5b6000602080838503121561284e57600080fd5b823567ffffffffffffffff81111561286557600080fd5b8301601f8101851361287657600080fd5b803561288961288482612805565b6127d4565b81815260059190911b820183019083810190878311156128a857600080fd5b928401925b828410156128cd576128be84612829565b825292840192908401906128ad565b979650505050505050565b6000602082840312156128ea57600080fd5b5035919050565b60006020828403121561290357600080fd5b61234a82612829565b6000806040838503121561291f57600080fd5b823561292a816126ed565b946020939093013593505050565b60008083601f84011261294a57600080fd5b50813567ffffffffffffffff81111561296257600080fd5b6020830191508360208260051b850101111561297d57600080fd5b9250929050565b6000806000806000806060878903121561299d57600080fd5b863567ffffffffffffffff808211156129b557600080fd5b6129c18a838b01612938565b909850965060208901359150808211156129da57600080fd5b6129e68a838b01612938565b909650945060408901359150808211156129ff57600080fd5b50612a0c89828a01612938565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015612a5a57835161ffff1683529284019291840191600101612a3a565b50909695505050505050565b60008060408385031215612a7957600080fd5b50508035926020909101359150565b60006020808385031215612a9b57600080fd5b823567ffffffffffffffff811115612ab257600080fd5b8301601f81018513612ac357600080fd5b8035612ad161288482612805565b81815260059190911b82018301908381019087831115612af057600080fd5b928401925b828410156128cd57833582529284019290840190612af5565b600080600060408486031215612b2357600080fd5b833567ffffffffffffffff811115612b3a57600080fd5b612b4686828701612938565b909790965060209590950135949350505050565b60008151808452602080850194506020840160005b83811015612b8f57815161ffff1687529582019590820190600101612b6f565b509495945050505050565b602081526000825160406020840152612bb66060840182612b5a565b9050602084015160408401528091505092915050565b60005b83811015612be7578181015183820152602001612bcf565b50506000910152565b6020815260008251806020840152612c0f816040850160208701612bcc565b601f01601f19169190910160400192915050565b60208152815160208201526020820151604082015260006040830151606080840152612c526080840182612b5a565b949350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c9857612c98612c70565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260806060820181905260009082015260a00190565b805480835260008281526020808220940193909190825b82600f82011015612e3a57815461ffff80821688526020612d14818a01838560101c1661ffff169052565b6040612d29818b018486851c1661ffff169052565b60609150612d41828b01848660301c1661ffff169052565b6080612d56818c018587851c1661ffff169052565b60a09150612d6e828c01858760501c1661ffff169052565b60c0612d83818d018688871c1661ffff169052565b60e09350612d9b848d01868860701c1661ffff169052565b61ffff86831c8616166101008d0152612dc06101208d01868860901c1661ffff169052565b61ffff86841c8616166101408d0152612de56101608d01868860b01c1661ffff169052565b61ffff86821c8616166101808d0152505050612e0d6101a08a01838560d01c1661ffff169052565b82901c1661ffff166101c088015260f01c6101e08701526102009095019460019190910190601001612ce9565b90549082811015612e565761ffff821686526020909501946001015b82811015612e735761ffff601083901c1686526020909501946001015b82811015612e9157602082901c61ffff168652602095909501946001015b82811015612eae5761ffff603083901c1686526020909501946001015b82811015612ecb5761ffff604083901c1686526020909501946001015b82811015612ee85761ffff605083901c1686526020909501946001015b82811015612f055761ffff606083901c1686526020909501946001015b82811015612f225761ffff607083901c1686526020909501946001015b82811015612f3f5761ffff608083901c1686526020909501946001015b82811015612f5c5761ffff609083901c1686526020909501946001015b82811015612f795761ffff60a083901c1686526020909501946001015b82811015612f965761ffff60b083901c1686526020909501946001015b82811015612fb35761ffff60c083901c1686526020909501946001015b82811015612fd05761ffff60d083901c1686526020909501946001015b82811015612fed5761ffff60e083901c1686526020909501946001015b828110156130035760f082901c86526020860195505b5093949350505050565b60208152600061234a6020830184612cd2565b60006020828403121561303257600080fd5b815161234a816126ed565b60006020828403121561304f57600080fd5b813560ff8116811461234a57600080fd5b6000808335601e1984360301811261307757600080fd5b83018035915067ffffffffffffffff82111561309257600080fd5b6020019150600581901b360382131561297d57600080fd5b6001600160a01b03938416815291909216602082015261ffff909116604082015260806060820181905260009082015260a00190565b60208082528181018390526000908460408401835b8681101561311c5761ffff61310984612829565b16825291830191908301906001016130f5565b509695505050505050565b808201808211156113b6576113b6612c70565b80820281158282048414176113b6576113b6612c70565b60008261316e57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156113b6576113b6612c70565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c00000000008152600082516131be81601b850160208701612bcc565b91909101601b0192915050565b6060815260006131de6060830186612cd2565b60208301949094525060400152919050565b60006020828403121561320257600080fd5b5051919050565b60006020828403121561321b57600080fd5b8151801515811461234a57600080fdfe7b226e616d65223a2022436861726765642053747265657473206f66204d696c616479222c226465736372697074696f6e223a2253616e6b6f206f6666696369616c20c2a9efb88f227da26469706673582212206409f47b69cfa37fd489ca452ac99822c049979066688c4ac3807cd9f61130b364736f6c6343000817003300000000000000000000000094fe1d5de3a4208c7411ae21968e044abc17be480000000000000000000000008bc31478f95fc8e4c7fe578fb86bad1fe851e41a0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000053444835ec5800000000000000000000000000000000000000000000000000006124fee993bc00000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000007ce66c50e28400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000006ef34f212cd5e693b4dbbfde41052af11114d5394d29139e215d7d2b9cb6aaf8b6efa21b761fc506c645e3c491b825182b903d6736cdcdf1853242a4393fb6dbee7b48cf96d253c35584ec7ce54d74e567200fc6bfed30b9c83d9e8ed97693b32bdcc67b4e1f0be07f13b9a05c3a011ed9a3dc13cae26e96df32a655886f36c6dc51cead9ede86762b57b84f48aff81f6d6d73d5a067fae9de3503d77e6cf885d54945aff102474d66957d680dbf7d33924d9c0f45df62585910d4de7823aad1e
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061027f5760003560e01c806364ab86751161015c578063bc07aa64116100ce578063e2fb6e3111610087578063e2fb6e31146105c1578063e8a3d485146105e1578063e984d794146105f6578063ee0dd5d614610609578063f2fde38b1461061c578063fcd1af011461062f57600080fd5b8063bc07aa6414610542578063bd28cc1714610555578063c0f05d8014610568578063c27a20d21461057b578063c88b863c1461058e578063cea01962146105a157600080fd5b80638b58c569116101205780638b58c569146104cf5780638da5cb5b146104ef5780639a03d9a314610500578063a56dade214610513578063b2a2b72214610526578063b32534cf1461052f57600080fd5b806364ab8675146104795780636ff1c9bc1461048c578063715018a61461049f5780638462151c146104a7578063853828b6146104c757600080fd5b8063372500ab116101f55780634d9f92c2116101b95780634d9f92c2146103c3578063518051c4146103ff57806351e5b6721461042357806352c84fe7146104365780635773d778146104495780636186938a1461046657600080fd5b8063372500ab146103875780633c76f6bd1461038f5780633ccfd60b1461039857806348179ee5146103a05780634a39fa801461033b57600080fd5b8063226112801161024757806322611280146103085780632352a8641461031057806326a4e8d21461033b57806326b321d11461034e578063276184ae14610361578063315a095d1461037457600080fd5b806307b25bba146102845780630ea230de146102a0578063150b7a02146102b357806319a249a8146102eb5780631db2b99d146102f5575b600080fd5b61028d60055481565b6040519081526020015b60405180910390f35b61028d6102ae366004612702565b61064f565b6102d26102c136600461271f565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610297565b6102f36106e8565b005b6102f361030336600461283b565b610704565b6102f36107f7565b600254610323906001600160a01b031681565b6040516001600160a01b039091168152602001610297565b6102f3610349366004612702565b610879565b6102f361035c3660046128d8565b6108a3565b600354610323906001600160a01b031681565b6102f36103823660046128d8565b6108b0565b6102f36108c6565b61028d600d5481565b6102f36108d0565b61028d6103ae366004612702565b60096020526000908152604090206001015481565b6103ea6103d1366004612702565b6008602052600090815260409020805460019091015482565b60408051928352602083019190915201610297565b61028d61040d3660046128f1565b61ffff166000908152600c602052604090205490565b6102f361043136600461290c565b610b1f565b6102f3610444366004612984565b610b46565b600e546104569060ff1681565b6040519015158152602001610297565b61028d6104743660046128f1565b6113ab565b61028d610487366004612702565b6113bc565b6102f361049a366004612702565b6113c7565b6102f3611561565b6104ba6104b5366004612702565b611573565b6040516102979190612a1e565b6102f361160a565b61028d6104dd3660046128d8565b600c6020526000908152604090205481565b6000546001600160a01b0316610323565b6102f361050e366004612702565b61177e565b61028d610521366004612702565b6117a8565b61028d60045481565b6102f361053d366004612a66565b611992565b6102f3610550366004612a88565b6119ac565b6102f361056336600461283b565b6119f6565b6102f36105763660046128d8565b611c92565b6102f3610589366004612b0e565b611c9f565b6102f361059c3660046128d8565b611cff565b61028d6105af3660046128d8565b600b6020526000908152604090205481565b6105d46105cf366004612702565b611d0c565b6040516102979190612b9a565b6105e9611dc5565b6040516102979190612bf0565b6102f3610604366004612a66565b611e0a565b6102f3610617366004612a88565b611e24565b6102f361062a366004612702565b611e6e565b61064261063d366004612702565b611ee7565b6040516102979190612c23565b600080805b6001600160a01b0384166000908152600860205260409020600201548110156106e1576001600160a01b03841660009081526008602052604090206002018054829081106106a4576106a4612c5a565b60009182526020909120601082040154600f9091166002026101000a900461ffff16156106d957816106d581612c86565b9250505b600101610654565b5092915050565b6106f0611fbf565b600e805460ff19811660ff90911615179055565b61070c611fbf565b60005b81518110156107b257600082828151811061072c5761072c612c5a565b602002602001015161ffff169050806000146107a957600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde9061077690309033908690600401612c9f565b600060405180830381600087803b15801561079057600080fd5b505af11580156107a4573d6000803e3d6000fd5b505050505b5060010161070f565b50336001600160a01b03167ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e20826040516107ec9190612a1e565b60405180910390a250565b6107ff612019565b33600090815260096020526040812090610819828261259d565b6001820160009055505061082b612173565b336000818152600860205260409081902090517ffb0fa2c910642b32b54a3cb67e087132deb00fe0e5d488e7ce5f43b4991f70899161086f9160029091019061300d565b60405180910390a2565b610881611fbf565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6108ab611fbf565b600455565b6108b8611fbf565b6108c23382612191565b5050565b6108ce612019565b565b336000908152600960205260409020546108e957600080fd5b6108f1612019565b3360009081526009602052604090206001015442811061092b57604051632fac778f60e21b81523360048201526024015b60405180910390fd5b336000908152600960205260408120905b8154811015610abe57600082828154811061095957610959612c5a565b6000918252602080832060108304015433845260089091526040832060029081018054600f9094169091026101000a90910461ffff16935090839081106109a2576109a2612c5a565b6000918252602080832060108304015433845260089091526040909220865461ffff6002600f90941684026101000a90940493909316935001908590859081106109ee576109ee612c5a565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1681548110610a2657610a26612c5a565b600091825260209091206010820401805461ffff6002600f90941684026101000a021916905554604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde90610a7e90309033908690600401612c9f565b600060405180830381600087803b158015610a9857600080fd5b505af1158015610aac573d6000803e3d6000fd5b50506001909401935061093c92505050565b5033600090815260096020526040812060010155610ada612173565b336001600160a01b03167ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e2082604051610b13919061300d565b60405180910390a25050565b610b27611fbf565b6001600160a01b03909116600090815260086020526040902060010155565b610b4e612019565b848314610b995760405162461bcd60e51b81526020600482015260196024820152780c2e4ceeadacadce8e640d8cadccee8d040dad2e6dac2e8c6d603b1b6044820152606401610922565b848114610be45760405162461bcd60e51b81526020600482015260196024820152780c2e4ceeadacadce8e640d8cadccee8d040dad2e6dac2e8c6d603b1b6044820152606401610922565b336000908152600860205260408120600201549003610fe157336000908152600860205260409020610c1a9060020187876125c2565b5060005b85811015610fdb5760025433906001600160a01b0316636352211e898985818110610c4b57610c4b612c5a565b9050602002016020810190610c6091906128f1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190613020565b6001600160a01b031614610d1857868682818110610ce357610ce3612c5a565b9050602002016020810190610cf891906128f1565b604051635b50a3cf60e11b815261ffff9091166004820152602401610922565b6000878783818110610d2c57610d2c612c5a565b9050602002016020810190610d4191906128f1565b868684818110610d5357610d53612c5a565b9050602002016020810190610d68919061303d565b6040805161ffff909316602084015260ff9091169082015260600160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610e53848484818110610dcd57610dcd612c5a565b9050602002810190610ddf9190613060565b808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250600a935091508a90508987818110610e2657610e26612c5a565b9050602002016020810190610e3b919061303d565b60ff1681526020019081526020016000205483612297565b610e945760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b226b2b935b632a83937b7b360711b6044820152606401610922565b600c6000898985818110610eaa57610eaa612c5a565b9050602002016020810190610ebf91906128f1565b61ffff16815260200190815260200160002054600014610f4457858583818110610eeb57610eeb612c5a565b9050602002016020810190610f00919061303d565b60ff16600c60008a8a86818110610f1957610f19612c5a565b9050602002016020810190610f2e91906128f1565b61ffff1681526020810191909152604001600020555b6002546001600160a01b031663b88d4fde33308b8b87818110610f6957610f69612c5a565b9050602002016020810190610f7e91906128f1565b6040518463ffffffff1660e01b8152600401610f9c939291906130aa565b600060405180830381600087803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b505060019093019250610c1e915050565b50611358565b60005b858110156113565760025433906001600160a01b0316636352211e89898581811061101157611011612c5a565b905060200201602081019061102691906128f1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015611065573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110899190613020565b6001600160a01b0316146110a957868682818110610ce357610ce3612c5a565b60008787838181106110bd576110bd612c5a565b90506020020160208101906110d291906128f1565b8686848181106110e4576110e4612c5a565b90506020020160208101906110f9919061303d565b6040805161ffff909316602084015260ff9091169082015260600160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120905061115e848484818110610dcd57610dcd612c5a565b61119f5760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b226b2b935b632a83937b7b360711b6044820152606401610922565b600c60008989858181106111b5576111b5612c5a565b90506020020160208101906111ca91906128f1565b61ffff1681526020019081526020016000205460001461124f578585838181106111f6576111f6612c5a565b905060200201602081019061120b919061303d565b60ff16600c60008a8a8681811061122457611224612c5a565b905060200201602081019061123991906128f1565b61ffff1681526020810191909152604001600020555b33600090815260086020526040902060020188888481811061127357611273612c5a565b905060200201602081019061128891906128f1565b8154600181018355600092835260209092206010830401805461ffff9283166002600f90951685026101000a90810293021916919091179055546001600160a01b031663b88d4fde33308b8b878181106112e4576112e4612c5a565b90506020020160208101906112f991906128f1565b6040518463ffffffff1660e01b8152600401611317939291906130aa565b600060405180830381600087803b15801561133157600080fd5b505af1158015611345573d6000803e3d6000fd5b505060019093019250610fe4915050565b505b611360612173565b336001600160a01b03167f29ac78bc3dcd88143fb4d2986027c15f05c86c7adec8521f8df902c854c0f5c1878760405161139b9291906130e0565b60405180910390a2505050505050565b60006113b6826122ad565b92915050565b60006113b682612351565b6113cf611fbf565b6001600160a01b03811660009081526008602090815260408083206002018054825181850281018501909352808352919290919083018282801561145a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114215790505b5050505050905060005b815181101561150757600082828151811061148157611481612c5a565b602002602001015161ffff169050806000146114fe57600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde906114cb90309088908690600401612c9f565b600060405180830381600087803b1580156114e557600080fd5b505af11580156114f9573d6000803e3d6000fd5b505050505b50600101611464565b50611511826117a8565b6001600160a01b038316600081815260086020526040908190206001019290925590517ff0b7bd0c6bac1e6b288e801469a8fe79118fc27bf620dbfce792534bc2878e2090610b13908490612a1e565b611569611fbf565b6108ce6000612485565b6001600160a01b0381166000908152600860209081526040918290206002018054835181840281018401909452808452606093928301828280156115fe57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116115c55790505b50505050509050919050565b3360009081526009602052604090205461162357600080fd5b61162b612019565b33600090815260096020908152604080832060010154600890925290912060020142821061166e57604051632fac778f60e21b8152336004820152602401610922565b60005b815481101561172857600082828154811061168e5761168e612c5a565b60009182526020909120601082040154600f9091166002026101000a900461ffff169050801561171f57600254604051635c46a7ef60e11b81526001600160a01b039091169063b88d4fde906116ec903090339086906004016130aa565b600060405180830381600087803b15801561170657600080fd5b505af115801561171a573d6000803e3d6000fd5b505050505b50600101611671565b503360009081526008602052604081208181556001810182905590611750600283018261259d565b50503360009081526009602052604081209061176c828261259d565b600182016000905550506108c2612173565b611786611fbf565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116600090815260086020908152604080832060020180548251818502810185019093528083528493849384939092909183018282801561183857602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116117ff5790505b5050505050905060005b81518110156118815761186d82828151811061186057611860612c5a565b60200260200101516122ad565b6118779085613127565b9350600101611842565b506001600160a01b03851660009081526009602052604090206001015480156119885760005b6001600160a01b038716600090815260096020526040902054811015611943576001600160a01b0387166000908152600960205260409020805461192f918591849081106118f7576118f7612c5a565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff168151811061186057611860612c5a565b6119399085613127565b93506001016118a7565b50600654600554611954908561313a565b61195e9190613151565b9250828410156119745750600095945050505050565b61197e8385613173565b9695505050505050565b5091949350505050565b61199a611fbf565b6000918252600b602052604090912055565b6119b4611fbf565b60005b81518110156108c2578181815181106119d2576119d2612c5a565b6020908102919091018101516000838152600a9092526040909120556001016119b7565b6119fe612019565b3360009081526008602052604090206002015481511115611a6b5760405162461bcd60e51b815260206004820152602160248201527f72657175657374696e67206d6f726520746f6b656e73207468616e206f776e656044820152601960fa1b6064820152608401610922565b6000815111611ab55760405162461bcd60e51b815260206004820152601660248201527572657175657374696e67207a65726f20746f6b656e7360501b6044820152606401610922565b3360009081526009602052604090206001015415611ae857604051632fac778f60e21b8152336004820152602401610922565b33600090815260086020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611b315790505b5050505050905060005b8251811015611c0f5781838281518110611b9057611b90612c5a565b602002602001015161ffff1681518110611bac57611bac612c5a565b602002602001015161ffff16600003611c075760405162461bcd60e51b815260206004820152601e60248201527f72657175657374696e67207a65726f20746f6b656e20776974686472617700006044820152606401610922565b600101611b74565b503360009081526009602090815260409091208351611c309285019061266f565b50600454611c3e9042613127565b33600090815260096020526040902060010155611c59612173565b336001600160a01b03167f83edb46098d7facbf9ea0441339f25f8bba07cf211f4047cd2d8bef7747452e983604051610b139190612a1e565b611c9a611fbf565b600755565b611ca7611fbf565b60005b82811015611cf9576000848483818110611cc657611cc6612c5a565b9050602002016020810190611cdb91906128f1565b61ffff166000908152600c6020526040902083905550600101611caa565b50505050565b611d07611fbf565b600d55565b6040805180820182526060808252600060208084018290526001600160a01b0386168252600981529084902084518154928302810184018652948501828152939493909284928491840182828015611dab57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611d725790505b505050505081526020016001820154815250509050919050565b606060006040518060800160405280604a815260200161322c604a9139905080604051602001611df59190613186565b60405160208183030381529060405291505090565b611e12611fbf565b6000918252600c602052604090912055565b611e2c611fbf565b60005b81518110156108c257818181518110611e4a57611e4a612c5a565b6020908102919091018101516000838152600b909252604090912055600101611e2f565b611e76611fbf565b6001600160a01b038116611edb5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610922565b611ee481612485565b50565b611f0b60405180606001604052806000815260200160008152602001606081525090565b6001600160a01b03821660009081526008602090815260409182902082516060810184528154815260018201548184015260028201805485518186028101860187528181529295939493860193830182828015611faf57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411611f765790505b5050505050815250509050919050565b6000546001600160a01b031633146108ce5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610922565b6120216124d5565b600e5460ff161561203157600080fd5b33600090815260086020526040902054421461216a57600061205233612351565b33600090815260086020526040902042905590508015612168576120763382612191565b156120d057336000818152600860205260409081902090517fa713cedec5f3f717911608ee42ed2c7a49db9b06305a7f817990cce586575acd916120c391600290910190859042906131cb565b60405180910390a2612168565b336000818152600860205260409081902090517fbc42de6c6966c6186e5cc495ff9dbd3510cfb473c3bb08480c93d6dd493d79009161211891600290910190859042906131cb565b60405180910390a260405162461bcd60e51b815260206004820152601760248201527f6661696c656420746f20636c61696d20726577617264730000000000000000006044820152606401610922565b505b6108ce60018055565b61217c336117a8565b33600090815260086020526040902060010155565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156121de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220291906131f0565b905080831161228d5760035460405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690529091169063a9059cbb906044016020604051808303816000875af115801561225e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122829190613209565b5060019150506113b6565b5060009392505050565b6000826122a4858461252e565b14949350505050565b60008161ffff166000036122c357506000919050565b604051631460147160e21b815261ffff83166004820152600090309063518051c490602401602060405180830381865afa158015612305573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232991906131f0565b6000818152600b602052604090205490915061234a906301e1338090613151565b9392505050565b6001600160a01b038116600090815260086020526040812060010154810361237b57506000919050565b6001600160a01b0382166000908152600860205260409020544210156123a357506000919050565b60065460075414612424576006546001600160a01b038316600090815260086020526040902054600d5442106123db57600d546123dd565b425b6123e79190613173565b6007546001600160a01b038516600090815260086020526040902060010154612410919061313a565b61241a919061313a565b6113b69190613151565b6001600160a01b038216600090815260086020526040902054600d54421061244e57600d54612450565b425b61245a9190613173565b6001600160a01b0383166000908152600860205260409020600101546113b6919061313a565b919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6002600154036125275760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610922565b6002600155565b600081815b84518110156125695761255f8286838151811061255257612552612c5a565b6020026020010151612571565b9150600101612533565b509392505050565b600081831061258d57600082815260208490526040902061234a565b5060009182526020526040902090565b50805460008255600f016010900490600052602060002090810190611ee491906126d8565b82805482825590600052602060002090600f0160109004810192821561265f5791602002820160005b8382111561262f57833561ffff1683826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026125eb565b801561265d5782816101000a81549061ffff021916905560020160208160010104928301926001030261262f565b505b5061266b9291506126d8565b5090565b82805482825590600052602060002090600f0160109004810192821561265f5791602002820160005b8382111561262f57835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302612698565b5b8082111561266b57600081556001016126d9565b6001600160a01b0381168114611ee457600080fd5b60006020828403121561271457600080fd5b813561234a816126ed565b60008060008060006080868803121561273757600080fd5b8535612742816126ed565b94506020860135612752816126ed565b935060408601359250606086013567ffffffffffffffff8082111561277657600080fd5b818801915088601f83011261278a57600080fd5b81358181111561279957600080fd5b8960208285010111156127ab57600080fd5b9699959850939650602001949392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156127fd576127fd6127be565b604052919050565b600067ffffffffffffffff82111561281f5761281f6127be565b5060051b60200190565b803561ffff8116811461248057600080fd5b6000602080838503121561284e57600080fd5b823567ffffffffffffffff81111561286557600080fd5b8301601f8101851361287657600080fd5b803561288961288482612805565b6127d4565b81815260059190911b820183019083810190878311156128a857600080fd5b928401925b828410156128cd576128be84612829565b825292840192908401906128ad565b979650505050505050565b6000602082840312156128ea57600080fd5b5035919050565b60006020828403121561290357600080fd5b61234a82612829565b6000806040838503121561291f57600080fd5b823561292a816126ed565b946020939093013593505050565b60008083601f84011261294a57600080fd5b50813567ffffffffffffffff81111561296257600080fd5b6020830191508360208260051b850101111561297d57600080fd5b9250929050565b6000806000806000806060878903121561299d57600080fd5b863567ffffffffffffffff808211156129b557600080fd5b6129c18a838b01612938565b909850965060208901359150808211156129da57600080fd5b6129e68a838b01612938565b909650945060408901359150808211156129ff57600080fd5b50612a0c89828a01612938565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015612a5a57835161ffff1683529284019291840191600101612a3a565b50909695505050505050565b60008060408385031215612a7957600080fd5b50508035926020909101359150565b60006020808385031215612a9b57600080fd5b823567ffffffffffffffff811115612ab257600080fd5b8301601f81018513612ac357600080fd5b8035612ad161288482612805565b81815260059190911b82018301908381019087831115612af057600080fd5b928401925b828410156128cd57833582529284019290840190612af5565b600080600060408486031215612b2357600080fd5b833567ffffffffffffffff811115612b3a57600080fd5b612b4686828701612938565b909790965060209590950135949350505050565b60008151808452602080850194506020840160005b83811015612b8f57815161ffff1687529582019590820190600101612b6f565b509495945050505050565b602081526000825160406020840152612bb66060840182612b5a565b9050602084015160408401528091505092915050565b60005b83811015612be7578181015183820152602001612bcf565b50506000910152565b6020815260008251806020840152612c0f816040850160208701612bcc565b601f01601f19169190910160400192915050565b60208152815160208201526020820151604082015260006040830151606080840152612c526080840182612b5a565b949350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c9857612c98612c70565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260806060820181905260009082015260a00190565b805480835260008281526020808220940193909190825b82600f82011015612e3a57815461ffff80821688526020612d14818a01838560101c1661ffff169052565b6040612d29818b018486851c1661ffff169052565b60609150612d41828b01848660301c1661ffff169052565b6080612d56818c018587851c1661ffff169052565b60a09150612d6e828c01858760501c1661ffff169052565b60c0612d83818d018688871c1661ffff169052565b60e09350612d9b848d01868860701c1661ffff169052565b61ffff86831c8616166101008d0152612dc06101208d01868860901c1661ffff169052565b61ffff86841c8616166101408d0152612de56101608d01868860b01c1661ffff169052565b61ffff86821c8616166101808d0152505050612e0d6101a08a01838560d01c1661ffff169052565b82901c1661ffff166101c088015260f01c6101e08701526102009095019460019190910190601001612ce9565b90549082811015612e565761ffff821686526020909501946001015b82811015612e735761ffff601083901c1686526020909501946001015b82811015612e9157602082901c61ffff168652602095909501946001015b82811015612eae5761ffff603083901c1686526020909501946001015b82811015612ecb5761ffff604083901c1686526020909501946001015b82811015612ee85761ffff605083901c1686526020909501946001015b82811015612f055761ffff606083901c1686526020909501946001015b82811015612f225761ffff607083901c1686526020909501946001015b82811015612f3f5761ffff608083901c1686526020909501946001015b82811015612f5c5761ffff609083901c1686526020909501946001015b82811015612f795761ffff60a083901c1686526020909501946001015b82811015612f965761ffff60b083901c1686526020909501946001015b82811015612fb35761ffff60c083901c1686526020909501946001015b82811015612fd05761ffff60d083901c1686526020909501946001015b82811015612fed5761ffff60e083901c1686526020909501946001015b828110156130035760f082901c86526020860195505b5093949350505050565b60208152600061234a6020830184612cd2565b60006020828403121561303257600080fd5b815161234a816126ed565b60006020828403121561304f57600080fd5b813560ff8116811461234a57600080fd5b6000808335601e1984360301811261307757600080fd5b83018035915067ffffffffffffffff82111561309257600080fd5b6020019150600581901b360382131561297d57600080fd5b6001600160a01b03938416815291909216602082015261ffff909116604082015260806060820181905260009082015260a00190565b60208082528181018390526000908460408401835b8681101561311c5761ffff61310984612829565b16825291830191908301906001016130f5565b509695505050505050565b808201808211156113b6576113b6612c70565b80820281158282048414176113b6576113b6612c70565b60008261316e57634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156113b6576113b6612c70565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c00000000008152600082516131be81601b850160208701612bcc565b91909101601b0192915050565b6060815260006131de6060830186612cd2565b60208301949094525060400152919050565b60006020828403121561320257600080fd5b5051919050565b60006020828403121561321b57600080fd5b8151801515811461234a57600080fdfe7b226e616d65223a2022436861726765642053747265657473206f66204d696c616479222c226465736372697074696f6e223a2253616e6b6f206f6666696369616c20c2a9efb88f227da26469706673582212206409f47b69cfa37fd489ca452ac99822c049979066688c4ac3807cd9f61130b364736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000094fe1d5de3a4208c7411ae21968e044abc17be480000000000000000000000008bc31478f95fc8e4c7fe578fb86bad1fe851e41a0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000053444835ec5800000000000000000000000000000000000000000000000000006124fee993bc00000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000007ce66c50e28400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000006ef34f212cd5e693b4dbbfde41052af11114d5394d29139e215d7d2b9cb6aaf8b6efa21b761fc506c645e3c491b825182b903d6736cdcdf1853242a4393fb6dbee7b48cf96d253c35584ec7ce54d74e567200fc6bfed30b9c83d9e8ed97693b32bdcc67b4e1f0be07f13b9a05c3a011ed9a3dc13cae26e96df32a655886f36c6dc51cead9ede86762b57b84f48aff81f6d6d73d5a067fae9de3503d77e6cf885d54945aff102474d66957d680dbf7d33924d9c0f45df62585910d4de7823aad1e
-----Decoded View---------------
Arg [0] : _erc721Address (address): 0x94Fe1D5DE3A4208C7411AE21968e044AbC17be48
Arg [1] : _erc20Address (address): 0x8bc31478F95FC8E4C7FE578FB86bAd1fe851e41A
Arg [2] : _rates (uint256[]): 5000000000000000000,6000000000000000000,7000000000000000000,8000000000000000000,9000000000000000000,10000000000000000000
Arg [3] : _merkleRoots (bytes32[]): System.Byte[],System.Byte[],System.Byte[],System.Byte[],System.Byte[],System.Byte[]
-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 00000000000000000000000094fe1d5de3a4208c7411ae21968e044abc17be48
Arg [1] : 0000000000000000000000008bc31478f95fc8e4c7fe578fb86bad1fe851e41a
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [5] : 0000000000000000000000000000000000000000000000004563918244f40000
Arg [6] : 00000000000000000000000000000000000000000000000053444835ec580000
Arg [7] : 0000000000000000000000000000000000000000000000006124fee993bc0000
Arg [8] : 0000000000000000000000000000000000000000000000006f05b59d3b200000
Arg [9] : 0000000000000000000000000000000000000000000000007ce66c50e2840000
Arg [10] : 0000000000000000000000000000000000000000000000008ac7230489e80000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [12] : ef34f212cd5e693b4dbbfde41052af11114d5394d29139e215d7d2b9cb6aaf8b
Arg [13] : 6efa21b761fc506c645e3c491b825182b903d6736cdcdf1853242a4393fb6dbe
Arg [14] : e7b48cf96d253c35584ec7ce54d74e567200fc6bfed30b9c83d9e8ed97693b32
Arg [15] : bdcc67b4e1f0be07f13b9a05c3a011ed9a3dc13cae26e96df32a655886f36c6d
Arg [16] : c51cead9ede86762b57b84f48aff81f6d6d73d5a067fae9de3503d77e6cf885d
Arg [17] : 54945aff102474d66957d680dbf7d33924d9c0f45df62585910d4de7823aad1e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.