Overview
ETH Balance
0.00069 ETH
Eth Value
$2.31 (@ $3,355.04/ETH)More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 5,960 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Burn Redeem | 21131058 | 16 days ago | IN | 0.00069 ETH | 0.00281879 | ||||
Update Burn Rede... | 20995768 | 35 days ago | IN | 0 ETH | 0.00149271 | ||||
Update Burn Rede... | 20995755 | 35 days ago | IN | 0 ETH | 0.00155909 | ||||
Update Burn Rede... | 20995752 | 35 days ago | IN | 0 ETH | 0.00162217 | ||||
Update Burn Rede... | 20995731 | 35 days ago | IN | 0 ETH | 0.0016714 | ||||
Update Burn Rede... | 20995713 | 35 days ago | IN | 0 ETH | 0.00153477 | ||||
Update Burn Rede... | 20995656 | 35 days ago | IN | 0 ETH | 0.00158783 | ||||
Update Burn Rede... | 20995618 | 35 days ago | IN | 0 ETH | 0.00203462 | ||||
Airdrop | 20545870 | 98 days ago | IN | 0 ETH | 0.00012437 | ||||
Airdrop | 20545862 | 98 days ago | IN | 0 ETH | 0.00012741 | ||||
Burn Redeem | 20446060 | 112 days ago | IN | 0.00069 ETH | 0.0002176 | ||||
Burn Redeem | 19920012 | 185 days ago | IN | 0.00069 ETH | 0.00311163 | ||||
Burn Redeem | 19692474 | 217 days ago | IN | 0.00069 ETH | 0.00127524 | ||||
Burn Redeem | 19598687 | 230 days ago | IN | 0.00069 ETH | 0.00211057 | ||||
Burn Redeem | 19500626 | 244 days ago | IN | 0.00069 ETH | 0.00238264 | ||||
Burn Redeem | 19435075 | 253 days ago | IN | 0.00069 ETH | 0.00745172 | ||||
Burn Redeem | 19434874 | 253 days ago | IN | 0.00069 ETH | 0.00757265 | ||||
Burn Redeem | 19425832 | 254 days ago | IN | 0.00069 ETH | 0.00906065 | ||||
Update Token URI | 19233760 | 281 days ago | IN | 0 ETH | 0.0019868 | ||||
Update Token URI | 19233757 | 281 days ago | IN | 0 ETH | 0.00190397 | ||||
Update Token URI | 19233752 | 281 days ago | IN | 0 ETH | 0.00171508 | ||||
Update Token URI | 19169554 | 290 days ago | IN | 0 ETH | 0.00199805 | ||||
Update Token URI | 19169552 | 290 days ago | IN | 0 ETH | 0.00188849 | ||||
Update Token URI | 19169548 | 290 days ago | IN | 0 ETH | 0.00194541 | ||||
Burn Redeem | 19114703 | 298 days ago | IN | 0.00069 ETH | 0.00202178 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20924404 | 45 days ago | 0.00276 ETH | ||||
19572774 | 234 days ago | 0.89385 ETH | ||||
19571708 | 234 days ago | 0.89385 ETH | ||||
18993458 | 315 days ago | 0.069 ETH | ||||
18993430 | 315 days ago | 0.069 ETH | ||||
18993421 | 315 days ago | 0.138 ETH | ||||
18847157 | 335 days ago | 0.0012 ETH | ||||
18782097 | 345 days ago | 5.94477 ETH | ||||
18762862 | 347 days ago | 0.0006 ETH | ||||
18487163 | 386 days ago | 0.0006 ETH | ||||
18460412 | 390 days ago | 0.0006 ETH | ||||
18140132 | 434 days ago | 0.0006 ETH | ||||
18073143 | 444 days ago | 0.0006 ETH | ||||
18008527 | 453 days ago | 0.0006 ETH | ||||
17966007 | 459 days ago | 0.0006 ETH | ||||
17873773 | 472 days ago | 0.00069 ETH | ||||
17836622 | 477 days ago | 0.00069 ETH | ||||
17820321 | 479 days ago | 0.00198 ETH | ||||
17818745 | 479 days ago | 0.00069 ETH | ||||
17797219 | 482 days ago | 0.001 ETH | ||||
17797210 | 482 days ago | 0.001 ETH | ||||
17797186 | 482 days ago | 0.0017 ETH | ||||
17797166 | 483 days ago | 0.001 ETH | ||||
17797149 | 483 days ago | 0.001 ETH | ||||
17796788 | 483 days ago | 0.00069 ETH |
Loading...
Loading
Contract Name:
ERC721BurnRedeem
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 150 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol"; import "./BurnRedeemCore.sol"; import "./BurnRedeemLib.sol"; import "./IERC721BurnRedeem.sol"; import "../../libraries/IERC721CreatorCoreVersion.sol"; contract ERC721BurnRedeem is BurnRedeemCore, IERC721BurnRedeem { using Strings for uint256; // NOTE: Only used for creatorContract versions < 3 // { contractAddress => { tokenId => { RedeemToken } } mapping(address => mapping(uint256 => RedeemToken)) internal _redeemTokens; // { creatorContractAddress => { instanceId => bool } } mapping(address => mapping(uint256 => bool)) private _identicalTokenURI; function supportsInterface(bytes4 interfaceId) public view virtual override(BurnRedeemCore, IERC165) returns (bool) { return interfaceId == type(IERC721BurnRedeem).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721BurnRedeem-initializeBurnRedeem}. */ function initializeBurnRedeem( address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI ) external creatorAdminRequired(creatorContractAddress) { // Max uint56 for instanceId require(instanceId > 0 && instanceId <= MAX_UINT_56, "Invalid instanceId"); uint8 creatorContractVersion; try IERC721CreatorCoreVersion(creatorContractAddress).VERSION() returns(uint256 version) { require(version <= 255, "Unsupported contract version"); creatorContractVersion = uint8(version); } catch {} _initialize(creatorContractAddress, creatorContractVersion, instanceId, burnRedeemParameters); _identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI; } /** * @dev See {IERC721BurnRedeem-updateBurnRedeem}. */ function updateBurnRedeem( address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI ) external creatorAdminRequired(creatorContractAddress) { _update(creatorContractAddress, instanceId, burnRedeemParameters); _identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI; } /** * See {IERC721BurnRedeem-updateTokenURI}. */ function updateTokenURI( address creatorContractAddress, uint256 instanceId, StorageProtocol storageProtocol, string calldata location, bool identicalTokenURI ) external override creatorAdminRequired(creatorContractAddress) { BurnRedeem storage burnRedeemInstance = _getBurnRedeem(creatorContractAddress, instanceId); burnRedeemInstance.storageProtocol = storageProtocol; burnRedeemInstance.location = location; _identicalTokenURI[creatorContractAddress][instanceId] = identicalTokenURI; emit BurnRedeemLib.BurnRedeemUpdated(creatorContractAddress, instanceId); } /** * Helper to mint multiple redeem tokens */ function _redeem(address creatorContractAddress, uint256 instanceId, BurnRedeem storage burnRedeemInstance, address to, uint32 count) internal override { if (burnRedeemInstance.redeemAmount == 1 && count == 1) { ++burnRedeemInstance.redeemedCount; uint256 newTokenId; if (burnRedeemInstance.contractVersion >= 3) { uint80 tokenData = uint56(instanceId) << 24 | burnRedeemInstance.redeemedCount; newTokenId = IERC721CreatorCore(creatorContractAddress).mintExtension(to, tokenData); } else { newTokenId = IERC721CreatorCore(creatorContractAddress).mintExtension(to); _redeemTokens[creatorContractAddress][newTokenId] = RedeemToken(uint224(instanceId), burnRedeemInstance.redeemedCount); } emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenId, 1); } else { uint256 totalCount = burnRedeemInstance.redeemAmount * count; require(totalCount <= MAX_UINT_16, "Invalid input"); uint256 startingCount = burnRedeemInstance.redeemedCount + 1; burnRedeemInstance.redeemedCount += uint32(totalCount); if (burnRedeemInstance.contractVersion >= 3) { uint80[] memory tokenDatas = new uint80[](totalCount); for (uint256 i; i < totalCount;) { tokenDatas[i] = uint56(instanceId) << 24 | uint24(startingCount+i); unchecked { ++i; } } uint256[] memory newTokenIds = IERC721CreatorCore(creatorContractAddress).mintExtensionBatch(to, tokenDatas); for (uint256 i; i < totalCount;) { emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenIds[i], 1); unchecked { i++; } } } else { uint256[] memory newTokenIds = IERC721CreatorCore(creatorContractAddress).mintExtensionBatch(to, uint16(totalCount)); for (uint256 i; i < totalCount;) { _redeemTokens[creatorContractAddress][newTokenIds[i]] = RedeemToken(uint224(instanceId), uint32(startingCount + i)); emit BurnRedeemLib.BurnRedeemMint(creatorContractAddress, instanceId, newTokenIds[i], 1); unchecked { i++; } } } } } /** * See {ICreatorExtensionTokenURI-tokenURI}. */ function tokenURI(address creatorContractAddress, uint256 tokenId) external override view returns(string memory uri) { RedeemToken memory token = _redeemTokens[creatorContractAddress][tokenId]; BurnRedeem memory burnRedeem; uint256 mintNumber; uint256 instanceId; if (token.instanceId == 0) { // No claim, try to retrieve from tokenData uint80 tokenData = IERC721CreatorCore(creatorContractAddress).tokenData(tokenId); instanceId = uint56(tokenData >> 24); require(instanceId != 0, "Token does not exist"); mintNumber = uint24(tokenData & MAX_UINT_24); } else { instanceId = token.instanceId; mintNumber = token.mintNumber; } burnRedeem = _burnRedeems[creatorContractAddress][instanceId]; string memory prefix = ""; if (burnRedeem.storageProtocol == StorageProtocol.ARWEAVE) { prefix = ARWEAVE_PREFIX; } else if (burnRedeem.storageProtocol == StorageProtocol.IPFS) { prefix = IPFS_PREFIX; } uri = string(abi.encodePacked(prefix, burnRedeem.location)); if (!_identicalTokenURI[creatorContractAddress][instanceId]) { uri = string(abi.encodePacked(uri, "/", uint256(mintNumber).toString())); } } /** * See {IBurnRedeemCore-getBurnRedeemForToken}. */ function getBurnRedeemForToken(address creatorContractAddress, uint256 tokenId) external override view returns(uint256 instanceId, BurnRedeem memory burnRedeem) { RedeemToken memory token = _redeemTokens[creatorContractAddress][tokenId]; if (token.instanceId == 0) { // No claim, try to retrieve from tokenData uint80 tokenData = IERC721CreatorCore(creatorContractAddress).tokenData(tokenId); instanceId = uint56(tokenData >> 24); } else { instanceId = token.instanceId; } require(instanceId != 0, "Token does not exist"); burnRedeem = _burnRedeems[creatorContractAddress][instanceId]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @dev Core creator interface */ interface ICreatorCore is IERC165 { event ExtensionRegistered(address indexed extension, address indexed sender); event ExtensionUnregistered(address indexed extension, address indexed sender); event ExtensionBlacklisted(address indexed extension, address indexed sender); event MintPermissionsUpdated(address indexed extension, address indexed permissions, address indexed sender); event RoyaltiesUpdated(uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints); event DefaultRoyaltiesUpdated(address payable[] receivers, uint256[] basisPoints); event ApproveTransferUpdated(address extension); event ExtensionRoyaltiesUpdated(address indexed extension, address payable[] receivers, uint256[] basisPoints); event ExtensionApproveTransferUpdated(address indexed extension, bool enabled); /** * @dev gets address of all extensions */ function getExtensions() external view returns (address[] memory); /** * @dev add an extension. Can only be called by contract owner or admin. * extension address must point to a contract implementing ICreatorExtension. * Returns True if newly added, False if already added. */ function registerExtension(address extension, string calldata baseURI) external; /** * @dev add an extension. Can only be called by contract owner or admin. * extension address must point to a contract implementing ICreatorExtension. * Returns True if newly added, False if already added. */ function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external; /** * @dev add an extension. Can only be called by contract owner or admin. * Returns True if removed, False if already removed. */ function unregisterExtension(address extension) external; /** * @dev blacklist an extension. Can only be called by contract owner or admin. * This function will destroy all ability to reference the metadata of any tokens created * by the specified extension. It will also unregister the extension if needed. * Returns True if removed, False if already removed. */ function blacklistExtension(address extension) external; /** * @dev set the baseTokenURI of an extension. Can only be called by extension. */ function setBaseTokenURIExtension(string calldata uri) external; /** * @dev set the baseTokenURI of an extension. Can only be called by extension. * For tokens with no uri configured, tokenURI will return "uri+tokenId" */ function setBaseTokenURIExtension(string calldata uri, bool identical) external; /** * @dev set the common prefix of an extension. Can only be called by extension. * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI" * Useful if you want to use ipfs/arweave */ function setTokenURIPrefixExtension(string calldata prefix) external; /** * @dev set the tokenURI of a token extension. Can only be called by extension that minted token. */ function setTokenURIExtension(uint256 tokenId, string calldata uri) external; /** * @dev set the tokenURI of a token extension for multiple tokens. Can only be called by extension that minted token. */ function setTokenURIExtension(uint256[] memory tokenId, string[] calldata uri) external; /** * @dev set the baseTokenURI for tokens with no extension. Can only be called by owner/admin. * For tokens with no uri configured, tokenURI will return "uri+tokenId" */ function setBaseTokenURI(string calldata uri) external; /** * @dev set the common prefix for tokens with no extension. Can only be called by owner/admin. * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI" * Useful if you want to use ipfs/arweave */ function setTokenURIPrefix(string calldata prefix) external; /** * @dev set the tokenURI of a token with no extension. Can only be called by owner/admin. */ function setTokenURI(uint256 tokenId, string calldata uri) external; /** * @dev set the tokenURI of multiple tokens with no extension. Can only be called by owner/admin. */ function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external; /** * @dev set a permissions contract for an extension. Used to control minting. */ function setMintPermissions(address extension, address permissions) external; /** * @dev Configure so transfers of tokens created by the caller (must be extension) gets approval * from the extension before transferring */ function setApproveTransferExtension(bool enabled) external; /** * @dev get the extension of a given token */ function tokenExtension(uint256 tokenId) external view returns (address); /** * @dev Set default royalties */ function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external; /** * @dev Set royalties of a token */ function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external; /** * @dev Set royalties of an extension */ function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external; /** * @dev Get royalites of a token. Returns list of receivers and basisPoints */ function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); // Royalty support for various other standards function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory); function getFeeBps(uint256 tokenId) external view returns (uint[] memory); function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256); /** * @dev Set the default approve transfer contract location. */ function setApproveTransfer(address extension) external; /** * @dev Get the default approve transfer contract location. */ function getApproveTransfer() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "./ICreatorCore.sol"; /** * @dev Core ERC721 creator interface */ interface IERC721CreatorCore is ICreatorCore { /** * @dev mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBase(address to) external returns (uint256); /** * @dev mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBase(address to, string calldata uri) external returns (uint256); /** * @dev batch mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBaseBatch(address to, uint16 count) external returns (uint256[] memory); /** * @dev batch mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBaseBatch(address to, string[] calldata uris) external returns (uint256[] memory); /** * @dev mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtension(address to) external returns (uint256); /** * @dev mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtension(address to, string calldata uri) external returns (uint256); /** * @dev mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtension(address to, uint80 data) external returns (uint256); /** * @dev batch mint a token. Can only be called by a registered extension. * Returns tokenIds minted */ function mintExtensionBatch(address to, uint16 count) external returns (uint256[] memory); /** * @dev batch mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtensionBatch(address to, string[] calldata uris) external returns (uint256[] memory); /** * @dev batch mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtensionBatch(address to, uint80[] calldata data) external returns (uint256[] memory); /** * @dev burn a token. Can only be called by token owner or approved address. * On burn, calls back to the registered extension's onBurn method */ function burn(uint256 tokenId) external; /** * @dev get token data */ function tokenData(uint256 tokenId) external view returns (uint80); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @dev Implement this if you want your extension to have overloadable URI's */ interface ICreatorExtensionTokenURI is IERC165 { /** * Get the uri for a given creator/tokenId */ function tokenURI(address creator, uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./IAdminControl.sol"; abstract contract AdminControl is Ownable, IAdminControl, ERC165 { using EnumerableSet for EnumerableSet.AddressSet; // Track registered admins EnumerableSet.AddressSet private _admins; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IAdminControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Only allows approved admins to call the specified function */ modifier adminRequired() { require(owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin"); _; } /** * @dev See {IAdminControl-getAdmins}. */ function getAdmins() external view override returns (address[] memory admins) { admins = new address[](_admins.length()); for (uint i = 0; i < _admins.length(); i++) { admins[i] = _admins.at(i); } return admins; } /** * @dev See {IAdminControl-approveAdmin}. */ function approveAdmin(address admin) external override onlyOwner { if (!_admins.contains(admin)) { emit AdminApproved(admin, msg.sender); _admins.add(admin); } } /** * @dev See {IAdminControl-revokeAdmin}. */ function revokeAdmin(address admin) external override onlyOwner { if (_admins.contains(admin)) { emit AdminRevoked(admin, msg.sender); _admins.remove(admin); } } /** * @dev See {IAdminControl-isAdmin}. */ function isAdmin(address admin) public override view returns (bool) { return (owner() == admin || _admins.contains(admin)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @dev Interface for admin control */ interface IAdminControl is IERC165 { event AdminApproved(address indexed account, address indexed sender); event AdminRevoked(address indexed account, address indexed sender); /** * @dev gets address of all admins */ function getAdmins() external view returns (address[] memory); /** * @dev add an admin. Can only be called by contract owner. */ function approveAdmin(address admin) external; /** * @dev remove an admin. Can only be called by contract owner. */ function revokeAdmin(address admin) external; /** * @dev checks whether or not given address is an admin * Returns True if they are */ function isAdmin(address admin) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.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 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * 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. */ 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 proved to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * _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} * * _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 the sibling nodes in `proof`, * consuming from one or the other at each step according to the instructions given by * `proofFlags`. * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild 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 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 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 for 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) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof} * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild 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 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 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 for 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) { 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 // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC721CreatorCoreVersion { function VERSION() external view returns(uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz /** * Manifold Membership interface */ interface IManifoldMembership { function isActiveMember(address sender) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; ///////////////////////////////////////////////////////////////////////////////////// // // // // // .%(#. // // #(((#%, // // (#(((((#%* // // /#((((((((##* // // (#((((((((((##%. // // ,##(/*/(////((((#%* // // .###(//****/////(((##%, // // (, ,%#((((((///******/////((##%( // // *((, ,##(///////*********////((###%* // // /(((( ,##(//////************/(((((###% // // /(((( ,##((////***************/((((###% // // ((( .###((///*****************((((#### // // . (##((//*******************((((##%* // // (#. .###((/********************((((##%. %. // // ,%(#. .###(/********,,,,,,,*****/(((###%# ((%, // // /%#/(/ /###(//****,,,,,,,,,,,****/((((((##%%%%#((#%. // // /##(//(#. ,###((/****,,,,,,,,,,,,,***/((/(((((((((#####% // // *%##(/////((###((((/***,,,,,,,,,,,,,,,***//((((((((((####%%%/ // // ####(((//////(//////**,,,,,,.....,,,,,,****/(((((//((####%%%% // // .####(((/((((((/////**,,,,,.......,,,,,,,,*****/////(#####%%%% // // .#%###((////(((//***,,,,,,..........,,,,,,,,*****//((#####%%%% // // /%%%###/////*****,,,,,,,..............,,,,,,,****/(((####%%%% // // /%%###(////****,,,,,,..... ......,,,,,,**(((####%%%% // // ,#%###(///****,,,,,.... .....,,,,,***/(/(##%%( // // (####(//****,,.... ....,,,,,***/(#### // // (###(/***,,,... ...,,,,***(##/ // // #. (#((/**,,,,.. ...,,,,*((#, // // ,#(##(((//,,,,.. ...,,,*/(((#((/ // // *#(((///*,,.... ....,*//(((( // // *(///***,.... ...,***//, // // ,//***,... ..,,*, // // // // // ///////////////////////////////////////////////////////////////////////////////////// import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol"; import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol"; import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "../../libraries/manifold-membership/IManifoldMembership.sol"; import "./BurnRedeemLib.sol"; import "./IBurnRedeemCore.sol"; import "./Interfaces.sol"; /** * @title Burn Redeem Core * @author manifold.xyz * @notice Core logic for Burn Redeem shared extensions. */ abstract contract BurnRedeemCore is ERC165, AdminControl, ReentrancyGuard, IBurnRedeemCore, ICreatorExtensionTokenURI { using Strings for uint256; uint256 public constant BURN_FEE = 690000000000000; uint256 public constant MULTI_BURN_FEE = 990000000000000; string internal constant ARWEAVE_PREFIX = "https://arweave.net/"; string internal constant IPFS_PREFIX = "ipfs://"; uint256 internal constant MAX_UINT_16 = 0xffff; uint256 internal constant MAX_UINT_24 = 0xffffff; uint256 internal constant MAX_UINT_32 = 0xffffffff; uint256 internal constant MAX_UINT_56 = 0xffffffffffffff; uint256 internal constant MAX_UINT_256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; // { creatorContractAddress => { instanceId => BurnRedeem } } mapping(address => mapping(uint256 => BurnRedeem)) internal _burnRedeems; address public manifoldMembershipContract; function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165, AdminControl) returns (bool) { return interfaceId == type(IBurnRedeemCore).interfaceId || interfaceId == type(IERC721Receiver).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(ICreatorExtensionTokenURI).interfaceId || super.supportsInterface(interfaceId); } /** * @notice This extension is shared, not single-creator. So we must ensure * that a burn redeems's initializer is an admin on the creator contract * @param creatorContractAddress the address of the creator contract to check the admin against */ modifier creatorAdminRequired(address creatorContractAddress) { require(IAdminControl(creatorContractAddress).isAdmin(msg.sender), "Wallet is not an admin"); _; } /** * Initialiazes a burn redeem with base parameters */ function _initialize( address creatorContractAddress, uint8 creatorContractVersion, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters ) internal { BurnRedeemLib.initialize(creatorContractAddress, creatorContractVersion, instanceId, _burnRedeems[creatorContractAddress][instanceId], burnRedeemParameters); } /** * Updates a burn redeem with base parameters */ function _update( address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters ) internal { BurnRedeemLib.update(creatorContractAddress, instanceId, _getBurnRedeem(creatorContractAddress, instanceId), burnRedeemParameters); } /** * See {IBurnRedeemCore-getBurnRedeem}. */ function getBurnRedeem(address creatorContractAddress, uint256 instanceId) external override view returns(BurnRedeem memory) { return _getBurnRedeem(creatorContractAddress, instanceId); } /** * Helper to get burn redeem instance */ function _getBurnRedeem(address creatorContractAddress, uint256 instanceId) internal view returns(BurnRedeem storage burnRedeemInstance) { burnRedeemInstance = _burnRedeems[creatorContractAddress][instanceId]; require(burnRedeemInstance.storageProtocol != StorageProtocol.INVALID, "Burn redeem not initialized"); } /** * Helper to get active burn redeem instance */ function _getActiveBurnRedeem(address creatorContractAddress, uint256 instanceId) private view returns(BurnRedeem storage burnRedeemInstance) { burnRedeemInstance = _burnRedeems[creatorContractAddress][instanceId]; require(burnRedeemInstance.storageProtocol != StorageProtocol.INVALID, "Burn redeem not initialized"); require( burnRedeemInstance.startDate <= block.timestamp && (block.timestamp < burnRedeemInstance.endDate || burnRedeemInstance.endDate == 0), "Burn redeem not active" ); } /** * See {IBurnRedeemCore-burnRedeem}. */ function burnRedeem(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens) external payable override nonReentrant { uint256 payableCost = _burnRedeem(msg.value, creatorContractAddress, instanceId, burnRedeemCount, burnTokens, _isActiveMember(msg.sender), true); if (msg.value > payableCost) { _forwardValue(payable(msg.sender), msg.value - payableCost); } } /** * (Batch overload) see {IBurnRedeemCore-burnRedeem}. */ function burnRedeem(address[] calldata creatorContractAddresses, uint256[] calldata instanceIds, uint32[] calldata burnRedeemCounts, BurnToken[][] calldata burnTokens) external payable override nonReentrant { require( creatorContractAddresses.length == instanceIds.length && creatorContractAddresses.length == burnRedeemCounts.length && creatorContractAddresses.length == burnTokens.length, "Invalid calldata" ); bool isActiveMember = _isActiveMember(msg.sender); uint256 msgValueRemaining = msg.value; for (uint256 i; i < creatorContractAddresses.length;) { msgValueRemaining -= _burnRedeem(msgValueRemaining, creatorContractAddresses[i], instanceIds[i], burnRedeemCounts[i], burnTokens[i], isActiveMember, false); unchecked { ++i; } } if (msgValueRemaining != 0) { _forwardValue(payable(msg.sender), msgValueRemaining); } } /** * See {IBurnRedeemCore-airdrop}. */ function airdrop(address creatorContractAddress, uint256 instanceId, address[] calldata recipients, uint32[] calldata amounts) external override creatorAdminRequired(creatorContractAddress) { require(recipients.length == amounts.length, "Invalid calldata"); BurnRedeem storage burnRedeemInstance = _getBurnRedeem(creatorContractAddress, instanceId); uint256 totalAmount; for (uint256 i; i < amounts.length;) { totalAmount += amounts[i] * burnRedeemInstance.redeemAmount; unchecked{ ++i; } } require( totalAmount + burnRedeemInstance.redeemedCount <= MAX_UINT_32, "Invalid amount" ); // Airdrop the tokens for (uint256 i; i < recipients.length;) { _redeem(creatorContractAddress, instanceId, burnRedeemInstance, recipients[i], amounts[i]); unchecked{ ++i; } } BurnRedeemLib.syncTotalSupply(burnRedeemInstance); } function _burnRedeem(uint256 msgValue, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens, bool isActiveMember, bool revertNoneRemaining) private returns (uint256) { BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId); // Get the amount that can be burned burnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount); if (burnRedeemCount == 0) { if (revertNoneRemaining) revert("No tokens available"); return 0; } uint256 payableCost = burnRedeemInstance.cost; uint256 cost = burnRedeemInstance.cost; if (!isActiveMember) { payableCost += _getManifoldFee(burnTokens.length); } if (burnRedeemCount > 1) { payableCost *= burnRedeemCount; cost *= burnRedeemCount; } require(msgValue >= payableCost, "Invalid amount"); if (cost > 0) { _forwardValue(burnRedeemInstance.paymentReceiver, cost); } // Do burn redeem _burnTokens(burnRedeemInstance, burnTokens, burnRedeemCount, msg.sender); _redeem(creatorContractAddress, instanceId, burnRedeemInstance, msg.sender, burnRedeemCount); return payableCost; } /** * @dev See {IBurnRedeemCore-recoverERC721}. */ function recoverERC721(address tokenAddress, uint256 tokenId, address destination) external override adminRequired { IERC721(tokenAddress).transferFrom(address(this), destination, tokenId); } /** * @dev See {IBurnRedeemCore-withdraw}. */ function withdraw(address payable recipient, uint256 amount) external override adminRequired { (bool sent, ) = recipient.call{value: amount}(""); require(sent, "Failed to transfer to recipient"); } /** * @dev See {IBurnRedeemCore-setManifoldMembership}. */ function setMembershipAddress(address addr) external override adminRequired { manifoldMembershipContract = addr; } /** * @dev See {IERC721Receiver-onERC721Received}. */ function onERC721Received( address, address from, uint256 id, bytes calldata data ) external override nonReentrant returns(bytes4) { _onERC721Received(from, id, data); return this.onERC721Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155Received}. */ function onERC1155Received( address, address from, uint256 id, uint256 value, bytes calldata data ) external override nonReentrant returns(bytes4) { // Check calldata is valid require(data.length % 32 == 0, "Invalid data"); address creatorContractAddress; uint256 instanceId; uint32 burnRedeemCount; uint256 burnItemIndex; bytes32[] memory merkleProof; (creatorContractAddress, instanceId, burnRedeemCount, burnItemIndex, merkleProof) = abi.decode(data, (address, uint256, uint32, uint256, bytes32[])); // Do burn redeem _onERC1155Received(from, id, value, creatorContractAddress, instanceId, burnRedeemCount, burnItemIndex, merkleProof); return this.onERC1155Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155BatchReceived}. */ function onERC1155BatchReceived( address, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external override nonReentrant returns(bytes4) { // Check calldata is valid require(data.length % 32 == 0, "Invalid data"); address creatorContractAddress; uint256 instanceId; uint32 burnRedeemCount; BurnToken[] memory burnTokens; (creatorContractAddress, instanceId, burnRedeemCount, burnTokens) = abi.decode(data, (address, uint256, uint32, BurnToken[])); // Do burn redeem _onERC1155BatchReceived(from, ids, values, creatorContractAddress, instanceId, burnRedeemCount, burnTokens); return this.onERC1155BatchReceived.selector; } /** * @notice ERC721 token transfer callback * @param from the person sending the tokens * @param id the token id of the burn token * @param data bytes indicating the target burnRedeem and, optionally, a merkle proof that the token is valid */ function _onERC721Received( address from, uint256 id, bytes calldata data ) private { // Check calldata is valid require(data.length % 32 == 0, "Invalid data"); address creatorContractAddress; uint256 instanceId; uint256 burnItemIndex; bytes32[] memory merkleProof; (creatorContractAddress, instanceId, burnItemIndex, merkleProof) = abi.decode(data, (address, uint256, uint256, bytes32[])); BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId); // A single ERC721 can only be sent in directly for a burn if: // 1. There is no cost to the burn (because no payment can be sent with a transfer) // 2. The burn only requires one NFT (one burnSet element and one count) // 3. They are an active member (because no fee payment can be sent with a transfer) require( burnRedeemInstance.cost == 0 && burnRedeemInstance.burnSet.length == 1 && burnRedeemInstance.burnSet[0].requiredCount == 1 && _isActiveMember(from), "Invalid input" ); uint256 burnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, 1); require(burnRedeemCount != 0, "No tokens available"); // Check that the burn token is valid BurnItem memory burnItem = burnRedeemInstance.burnSet[0].items[burnItemIndex]; // Can only take in one burn item require(burnItem.tokenSpec == TokenSpec.ERC721, "Invalid input"); BurnRedeemLib.validateBurnItem(burnItem, msg.sender, id, merkleProof); // Do burn and redeem _burn(burnItem, address(this), msg.sender, id, 1); _redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, 1); } /** * Execute onERC1155Received burn/redeem */ function _onERC1155Received(address from, uint256 tokenId, uint256 value, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, uint256 burnItemIndex, bytes32[] memory merkleProof) private { BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId); // A single 1155 can only be sent in directly for a burn if: // 1. There is no cost to the burn (because no payment can be sent with a transfer) // 2. The burn only requires one NFT (one burn set element and one required count in the set) // 3. They are an active member (because no fee payment can be sent with a transfer) require( burnRedeemInstance.cost == 0 && burnRedeemInstance.burnSet.length == 1 && burnRedeemInstance.burnSet[0].requiredCount == 1 && _isActiveMember(from), "Invalid input" ); uint32 availableBurnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount); require(availableBurnRedeemCount != 0, "No tokens available"); // Check that the burn token is valid BurnItem memory burnItem = burnRedeemInstance.burnSet[0].items[burnItemIndex]; require(value == burnItem.amount * burnRedeemCount, "Invalid input"); BurnRedeemLib.validateBurnItem(burnItem, msg.sender, tokenId, merkleProof); _burn(burnItem, address(this), msg.sender, tokenId, availableBurnRedeemCount); _redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, availableBurnRedeemCount); // Return excess amount if (availableBurnRedeemCount != burnRedeemCount) { IERC1155(msg.sender).safeTransferFrom(address(this), from, tokenId, (burnRedeemCount - availableBurnRedeemCount) * burnItem.amount, ""); } } /** * Execute onERC1155BatchReceived burn/redeem */ function _onERC1155BatchReceived(address from, uint256[] memory tokenIds, uint256[] memory values, address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] memory burnTokens) private { BurnRedeem storage burnRedeemInstance = _getActiveBurnRedeem(creatorContractAddress, instanceId); // A single 1155 can only be sent in directly for a burn if: // 1. There is no cost to the burn (because no payment can be sent with a transfer) // 2. We have the right data length // 3. They are an active member (because no fee payment can be sent with a transfer) require( burnRedeemInstance.cost == 0 && burnTokens.length == tokenIds.length && _isActiveMember(from), "Invalid input" ); uint32 availableBurnRedeemCount = _getAvailableBurnRedeemCount(burnRedeemInstance.totalSupply, burnRedeemInstance.redeemedCount, burnRedeemInstance.redeemAmount, burnRedeemCount); require(availableBurnRedeemCount != 0, "No tokens available"); // Verify the values match what is needed uint256[] memory returnValues = new uint256[](tokenIds.length); for (uint256 i; i < burnTokens.length;) { BurnToken memory burnToken = burnTokens[i]; BurnItem memory burnItem = burnRedeemInstance.burnSet[burnToken.groupIndex].items[burnToken.itemIndex]; require(burnToken.id == tokenIds[i], "Invalid token"); require(burnItem.amount * burnRedeemCount == values[i], "Invalid amount"); if (availableBurnRedeemCount != burnRedeemCount) { returnValues[i] = values[i] - burnItem.amount * availableBurnRedeemCount; } unchecked { ++i; } } // Do burn redeem _burnTokens(burnRedeemInstance, burnTokens, availableBurnRedeemCount, address(this)); _redeem(creatorContractAddress, instanceId, burnRedeemInstance, from, availableBurnRedeemCount); // Return excess amount if (availableBurnRedeemCount != burnRedeemCount) { IERC1155(msg.sender).safeBatchTransferFrom(address(this), from, tokenIds, returnValues, ""); } } /** * Send funds to receiver */ function _forwardValue(address payable receiver, uint256 amount) private { (bool sent, ) = receiver.call{value: amount}(""); require(sent, "Failed to transfer to recipient"); } /** * Burn all listed tokens and check that the burn set is satisfied */ function _burnTokens(BurnRedeem storage burnRedeemInstance, BurnToken[] memory burnTokens, uint256 burnRedeemCount, address owner) private { // Check that each group in the burn set is satisfied uint256[] memory groupCounts = new uint256[](burnRedeemInstance.burnSet.length); for (uint256 i; i < burnTokens.length;) { BurnToken memory burnToken = burnTokens[i]; BurnItem memory burnItem = burnRedeemInstance.burnSet[burnToken.groupIndex].items[burnToken.itemIndex]; BurnRedeemLib.validateBurnItem(burnItem, burnToken.contractAddress, burnToken.id, burnToken.merkleProof); _burn(burnItem, owner, burnToken.contractAddress, burnToken.id, burnRedeemCount); groupCounts[burnToken.groupIndex] += burnRedeemCount; unchecked { ++i; } } for (uint256 i; i < groupCounts.length;) { require(groupCounts[i] == burnRedeemInstance.burnSet[i].requiredCount * burnRedeemCount, "Invalid number of tokens"); unchecked { ++i; } } } /** * Helper to get the Manifold fee for the sender */ function _getManifoldFee(uint256 burnTokenCount) private pure returns(uint256 fee) { fee = burnTokenCount <= 1 ? BURN_FEE : MULTI_BURN_FEE; } /** * Helper to check if the sender holds an active Manifold membership */ function _isActiveMember(address sender) private view returns(bool) { return manifoldMembershipContract != address(0) && IManifoldMembership(manifoldMembershipContract).isActiveMember(sender); } /** * Helper to get the number of burn redeems the person can accomplish */ function _getAvailableBurnRedeemCount(uint32 totalSupply, uint32 redeemedCount, uint32 redeemAmount, uint32 desiredCount) internal pure returns(uint32 burnRedeemCount) { if (totalSupply == 0) { burnRedeemCount = desiredCount; } else { uint32 remainingCount = (totalSupply - redeemedCount) / redeemAmount; if (remainingCount > desiredCount) { burnRedeemCount = desiredCount; } else { burnRedeemCount = remainingCount; } } } /** * Abstract helper to mint multiple redeem tokens. To be implemented by inheriting contracts. */ function _redeem(address creatorContractAddress, uint256 instanceId, BurnRedeem storage burnRedeemInstance, address to, uint32 count) internal virtual; /** * Helper to burn token */ function _burn(BurnItem memory burnItem, address from, address contractAddress, uint256 tokenId, uint256 burnRedeemCount) private { if (burnItem.tokenSpec == TokenSpec.ERC1155) { uint256 amount = burnItem.amount * burnRedeemCount; if (burnItem.burnSpec == BurnSpec.NONE) { // Send to 0xdEaD to burn if contract doesn't have burn function IERC1155(contractAddress).safeTransferFrom(from, address(0xdEaD), tokenId, amount, ""); } else if (burnItem.burnSpec == BurnSpec.MANIFOLD) { // Burn using the creator core's burn function uint256[] memory tokenIds = new uint256[](1); tokenIds[0] = tokenId; uint256[] memory amounts = new uint256[](1); amounts[0] = amount; Manifold1155(contractAddress).burn(from, tokenIds, amounts); } else if (burnItem.burnSpec == BurnSpec.OPENZEPPELIN) { // Burn using OpenZeppelin's burn function OZBurnable1155(contractAddress).burn(from, tokenId, amount); } else { revert("Invalid burn spec"); } } else if (burnItem.tokenSpec == TokenSpec.ERC721) { require(burnRedeemCount == 1, "Invalid burn count"); if (burnItem.burnSpec == BurnSpec.NONE) { // Send to 0xdEaD to burn if contract doesn't have burn function IERC721(contractAddress).safeTransferFrom(from, address(0xdEaD), tokenId, ""); } else if (burnItem.burnSpec == BurnSpec.MANIFOLD || burnItem.burnSpec == BurnSpec.OPENZEPPELIN) { if (from != address(this)) { // 721 `burn` functions do not have a `from` parameter, so we must verify the owner require(IERC721(contractAddress).ownerOf(tokenId) == from, "Sender is not owner"); } // Burn using the contract's burn function Burnable721(contractAddress).burn(tokenId); } else { revert("Invalid burn spec"); } } else { revert("Invalid token spec"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; ///////////////////////////////////////////////////////////////////////////////////// // // // // // .%(#. // // #(((#%, // // (#(((((#%* // // /#((((((((##* // // (#((((((((((##%. // // ,##(/*/(////((((#%* // // .###(//****/////(((##%, // // (, ,%#((((((///******/////((##%( // // *((, ,##(///////*********////((###%* // // /(((( ,##(//////************/(((((###% // // /(((( ,##((////***************/((((###% // // ((( .###((///*****************((((#### // // . (##((//*******************((((##%* // // (#. .###((/********************((((##%. %. // // ,%(#. .###(/********,,,,,,,*****/(((###%# ((%, // // /%#/(/ /###(//****,,,,,,,,,,,****/((((((##%%%%#((#%. // // /##(//(#. ,###((/****,,,,,,,,,,,,,***/((/(((((((((#####% // // *%##(/////((###((((/***,,,,,,,,,,,,,,,***//((((((((((####%%%/ // // ####(((//////(//////**,,,,,,.....,,,,,,****/(((((//((####%%%% // // .####(((/((((((/////**,,,,,.......,,,,,,,,*****/////(#####%%%% // // .#%###((////(((//***,,,,,,..........,,,,,,,,*****//((#####%%%% // // /%%%###/////*****,,,,,,,..............,,,,,,,****/(((####%%%% // // /%%###(////****,,,,,,..... ......,,,,,,**(((####%%%% // // ,#%###(///****,,,,,.... .....,,,,,***/(/(##%%( // // (####(//****,,.... ....,,,,,***/(#### // // (###(/***,,,... ...,,,,***(##/ // // #. (#((/**,,,,.. ...,,,,*((#, // // ,#(##(((//,,,,.. ...,,,*/(((#((/ // // *#(((///*,,.... ....,*//(((( // // *(///***,.... ...,***//, // // ,//***,... ..,,*, // // // // // ///////////////////////////////////////////////////////////////////////////////////// import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "./IBurnRedeemCore.sol"; /** * @title Burn Redeem Lib * @author manifold.xyz * @notice Library for Burn Redeem shared extensions. */ library BurnRedeemLib { event BurnRedeemInitialized(address indexed creatorContract, uint256 indexed instanceId, address initializer); event BurnRedeemUpdated(address indexed creatorContract, uint256 indexed instanceId); event BurnRedeemMint(address indexed creatorContract, uint256 indexed instanceId, uint256 indexed tokenId, uint32 redeemedCount); /** * Initialiazes a burn redeem with base parameters */ function initialize( address creatorContractAddress, uint8 creatorContractVersion, uint256 instanceId, IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters ) public { // Sanity checks require(burnRedeemInstance.storageProtocol == IBurnRedeemCore.StorageProtocol.INVALID, "Burn redeem already initialized"); _validateParameters(burnRedeemParameters); // Create the burn redeem burnRedeemInstance.contractVersion = creatorContractVersion; _setParameters(burnRedeemInstance, burnRedeemParameters); _setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet); emit BurnRedeemInitialized(creatorContractAddress, instanceId, msg.sender); } /** * Updates a burn redeem with base parameters */ function update( address creatorContractAddress, uint256 instanceId, IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters ) public { // Sanity checks require(burnRedeemInstance.storageProtocol != IBurnRedeemCore.StorageProtocol.INVALID, "Burn redeem not initialized"); _validateParameters(burnRedeemParameters); // The current redeemedCount must be divisible by redeemAmount require(burnRedeemInstance.redeemedCount % burnRedeemParameters.redeemAmount == 0, "Invalid amount"); // Overwrite the existing burnRedeem _setParameters(burnRedeemInstance, burnRedeemParameters); _setBurnGroups(burnRedeemInstance, burnRedeemParameters.burnSet); syncTotalSupply(burnRedeemInstance); emit BurnRedeemUpdated(creatorContractAddress, instanceId); } /** * Helper to update total supply if redeemedCount exceeds totalSupply after airdrop or instance update. */ function syncTotalSupply(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance) public { if ( burnRedeemInstance.totalSupply != 0 && burnRedeemInstance.redeemedCount > burnRedeemInstance.totalSupply ) { burnRedeemInstance.totalSupply = burnRedeemInstance.redeemedCount; } } /* * Helper to validate burn item */ function validateBurnItem(IBurnRedeemCore.BurnItem memory burnItem, address contractAddress, uint256 tokenId, bytes32[] memory merkleProof) public pure { require(contractAddress == burnItem.contractAddress, "Invalid burn token"); if (burnItem.validationType == IBurnRedeemCore.ValidationType.CONTRACT) { return; } else if (burnItem.validationType == IBurnRedeemCore.ValidationType.RANGE) { require(tokenId >= burnItem.minTokenId && tokenId <= burnItem.maxTokenId, "Invalid token ID"); return; } else if (burnItem.validationType == IBurnRedeemCore.ValidationType.MERKLE_TREE) { bytes32 leaf = keccak256(abi.encodePacked(tokenId)); require(MerkleProof.verify(merkleProof, burnItem.merkleRoot, leaf), "Invalid merkle proof"); return; } revert("Invalid burn item"); } /** * Helper to validate the parameters for a burn redeem */ function _validateParameters(IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters) internal pure { require(burnRedeemParameters.storageProtocol != IBurnRedeemCore.StorageProtocol.INVALID, "Storage protocol invalid"); require(burnRedeemParameters.paymentReceiver != address(0), "Payment receiver required"); require(burnRedeemParameters.endDate == 0 || burnRedeemParameters.startDate < burnRedeemParameters.endDate, "startDate after endDate"); require(burnRedeemParameters.totalSupply % burnRedeemParameters.redeemAmount == 0, "Remainder left from totalSupply"); } /** * Helper to set top level properties for a burn redeem */ function _setParameters(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnRedeemParameters calldata burnRedeemParameters) private { burnRedeemInstance.startDate = burnRedeemParameters.startDate; burnRedeemInstance.endDate = burnRedeemParameters.endDate; burnRedeemInstance.redeemAmount = burnRedeemParameters.redeemAmount; burnRedeemInstance.totalSupply = burnRedeemParameters.totalSupply; burnRedeemInstance.storageProtocol = burnRedeemParameters.storageProtocol; burnRedeemInstance.location = burnRedeemParameters.location; burnRedeemInstance.cost = burnRedeemParameters.cost; burnRedeemInstance.paymentReceiver = burnRedeemParameters.paymentReceiver; } /** * Helper to set the burn groups for a burn redeem */ function _setBurnGroups(IBurnRedeemCore.BurnRedeem storage burnRedeemInstance, IBurnRedeemCore.BurnGroup[] calldata burnGroups) private { delete burnRedeemInstance.burnSet; for (uint256 i; i < burnGroups.length;) { burnRedeemInstance.burnSet.push(); IBurnRedeemCore.BurnGroup storage burnGroup = burnRedeemInstance.burnSet[i]; require( burnGroups[i].requiredCount > 0 && burnGroups[i].requiredCount <= burnGroups[i].items.length, "Invalid input" ); burnGroup.requiredCount = burnGroups[i].requiredCount; for (uint256 j; j < burnGroups[i].items.length;) { IBurnRedeemCore.BurnItem memory burnItem = burnGroups[i].items[j]; require( ( (burnItem.tokenSpec == IBurnRedeemCore.TokenSpec.ERC1155 && burnItem.amount > 0) || (burnItem.tokenSpec == IBurnRedeemCore.TokenSpec.ERC721 && burnItem.amount == 0) ) && burnItem.validationType != IBurnRedeemCore.ValidationType.INVALID, "Invalid input"); burnGroup.items.push(burnGroups[i].items[j]); unchecked { ++j; } } unchecked { ++i; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * Burn Redeem Core interface */ interface IBurnRedeemCore is IERC165, IERC721Receiver, IERC1155Receiver { enum StorageProtocol { INVALID, NONE, ARWEAVE, IPFS } /** * @notice the validation type used for a `BurnItem` * CONTRACT any token from a specific contract is valid * RANGE token IDs within a range (inclusive) are valid * MERKLE_TREE various individual token IDs included in a merkle tree are valid */ enum ValidationType { INVALID, CONTRACT, RANGE, MERKLE_TREE } enum TokenSpec { INVALID, ERC721, ERC1155 } enum BurnSpec { NONE, MANIFOLD, OPENZEPPELIN } /** * @notice a `BurnItem` indicates which tokens are eligible to be burned * @param validationType which type of validation used to check that the burn item is * satisfied * @param tokenSpec whether the token is an ERC721 or ERC1155 * @param burnSpec whether the contract for a token has a `burn` function and, if so, * what interface * @param amount (only for ERC1155 tokens) the amount (value) required to burn * @param minTokenId (only for RANGE validation) the minimum valid token ID * @param maxTokenId (only for RANGE validation) the maximum valid token ID * @param merkleRoot (only for MERKLE_TREE validation) the root of the merkle tree of * valid token IDs */ struct BurnItem { ValidationType validationType; address contractAddress; TokenSpec tokenSpec; BurnSpec burnSpec; uint72 amount; uint256 minTokenId; uint256 maxTokenId; bytes32 merkleRoot; } /** * @notice a `BurnGroup` is a group of valid `BurnItem`s * @param requiredCount the number of `BurnItem`s (0 < requiredCount <= items.length) that * need to be included in a burn * @param items the list of `BurnItem`s */ struct BurnGroup { uint256 requiredCount; BurnItem[] items; } /** * @notice parameters for burn redeem intialization/updates * @param paymentReceiver the address to forward proceeds from paid burn redeems * @param storageProtocol the type of storage used for the redeem token URIs * @param redeemAmount the number of redeem tokens to mint for each burn redeem * @param totalSupply the maximum number of redeem tokens to mint (0 for unlimited) * @param startDate the starting time for the burn redeem (0 for immediately) * @param endDate the end time for the burn redeem (0 for never) * @param cost the cost for each burn redeem * @param location used to construct the token URI (Arweave hash, full URI, etc.) * @param burnSet a list of `BurnGroup`s that must each be satisfied for a burn redeem */ struct BurnRedeemParameters { address payable paymentReceiver; StorageProtocol storageProtocol; uint16 redeemAmount; uint32 totalSupply; uint48 startDate; uint48 endDate; uint160 cost; string location; BurnGroup[] burnSet; } struct BurnRedeem { address payable paymentReceiver; StorageProtocol storageProtocol; uint32 redeemedCount; uint16 redeemAmount; uint32 totalSupply; uint8 contractVersion; uint48 startDate; uint48 endDate; uint160 cost; string location; BurnGroup[] burnSet; } /** * @notice a pointer to a `BurnItem` in a `BurnGroup` used in calls to `burnRedeem` * @param groupIndex the index of the `BurnGroup` in `BurnRedeem.burnSet` * @param itemIndex the index of the `BurnItem` in `BurnGroup.items` * @param contractAddress the address of the contract for the token * @param id the token ID * @param merkleProof the merkle proof for the token ID (only for MERKLE_TREE validation) */ struct BurnToken { uint48 groupIndex; uint48 itemIndex; address contractAddress; uint256 id; bytes32[] merkleProof; } /** * @notice get a burn redeem corresponding to a creator contract and instanceId * @param creatorContractAddress the address of the creator contract * @param instanceId the instanceId of the burn redeem for the creator contract * @return BurnRedeem the burn redeem object */ function getBurnRedeem(address creatorContractAddress, uint256 instanceId) external view returns(BurnRedeem memory); /** * @notice get a burn redeem corresponding to a creator contract and tokenId * @param creatorContractAddress the address of the creator contract * @param tokenId the token to retrieve the burn redeem for * @return the burn redeem instanceId and burn redeem object */ function getBurnRedeemForToken(address creatorContractAddress, uint256 tokenId) external view returns(uint256, BurnRedeem memory); /** * @notice burn tokens and mint a redeem token * @param creatorContractAddress the address of the creator contract * @param instanceId the instanceId of the burn redeem for the creator contract * @param burnRedeemCount the number of burn redeems we want to do * @param burnTokens the tokens to burn with pointers to the corresponding BurnItem requirement */ function burnRedeem(address creatorContractAddress, uint256 instanceId, uint32 burnRedeemCount, BurnToken[] calldata burnTokens) external payable; /** * @notice burn tokens and mint redeem tokens multiple times in a single transaction * @param creatorContractAddresses the addresses of the creator contracts * @param instanceIds the instanceIds of the burn redeems for the corresponding creator contract * @param burnRedeemCounts the burn redeem counts for each burn * @param burnTokens the tokens to burn for each burn redeem with pointers to the corresponding BurnItem requirement */ function burnRedeem(address[] calldata creatorContractAddresses, uint256[] calldata instanceIds, uint32[] calldata burnRedeemCounts, BurnToken[][] calldata burnTokens) external payable; /** * @notice allow admin to airdrop arbitrary tokens * @param creatorContractAddress the creator contract to mint tokens for * @param instanceId the instanceId of the burn redeem for the creator contract * @param recipients addresses to airdrop to * @param amounts number of redeems to perform for each address in recipients */ function airdrop(address creatorContractAddress, uint256 instanceId, address[] calldata recipients, uint32[] calldata amounts) external; /** * @notice recover a token that was sent to the contract without safeTransferFrom * @param tokenAddress the address of the token contract * @param tokenId the id of the token * @param destination the address to send the token to */ function recoverERC721(address tokenAddress, uint256 tokenId, address destination) external; /** * @notice withdraw Manifold fee proceeds from the contract * @param recipient recepient of the funds * @param amount amount to withdraw in Wei */ function withdraw(address payable recipient, uint256 amount) external; /** * @notice set the Manifold Membership contract address * @param addr the address of the Manifold Membership contract */ function setMembershipAddress(address addr) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "./IBurnRedeemCore.sol"; interface IERC721BurnRedeem is IBurnRedeemCore { struct RedeemToken { uint224 instanceId; uint32 mintNumber; } /** * @notice initialize a new burn redeem, emit initialize event * @param creatorContractAddress the creator contract the burn will mint redeem tokens for * @param instanceId the instanceId of the burnRedeem for the creator contract * @param burnRedeemParameters the parameters which will affect the minting behavior of the burn redeem * @param identicalTokenURI whether or not the tokenURI is identical */ function initializeBurnRedeem(address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI) external; /** * @notice update an existing burn redeem * @param creatorContractAddress the creator contract corresponding to the burn redeem * @param instanceId the instanceId of the burnRedeem for the creator contract * @param burnRedeemParameters the parameters which will affect the minting behavior of the burn redeem * @param identicalTokenURI whether or not the tokenURI is identical */ function updateBurnRedeem(address creatorContractAddress, uint256 instanceId, BurnRedeemParameters calldata burnRedeemParameters, bool identicalTokenURI) external; /** * @notice update an existing burn redeem * @param creatorContractAddress the creator contract corresponding to the burn redeem * @param instanceId the instanceId of the burnRedeem for the creator contract * @param storageProtocol the storage protocol for the metadata * @param location the location of the metadata * @param identicalTokenURI whether or not the URI's are supposed to be identical */ function updateTokenURI(address creatorContractAddress, uint256 instanceId, StorageProtocol storageProtocol, string calldata location, bool identicalTokenURI) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface Burnable721 { function burn(uint256 tokenId) external; } interface OZBurnable1155 { function burn(address account, uint256 id, uint256 value) external; } interface Manifold1155 { function burn(address account, uint256[] memory tokenIds, uint256[] memory amounts) external; }
{ "optimizer": { "enabled": true, "runs": 150 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/manifold/burnredeem/BurnRedeemLib.sol": { "BurnRedeemLib": "0xf56dfc2f506f3fbe85d33fd70653d7bac0907d56" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminRevoked","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"},{"inputs":[],"name":"BURN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTI_BURN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint32[]","name":"amounts","type":"uint32[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"approveAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"creatorContractAddresses","type":"address[]"},{"internalType":"uint256[]","name":"instanceIds","type":"uint256[]"},{"internalType":"uint32[]","name":"burnRedeemCounts","type":"uint32[]"},{"components":[{"internalType":"uint48","name":"groupIndex","type":"uint48"},{"internalType":"uint48","name":"itemIndex","type":"uint48"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct IBurnRedeemCore.BurnToken[][]","name":"burnTokens","type":"tuple[][]"}],"name":"burnRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"uint32","name":"burnRedeemCount","type":"uint32"},{"components":[{"internalType":"uint48","name":"groupIndex","type":"uint48"},{"internalType":"uint48","name":"itemIndex","type":"uint48"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct IBurnRedeemCore.BurnToken[]","name":"burnTokens","type":"tuple[]"}],"name":"burnRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAdmins","outputs":[{"internalType":"address[]","name":"admins","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"}],"name":"getBurnRedeem","outputs":[{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint32","name":"redeemedCount","type":"uint32"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint8","name":"contractVersion","type":"uint8"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBurnRedeemForToken","outputs":[{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint32","name":"redeemedCount","type":"uint32"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint8","name":"contractVersion","type":"uint8"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeem","name":"burnRedeem","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeemParameters","name":"burnRedeemParameters","type":"tuple"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"initializeBurnRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manifoldMembershipContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"destination","type":"address"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"revokeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setMembershipAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentReceiver","type":"address"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"uint16","name":"redeemAmount","type":"uint16"},{"internalType":"uint32","name":"totalSupply","type":"uint32"},{"internalType":"uint48","name":"startDate","type":"uint48"},{"internalType":"uint48","name":"endDate","type":"uint48"},{"internalType":"uint160","name":"cost","type":"uint160"},{"internalType":"string","name":"location","type":"string"},{"components":[{"internalType":"uint256","name":"requiredCount","type":"uint256"},{"components":[{"internalType":"enum IBurnRedeemCore.ValidationType","name":"validationType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"enum IBurnRedeemCore.TokenSpec","name":"tokenSpec","type":"uint8"},{"internalType":"enum IBurnRedeemCore.BurnSpec","name":"burnSpec","type":"uint8"},{"internalType":"uint72","name":"amount","type":"uint72"},{"internalType":"uint256","name":"minTokenId","type":"uint256"},{"internalType":"uint256","name":"maxTokenId","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct IBurnRedeemCore.BurnItem[]","name":"items","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnGroup[]","name":"burnSet","type":"tuple[]"}],"internalType":"struct IBurnRedeemCore.BurnRedeemParameters","name":"burnRedeemParameters","type":"tuple"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"updateBurnRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorContractAddress","type":"address"},{"internalType":"uint256","name":"instanceId","type":"uint256"},{"internalType":"enum IBurnRedeemCore.StorageProtocol","name":"storageProtocol","type":"uint8"},{"internalType":"string","name":"location","type":"string"},{"internalType":"bool","name":"identicalTokenURI","type":"bool"}],"name":"updateTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d3362000028565b600160035562000078565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b615c6480620000886000396000f3fe6080604052600436106101615760003560e01c80637ab39392116100c1578063c9dad6961161007a578063c9dad6961461040a578063cc7ac3f71461041d578063e9dc63751461043d578063f0e9fcd11461046a578063f23a6e611461048a578063f2fde38b146104aa578063f3fef3a3146104ca57600080fd5b80637ab39392146103445780638da5cb5b1461036457806395bc312b14610382578063b058d2f81461039d578063bc197c81146103ca578063c2065c10146103ea57600080fd5b80633f25c9961161011e5780633f25c9961461025857806341d29f071461027857806342b54fee146102a6578063480df058146102b957806350d10839146102e25780636d73e6691461030f578063715018a61461032f57600080fd5b806301ffc9a714610166578063150b7a021461019b57806324d7806c146101d457806327a99a14146101f45780632d3456701461021657806331ae450b14610236575b600080fd5b34801561017257600080fd5b5061018661018136600461445b565b6104ea565b60405190151581526020015b60405180910390f35b3480156101a757600080fd5b506101bb6101b63660046144e2565b610515565b6040516001600160e01b03199091168152602001610192565b3480156101e057600080fd5b506101866101ef366004614554565b61056a565b34801561020057600080fd5b5061021461020f36600461457f565b6105a3565b005b34801561022257600080fd5b50610214610231366004614554565b610674565b34801561024257600080fd5b5061024b6106d2565b60405161019291906145f0565b34801561026457600080fd5b5061021461027336600461465a565b610780565b34801561028457600080fd5b506102986102933660046146de565b6108b4565b6040516101929291906149c3565b6102146102b4366004614a20565b610d2e565b3480156102c557600080fd5b506102d46602738d24e5200081565b604051908152602001610192565b3480156102ee57600080fd5b50600554610302906001600160a01b031681565b6040516101929190614ae3565b34801561031b57600080fd5b5061021461032a366004614554565b610e93565b34801561033b57600080fd5b50610214610eeb565b34801561035057600080fd5b5061021461035f366004614554565b610eff565b34801561037057600080fd5b506000546001600160a01b0316610302565b34801561038e57600080fd5b506102d4660384665653e00081565b3480156103a957600080fd5b506103bd6103b83660046146de565b610f6b565b6040516101929190614af7565b3480156103d657600080fd5b506101bb6103e5366004614b0a565b6112a6565b3480156103f657600080fd5b50610214610405366004614bb4565b6113bc565b610214610418366004614c53565b611610565b34801561042957600080fd5b5061021461043836600461457f565b61167c565b34801561044957600080fd5b5061045d6104583660046146de565b61185c565b6040516101929190614cb2565b34801561047657600080fd5b50610214610485366004614cc5565b611e16565b34801561049657600080fd5b506101bb6104a5366004614d07565b611ecd565b3480156104b657600080fd5b506102146104c5366004614554565b611f6a565b3480156104d657600080fd5b506102146104e53660046146de565b611fe0565b60006001600160e01b0319821663d4f6907560e01b148061050f575061050f826120d2565b92915050565b60006002600354036105425760405162461bcd60e51b815260040161053990614d7b565b60405180910390fd5b600260035561055385858585612148565b50630a85bd0160e11b600160035595945050505050565b6000816001600160a01b03166105886000546001600160a01b031690565b6001600160a01b0316148061050f575061050f600183612482565b604051630935e01b60e21b815284906001600160a01b038216906324d7806c906105d1903390600401614ae3565b602060405180830381865afa1580156105ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106129190614db2565b61062e5760405162461bcd60e51b815260040161053990614dcf565b6106398585856124a7565b506001600160a01b0393909316600090815260076020908152604080832094835293905291909120805460ff19169215159290921790915550565b61067c612519565b610687600182612482565b156106cf5760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36106cd600182612573565b505b50565b60606106de6001612588565b6001600160401b038111156106f5576106f5614dff565b60405190808252806020026020018201604052801561071e578160200160208202803683370190505b50905060005b61072e6001612588565b81101561077c57610740600182612592565b82828151811061075257610752614e15565b6001600160a01b03909216602092830291909101909101528061077481614e41565b915050610724565b5090565b604051630935e01b60e21b815286906001600160a01b038216906324d7806c906107ae903390600401614ae3565b602060405180830381865afa1580156107cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ef9190614db2565b61080b5760405162461bcd60e51b815260040161053990614dcf565b6000610817888861259e565b80549091508690829060ff60a01b1916600160a01b83600381111561083e5761083e61470a565b021790555060028101610852858783614eda565b506001600160a01b03881660008181526007602090815260408083208b8452909152808220805460ff1916871515179055518992917fc4487c68aeaaea10bc0e1e6408497e8b1eedeb6aeece8711fdb0da6b6c288dab91a35050505050505050565b60006108be6143fc565b6001600160a01b038416600090815260066020908152604080832086845282528083208151808301909252546001600160e01b038116808352600160e01b90910463ffffffff169282019290925291036109935760405163b4b5b48f60e01b8152600481018590526000906001600160a01b0387169063b4b5b48f90602401602060405180830381865afa15801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190614f99565b60181c66ffffffffffffff1693506109a19050565b80516001600160e01b031692505b826000036109e85760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610539565b6001600160a01b0385811660009081526004602090815260408083208784528252918290208251610160810190935280549384168352919290830190600160a01b900460ff166003811115610a3f57610a3f61470a565b6003811115610a5057610a5061470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e082015260028201805461010090920191610ae090614e5a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b0c90614e5a565b8015610b595780601f10610b2e57610100808354040283529160200191610b59565b820191906000526020600020905b815481529060010190602001808311610b3c57829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015610d1c57838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015610d0557600084815260209020604080516101008101909152600484029091018054829060ff166003811115610c1557610c1561470a565b6003811115610c2657610c2661470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115610c5e57610c5e61470a565b6002811115610c6f57610c6f61470a565b81528154602090910190600160b01b900460ff166002811115610c9457610c9461470a565b6002811115610ca557610ca561470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190610bd9565b505050508152505081526020019060010190610b87565b50505050815250509150509250929050565b600260035403610d505760405162461bcd60e51b815260040161053990614d7b565b60026003558685148015610d6357508683145b8015610d6e57508681145b610dad5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c6461746160801b6044820152606401610539565b6000610db83361262c565b90503460005b89811015610e7157610e5d828c8c84818110610ddc57610ddc614e15565b9050602002016020810190610df19190614554565b8b8b85818110610e0357610e03614e15565b905060200201358a8a86818110610e1c57610e1c614e15565b9050602002016020810190610e319190614fc5565b898987818110610e4357610e43614e15565b9050602002810190610e559190614fe0565b8960006126b5565b610e679083615029565b9150600101610dbe565b508015610e8257610e82338261202a565b505060016003555050505050505050565b610e9b612519565b610ea6600182612482565b6106cf5760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36106cd600182612808565b610ef3612519565b610efd600061281d565b565b33610f126000546001600160a01b031690565b6001600160a01b03161480610f2d5750610f2d600133612482565b610f495760405162461bcd60e51b81526004016105399061503c565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b610f736143fc565b610f7d838361259e565b60408051610160810190915281546001600160a01b03811682529091906020830190600160a01b900460ff166003811115610fba57610fba61470a565b6003811115610fcb57610fcb61470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e08201526002820180546101009092019161105b90614e5a565b80601f016020809104026020016040519081016040528092919081815260200182805461108790614e5a565b80156110d45780601f106110a9576101008083540402835291602001916110d4565b820191906000526020600020905b8154815290600101906020018083116110b757829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b8282101561129757838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b8282101561128057600084815260209020604080516101008101909152600484029091018054829060ff1660038111156111905761119061470a565b60038111156111a1576111a161470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156111d9576111d961470a565b60028111156111ea576111ea61470a565b81528154602090910190600160b01b900460ff16600281111561120f5761120f61470a565b60028111156112205761122061470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190611154565b505050508152505081526020019060010190611102565b50505091525090949350505050565b60006002600354036112ca5760405162461bcd60e51b815260040161053990614d7b565b60026003556112da602083615096565b156112f75760405162461bcd60e51b8152600401610539906150aa565b600080806060611309868801886152b1565b8094508195508296508397505050505061139e8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508a92508991508890508761286d565b505060016003555063bc197c8160e01b9a9950505050505050505050565b604051630935e01b60e21b815286906001600160a01b038216906324d7806c906113ea903390600401614ae3565b602060405180830381865afa158015611407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142b9190614db2565b6114475760405162461bcd60e51b815260040161053990614dcf565b8382146114895760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c6461746160801b6044820152606401610539565b6000611495888861259e565b90506000805b848110156114fb578254600160c81b900461ffff168686838181106114c2576114c2614e15565b90506020020160208101906114d79190614fc5565b6114e1919061532e565b6114f19063ffffffff1683615356565b915060010161149b565b50815463ffffffff9061151790600160a81b9004821683615356565b11156115355760405162461bcd60e51b815260040161053990615369565b60005b868110156115a1576115998a8a858b8b8681811061155857611558614e15565b905060200201602081019061156d9190614554565b8a8a8781811061157f5761157f614e15565b90506020020160208101906115949190614fc5565b612cb8565b600101611538565b5060405163e5c986cd60e01b81526004810183905273f56dfc2f506f3fbe85d33fd70653d7bac0907d569063e5c986cd9060240160006040518083038186803b1580156115ed57600080fd5b505af4158015611601573d6000803e3d6000fd5b50505050505050505050505050565b6002600354036116325760405162461bcd60e51b815260040161053990614d7b565b6002600355600061165234878787878761164b3361262c565b60016126b5565b90508034111561166f5761166f3361166a8334615029565b61202a565b5050600160035550505050565b604051630935e01b60e21b815284906001600160a01b038216906324d7806c906116aa903390600401614ae3565b602060405180830381865afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116eb9190614db2565b6117075760405162461bcd60e51b815260040161053990614dcf565b60008411801561171e575066ffffffffffffff8411155b61175f5760405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a59081a5b9cdd185b98d9525960721b6044820152606401610539565b6000856001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156117bb575060408051601f3d908101601f191682019092526117b891810190615391565b60015b156118145760ff8111156118115760405162461bcd60e51b815260206004820152601c60248201527f556e737570706f7274656420636f6e74726163742076657273696f6e000000006044820152606401610539565b90505b61182086828787613305565b50506001600160a01b0393909316600090815260076020908152604080832094835293905291909120805460ff19169215159290921790915550565b6001600160a01b03821660009081526006602090815260408083208484528252918290208251808401909352546001600160e01b0381168352600160e01b900463ffffffff16908201526060906118b16143fc565b60008083600001516001600160e01b031660000361199b5760405163b4b5b48f60e01b8152600481018790526000906001600160a01b0389169063b4b5b48f90602401602060405180830381865afa158015611911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119359190614f99565b66ffffffffffffff601882901c1692509050600082900361198f5760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610539565b62ffffff1691506119b5565b50508151602083015163ffffffff16906001600160e01b03165b6001600160a01b0387811660009081526004602090815260408083208584528252918290208251610160810190935280549384168352919290830190600160a01b900460ff166003811115611a0c57611a0c61470a565b6003811115611a1d57611a1d61470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e082015260028201805461010090920191611aad90614e5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad990614e5a565b8015611b265780601f10611afb57610100808354040283529160200191611b26565b820191906000526020600020905b815481529060010190602001808311611b0957829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015611ce957838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015611cd257600084815260209020604080516101008101909152600484029091018054829060ff166003811115611be257611be261470a565b6003811115611bf357611bf361470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115611c2b57611c2b61470a565b6002811115611c3c57611c3c61470a565b81528154602090910190600160b01b900460ff166002811115611c6157611c6161470a565b6002811115611c7257611c7261470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190611ba6565b505050508152505081526020019060010190611b54565b50505091525050604080516020810190915260008152909350600284602001516003811115611d1a57611d1a61470a565b03611d50575060408051808201909152601481527368747470733a2f2f617277656176652e6e65742f60601b6020820152611d8d565b600384602001516003811115611d6857611d6861470a565b03611d8d5750604080518082019091526007815266697066733a2f2f60c81b60208201525b610120840151604051611da49183916020016153aa565b60408051601f198184030181529181526001600160a01b038a166000908152600760209081528282208683529052205490965060ff16611e0b5785611de88461339a565b604051602001611df99291906153d9565b60405160208183030381529060405295505b505050505092915050565b33611e296000546001600160a01b031690565b6001600160a01b03161480611e445750611e44600133612482565b611e605760405162461bcd60e51b81526004016105399061503c565b6040516323b872dd60e01b81523060048201526001600160a01b038281166024830152604482018490528416906323b872dd90606401600060405180830381600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b50505050505050565b6000600260035403611ef15760405162461bcd60e51b815260040161053990614d7b565b6002600355611f01602083615096565b15611f1e5760405162461bcd60e51b8152600401610539906150aa565b60008080806060611f3187890189615415565b939850919650945092509050611f4d8b8b8b88888888886134a2565b505060016003555063f23a6e6160e01b9998505050505050505050565b611f72612519565b6001600160a01b038116611fd75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610539565b6106cf8161281d565b33611ff36000546001600160a01b031690565b6001600160a01b0316148061200e575061200e600133612482565b61202a5760405162461bcd60e51b81526004016105399061503c565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612077576040519150601f19603f3d011682016040523d82523d6000602084013e61207c565b606091505b50509050806120cd5760405162461bcd60e51b815260206004820152601f60248201527f4661696c656420746f207472616e7366657220746f20726563697069656e74006044820152606401610539565b505050565b60006001600160e01b0319821663c147147760e01b148061210357506001600160e01b03198216630a85bd0160e11b145b8061211e57506001600160e01b03198216630271189760e51b145b8061213957506001600160e01b0319821663e9dc637560e01b145b8061050f575061050f8261386b565b612153602082615096565b156121705760405162461bcd60e51b8152600401610539906150aa565b60008080606061218285870187615488565b92965090945092509050600061219885856138a0565b6001810154909150600160601b90046001600160a01b03161580156121c1575060038101546001145b80156121f45750806003016000815481106121de576121de614e15565b9060005260206000209060020201600001546001145b801561220457506122048961262c565b6122205760405162461bcd60e51b8152600401610539906154de565b80546000906122569063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b9091041660016139be565b63ffffffff1690508060000361227e5760405162461bcd60e51b815260040161053990615505565b60008260030160008154811061229657612296614e15565b906000526020600020906002020160010185815481106122b8576122b8614e15565b600091825260209091206040805161010081019091526004909202018054829060ff1660038111156122ec576122ec61470a565b60038111156122fd576122fd61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156123355761233561470a565b60028111156123465761234661470a565b81528154602090910190600160b01b900460ff16600281111561236b5761236b61470a565b600281111561237c5761237c61470a565b81528154600160b81b90046001600160481b03166020820152600180830154604083015260028301546060830152600390920154608090910152909150816040015160028111156123cf576123cf61470a565b146123ec5760405162461bcd60e51b8152600401610539906154de565b604051630e5597a560e31b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56906372acbd289061242990849033908f908a90600401615532565b60006040518083038186803b15801561244157600080fd5b505af4158015612455573d6000803e3d6000fd5b505050506124678130338d6001613a17565b6124758787858e6001612cb8565b5050505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b73f56dfc2f506f3fbe85d33fd70653d7bac0907d5663b40609bf84846124cd878761259e565b856040518563ffffffff1660e01b81526004016124ed949392919061590a565b60006040518083038186803b15801561250557600080fd5b505af4158015611ec4573d6000803e3d6000fd5b6000546001600160a01b03163314610efd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610539565b60006124a0836001600160a01b038416613f07565b600061050f825490565b60006124a08383614001565b6001600160a01b03821660009081526004602090815260408083208484529091528120908154600160a01b900460ff1660038111156125df576125df61470a565b0361050f5760405162461bcd60e51b815260206004820152601b60248201527f4275726e2072656465656d206e6f7420696e697469616c697a656400000000006044820152606401610539565b6005546000906001600160a01b03161580159061050f57506005546040516345ecd02f60e01b81526001600160a01b03909116906345ecd02f90612674908590600401614ae3565b602060405180830381865afa158015612691573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050f9190614db2565b6000806126c289896138a0565b80549091506126f79063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b909104168a6139be565b96508663ffffffff1660000361272f5782156127255760405162461bcd60e51b815260040161053990615505565b60009150506127fc565b6001810154600160601b90046001600160a01b03168085612760576127538761402b565b61275d9083615356565b91505b60018963ffffffff1611156127945761277f63ffffffff8a1683615937565b915061279163ffffffff8a1682615937565b90505b818c10156127b45760405162461bcd60e51b815260040161053990615369565b80156127cf5782546127cf906001600160a01b03168261202a565b6127ea836127dd898b61594e565b8b63ffffffff1633614051565b6127f78b8b85338d612cb8565b509150505b98975050505050505050565b60006124a0836001600160a01b0384166143ad565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061287985856138a0565b6001810154909150600160601b90046001600160a01b031615801561289f575086518251145b80156128af57506128af8861262c565b6128cb5760405162461bcd60e51b8152600401610539906154de565b80546000906129009063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b90910416876139be565b90508063ffffffff166000036129285760405162461bcd60e51b815260040161053990615505565b600088516001600160401b0381111561294357612943614dff565b60405190808252806020026020018201604052801561296c578160200160208202803683370190505b50905060005b8451811015612c1d57600085828151811061298f5761298f614e15565b60200260200101519050600085600301826000015165ffffffffffff16815481106129bc576129bc614e15565b9060005260206000209060020201600101826020015165ffffffffffff16815481106129ea576129ea614e15565b600091825260209091206040805161010081019091526004909202018054829060ff166003811115612a1e57612a1e61470a565b6003811115612a2f57612a2f61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115612a6757612a6761470a565b6002811115612a7857612a7861470a565b81528154602090910190600160b01b900460ff166002811115612a9d57612a9d61470a565b6002811115612aae57612aae61470a565b81528154600160b81b90046001600160481b0316602082015260018201546040820152600282015460608201526003909101546080909101528c519091508c9084908110612afe57612afe614e15565b6020026020010151826060015114612b485760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610539565b8a8381518110612b5a57612b5a614e15565b60200260200101518863ffffffff168260800151612b78919061595b565b6001600160481b031614612b9e5760405162461bcd60e51b815260040161053990615369565b8763ffffffff168563ffffffff1614612c13578463ffffffff168160800151612bc7919061595b565b6001600160481b03168b8481518110612be257612be2614e15565b6020026020010151612bf49190615029565b848481518110612c0657612c06614e15565b6020026020010181815250505b5050600101612972565b50612c3083858463ffffffff1630614051565b612c3d8787858d86612cb8565b8463ffffffff168263ffffffff1614612cac57604051631759616b60e11b81523390632eb2c2d690612c799030908e908e9087906004016159b9565b600060405180830381600087803b158015612c9357600080fd5b505af1158015612ca7573d6000803e3d6000fd5b505050505b50505050505050505050565b8254600160c81b900461ffff166001148015612cda57508063ffffffff166001145b15612ef05782548390601590612cfc90600160a81b900463ffffffff16615a14565b91906101000a81548163ffffffff021916908363ffffffff1602179055506000600384600001601f9054906101000a900460ff1660ff1610612dd357835460405163d397371960e01b81526001600160a01b038581166004830152600160a81b90920463ffffffff16601888901b66ffffffff0000001617602482018190529188169063d3973719906044016020604051808303816000875af1158015612da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dcb9190615391565b915050612ea7565b604051630525194b60e31b81526001600160a01b03871690632928ca5890612dff908690600401614ae3565b6020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e429190615391565b6040805180820182526001600160e01b038089168252875463ffffffff600160a81b909104811660208085019182526001600160a01b038d16600090815260068252868120888252909152949094209251935116600160e01b02921691909117905590505b60405160018152819086906001600160a01b038916907fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe09060200160405180910390a4506132fe565b8254600090612f0b908390600160c81b900461ffff1661532e565b63ffffffff16905061ffff811115612f355760405162461bcd60e51b8152600401610539906154de565b8354600090612f5290600160a81b900463ffffffff166001615a37565b855463ffffffff918216925083918791601591612f79918591600160a81b90910416615a37565b92506101000a81548163ffffffff021916908363ffffffff160217905550600385600001601f9054906101000a900460ff1660ff161061315f576000826001600160401b03811115612fcd57612fcd614dff565b604051908082528060200260200182016040528015612ff6578160200160208202803683370190505b50905060005b838110156130605761300e8184615356565b62ffffff1660188966ffffffffffffff16901b1766ffffffffffffff1682828151811061303d5761303d614e15565b69ffffffffffffffffffff90921660209283029190910190910152600101612ffc565b5060405163213c198760e11b81526000906001600160a01b038a1690634278330e906130929089908690600401615a54565b6000604051808303816000875af11580156130b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130d99190810190615ab6565b905060005b84811015613157578181815181106130f8576130f8614e15565b6020026020010151898b6001600160a01b03167fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe06001604051613147919063ffffffff91909116815260200190565b60405180910390a46001016130de565b505050611ec4565b60405163e00aab4b60e01b81526001600160a01b03858116600483015261ffff841660248301526000919089169063e00aab4b906044016000604051808303816000875af11580156131b5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131dd9190810190615ab6565b905060005b838110156132f9576040518060400160405280896001600160e01b0316815260200182856132109190615356565b63ffffffff1690526001600160a01b038a166000908152600660205260408120845190919085908590811061324757613247614e15565b6020908102919091018101518252818101929092526040016000208251929091015163ffffffff16600160e01b026001600160e01b03909216919091179055815182908290811061329a5761329a614e15565b6020026020010151888a6001600160a01b03167fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe060016040516132e9919063ffffffff91909116815260200190565b60405180910390a46001016131e2565b505050505b5050505050565b6001600160a01b03841660009081526004602081815260408084208685529091529182902091516314765c6b60e01b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56926314765c6b9261336492899289928992899101615b3b565b60006040518083038186803b15801561337c57600080fd5b505af4158015613390573d6000803e3d6000fd5b5050505050505050565b6060816000036133c15750506040805180820190915260018152600360fc1b602082015290565b8160005b81156133eb57806133d581614e41565b91506133e49050600a83615b71565b91506133c5565b6000816001600160401b0381111561340557613405614dff565b6040519080825280601f01601f19166020018201604052801561342f576020820181803683370190505b5090505b841561349a57613444600183615029565b9150613451600a86615096565b61345c906030615356565b60f81b81838151811061347157613471614e15565b60200101906001600160f81b031916908160001a905350613493600a86615b71565b9450613433565b949350505050565b60006134ae86866138a0565b6001810154909150600160601b90046001600160a01b03161580156134d7575060038101546001145b801561350a5750806003016000815481106134f4576134f4614e15565b9060005260206000209060020201600001546001145b801561351a575061351a8961262c565b6135365760405162461bcd60e51b8152600401610539906154de565b805460009061356b9063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b90910416886139be565b90508063ffffffff166000036135935760405162461bcd60e51b815260040161053990615505565b6000826003016000815481106135ab576135ab614e15565b906000526020600020906002020160010185815481106135cd576135cd614e15565b600091825260209091206040805161010081019091526004909202018054829060ff1660038111156136015761360161470a565b60038111156136125761361261470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff16600281111561364a5761364a61470a565b600281111561365b5761365b61470a565b81528154602090910190600160b01b900460ff1660028111156136805761368061470a565b60028111156136915761369161470a565b81528154600160b81b90046001600160481b0316602082015260018201546040820152600282015460608201526003909101546080918201528101519091506136e19063ffffffff88169061595b565b6001600160481b031689146137085760405162461bcd60e51b8152600401610539906154de565b604051630e5597a560e31b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56906372acbd289061374590849033908f908a90600401615532565b60006040518083038186803b15801561375d57600080fd5b505af4158015613771573d6000803e3d6000fd5b505050506137888130338d8663ffffffff16613a17565b6137958888858e86612cb8565b8563ffffffff168263ffffffff161461247557336001600160a01b031663f242432a308d8d8560800151878c6137cb9190615b85565b63ffffffff166137db919061595b565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015293909216602484015260448301526001600160481b0316606482015260a06084820152600060a482015260c401600060405180830381600087803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160e01b03198216632a9f3abf60e11b148061050f57506301ffc9a760e01b6001600160e01b031983161461050f565b6001600160a01b03821660009081526004602090815260408083208484529091528120908154600160a01b900460ff1660038111156138e1576138e161470a565b0361392e5760405162461bcd60e51b815260206004820152601b60248201527f4275726e2072656465656d206e6f7420696e697469616c697a656400000000006044820152606401610539565b60018101544265ffffffffffff9091161180159061397957506001810154600160301b900465ffffffffffff1642108061397957506001810154600160301b900465ffffffffffff16155b61050f5760405162461bcd60e51b81526020600482015260166024820152754275726e2072656465656d206e6f742061637469766560501b6044820152606401610539565b60008463ffffffff166000036139d557508061349a565b6000836139e28688615b85565b6139ec9190615ba2565b90508263ffffffff168163ffffffff161115613a0a57829150613a0e565b8091505b50949350505050565b600285604001516002811115613a2f57613a2f61470a565b03613c985760008186608001516001600160481b0316613a4f9190615937565b9050600086606001516002811115613a6957613a6961470a565b03613af357604051637921219560e11b81526001600160a01b03868116600483015261dead6024830152604482018590526064820183905260a06084830152600060a483015285169063f242432a9060c4015b600060405180830381600087803b158015613ad657600080fd5b505af1158015613aea573d6000803e3d6000fd5b50505050613c92565b600186606001516002811115613b0b57613b0b61470a565b03613bfd57604080516001808252818301909252600091602080830190803683370190505090508381600081518110613b4657613b46614e15565b60209081029190910101526040805160018082528183019092526000918160200160208202803683370190505090508281600081518110613b8957613b89614e15565b6020908102919091010152604051633db0f8ab60e01b81526001600160a01b03871690633db0f8ab90613bc4908a9086908690600401615bc5565b600060405180830381600087803b158015613bde57600080fd5b505af1158015613bf2573d6000803e3d6000fd5b505050505050613c92565b600286606001516002811115613c1557613c1561470a565b03613c5657604051637a94c56560e11b81526001600160a01b038681166004830152602482018590526044820183905285169063f5298aca90606401613abc565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206275726e207370656360781b6044820152606401610539565b506132fe565b600185604001516002811115613cb057613cb061470a565b03613eca5780600114613cfa5760405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a5908189d5c9b8818dbdd5b9d60721b6044820152606401610539565b600085606001516002811115613d1257613d1261470a565b03613d9557604051635c46a7ef60e11b81526001600160a01b03858116600483015261dead602483015260448201849052608060648301526000608483015284169063b88d4fde9060a4015b600060405180830381600087803b158015613d7857600080fd5b505af1158015613d8c573d6000803e3d6000fd5b505050506132fe565b600185606001516002811115613dad57613dad61470a565b1480613dce5750600285606001516002811115613dcc57613dcc61470a565b145b15613c56576001600160a01b0384163014613e9d576040516331a9108f60e11b8152600481018390526001600160a01b038086169190851690636352211e90602401602060405180830381865afa158015613e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e519190615bfb565b6001600160a01b031614613e9d5760405162461bcd60e51b815260206004820152601360248201527229b2b73232b91034b9903737ba1037bbb732b960691b6044820152606401610539565b604051630852cd8d60e31b8152600481018390526001600160a01b038416906342966c6890602401613d5e565b60405162461bcd60e51b8152602060048201526012602482015271496e76616c696420746f6b656e207370656360701b6044820152606401610539565b60008181526001830160205260408120548015613ff0576000613f2b600183615029565b8554909150600090613f3f90600190615029565b9050818114613fa4576000866000018281548110613f5f57613f5f614e15565b9060005260206000200154905080876000018481548110613f8257613f82614e15565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613fb557613fb5615c18565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061050f565b600091505061050f565b5092915050565b600082600001828154811061401857614018614e15565b9060005260206000200154905092915050565b6000600182111561404357660384665653e00061050f565b6602738d24e5200092915050565b60038401546000906001600160401b0381111561407057614070614dff565b604051908082528060200260200182016040528015614099578160200160208202803683370190505b50905060005b84518110156142fc5760008582815181106140bc576140bc614e15565b60200260200101519050600087600301826000015165ffffffffffff16815481106140e9576140e9614e15565b9060005260206000209060020201600101826020015165ffffffffffff168154811061411757614117614e15565b600091825260209091206040805161010081019091526004909202018054829060ff16600381111561414b5761414b61470a565b600381111561415c5761415c61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156141945761419461470a565b60028111156141a5576141a561470a565b81528154602090910190600160b01b900460ff1660028111156141ca576141ca61470a565b60028111156141db576141db61470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b031681526020016001820154815260200160028201548152602001600382015481525050905073f56dfc2f506f3fbe85d33fd70653d7bac0907d566372acbd28828460400151856060015186608001516040518563ffffffff1660e01b81526004016142779493929190615532565b60006040518083038186803b15801561428f57600080fd5b505af41580156142a3573d6000803e3d6000fd5b505050506142bc8186846040015185606001518a613a17565b8584836000015165ffffffffffff16815181106142db576142db614e15565b602002602001018181516142ef9190615356565b905250505060010161409f565b5060005b81518110156143a5578386600301828154811061431f5761431f614e15565b90600052602060002090600202016000015461433b9190615937565b82828151811061434d5761434d614e15565b60200260200101511461439d5760405162461bcd60e51b8152602060048201526018602482015277496e76616c6964206e756d626572206f6620746f6b656e7360401b6044820152606401610539565b600101614300565b505050505050565b60008181526001830160205260408120546143f45750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561050f565b50600061050f565b6040805161016081019091526000808252602082019081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e083019190915261010082018190526101209091015290565b60006020828403121561446d57600080fd5b81356001600160e01b0319811681146124a057600080fd5b6001600160a01b03811681146106cf57600080fd5b60008083601f8401126144ac57600080fd5b5081356001600160401b038111156144c357600080fd5b6020830191508360208285010111156144db57600080fd5b9250929050565b6000806000806000608086880312156144fa57600080fd5b853561450581614485565b9450602086013561451581614485565b93506040860135925060608601356001600160401b0381111561453757600080fd5b6145438882890161449a565b969995985093965092949392505050565b60006020828403121561456657600080fd5b81356124a081614485565b80151581146106cf57600080fd5b6000806000806080858703121561459557600080fd5b84356145a081614485565b93506020850135925060408501356001600160401b038111156145c257600080fd5b850161012081880312156145d557600080fd5b915060608501356145e581614571565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b818110156146315783516001600160a01b03168352928401929184019160010161460c565b50909695505050505050565b600481106106cf57600080fd5b80356146558161463d565b919050565b60008060008060008060a0878903121561467357600080fd5b863561467e81614485565b95506020870135945060408701356146958161463d565b935060608701356001600160401b038111156146b057600080fd5b6146bc89828a0161449a565b90945092505060808701356146d081614571565b809150509295509295509295565b600080604083850312156146f157600080fd5b82356146fc81614485565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600481106106cf576106cf61470a565b61473981614720565b9052565b60005b83811015614758578181015183820152602001614740565b50506000910152565b6000815180845261477981602086016020860161473d565b601f01601f19169290920160200192915050565b600381106106cf576106cf61470a565b6147398161478d565b80516147b181614720565b82526020818101516001600160a01b03169083015260408101516147d48161478d565b604083015260608101516147e78161478d565b60608301526080818101516001600160481b03169083015260a0808201519083015260c0808201519083015260e090810151910152565b600081518084526020808501808196508360051b810191508286016000805b868110156148ae578385038a528251805186528601516040878701819052815190870181905290870190606087019084905b80821015614899576148828385516147a6565b61010083019250898401935060018201915061486f565b50509a87019a9550509185019160010161483d565b509298975050505050505050565b80516001600160a01b03168252600061016060208301516148e06020860182614730565b5060408301516148f8604086018263ffffffff169052565b50606083015161490e606086018261ffff169052565b506080830151614926608086018263ffffffff169052565b5060a083015161493b60a086018260ff169052565b5060c083015161495560c086018265ffffffffffff169052565b5060e083015161496f60e086018265ffffffffffff169052565b50610100838101516001600160a01b0316908501526101208084015181860183905261499d83870182614761565b9250505061014080840151858303828701526149b9838261481e565b9695505050505050565b82815260406020820152600061349a60408301846148bc565b60008083601f8401126149ee57600080fd5b5081356001600160401b03811115614a0557600080fd5b6020830191508360208260051b85010111156144db57600080fd5b6000806000806000806000806080898b031215614a3c57600080fd5b88356001600160401b0380821115614a5357600080fd5b614a5f8c838d016149dc565b909a50985060208b0135915080821115614a7857600080fd5b614a848c838d016149dc565b909850965060408b0135915080821115614a9d57600080fd5b614aa98c838d016149dc565b909650945060608b0135915080821115614ac257600080fd5b50614acf8b828c016149dc565b999c989b5096995094979396929594505050565b6001600160a01b0391909116815260200190565b6020815260006124a060208301846148bc565b60008060008060008060008060a0898b031215614b2657600080fd5b8835614b3181614485565b97506020890135614b4181614485565b965060408901356001600160401b0380821115614b5d57600080fd5b614b698c838d016149dc565b909850965060608b0135915080821115614b8257600080fd5b614b8e8c838d016149dc565b909650945060808b0135915080821115614ba757600080fd5b50614acf8b828c0161449a565b60008060008060008060808789031215614bcd57600080fd5b8635614bd881614485565b95506020870135945060408701356001600160401b0380821115614bfb57600080fd5b614c078a838b016149dc565b90965094506060890135915080821115614c2057600080fd5b50614c2d89828a016149dc565b979a9699509497509295939492505050565b803563ffffffff8116811461465557600080fd5b600080600080600060808688031215614c6b57600080fd5b8535614c7681614485565b945060208601359350614c8b60408701614c3f565b925060608601356001600160401b03811115614ca657600080fd5b614543888289016149dc565b6020815260006124a06020830184614761565b600080600060608486031215614cda57600080fd5b8335614ce581614485565b9250602084013591506040840135614cfc81614485565b809150509250925092565b60008060008060008060a08789031215614d2057600080fd5b8635614d2b81614485565b95506020870135614d3b81614485565b9450604087013593506060870135925060808701356001600160401b03811115614d6457600080fd5b614c2d89828a0161449a565b803561465581614485565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215614dc457600080fd5b81516124a081614571565b6020808252601690820152752bb0b63632ba1034b9903737ba1030b71030b236b4b760511b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614e5357614e53614e2b565b5060010190565b600181811c90821680614e6e57607f821691505b602082108103614e8e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156120cd57600081815260208120601f850160051c81016020861015614ebb5750805b601f850160051c820191505b818110156143a557828155600101614ec7565b6001600160401b03831115614ef157614ef1614dff565b614f0583614eff8354614e5a565b83614e94565b6000601f841160018114614f395760008515614f215750838201355b600019600387901b1c1916600186901b1783556132fe565b600083815260209020601f19861690835b82811015614f6a5786850135825560209485019460019092019101614f4a565b5086821015614f875760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b600060208284031215614fab57600080fd5b815169ffffffffffffffffffff811681146124a057600080fd5b600060208284031215614fd757600080fd5b6124a082614c3f565b6000808335601e19843603018112614ff757600080fd5b8301803591506001600160401b0382111561501157600080fd5b6020019150600581901b36038213156144db57600080fd5b8181038181111561050f5761050f614e2b565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b6000826150a5576150a5615080565b500690565b6020808252600c908201526b496e76616c6964206461746160a01b604082015260600190565b60405160a081016001600160401b03811182821017156150f2576150f2614dff565b60405290565b604051601f8201601f191681016001600160401b038111828210171561512057615120614dff565b604052919050565b60006001600160401b0382111561514157615141614dff565b5060051b60200190565b803565ffffffffffff8116811461465557600080fd5b600082601f83011261517257600080fd5b8135602061518761518283615128565b6150f8565b82815260059290921b840181019181810190868411156151a657600080fd5b8286015b848110156151c157803583529183019183016151aa565b509695505050505050565b60006151da61518284615128565b8381529050602080820190600585901b8401868111156151f957600080fd5b845b818110156152a65780356001600160401b038082111561521b5760008081fd5b9087019060a0828b0312156152305760008081fd5b6152386150d0565b6152418361514b565b815261524e86840161514b565b8682015260408084013561526181614485565b9082015260608381013590820152608080840135838111156152835760008081fd5b61528f8d828701615161565b9183019190915250865250509282019282016151fb565b505050509392505050565b600080600080608085870312156152c757600080fd5b84356152d281614485565b9350602085013592506152e760408601614c3f565b915060608501356001600160401b0381111561530257600080fd5b8501601f8101871361531357600080fd5b615322878235602084016151cc565b91505092959194509250565b63ffffffff81811683821602808216919082811461534e5761534e614e2b565b505092915050565b8082018082111561050f5761050f614e2b565b6020808252600e908201526d125b9d985b1a5908185b5bdd5b9d60921b604082015260600190565b6000602082840312156153a357600080fd5b5051919050565b600083516153bc81846020880161473d565b8351908301906153d081836020880161473d565b01949350505050565b600083516153eb81846020880161473d565b602f60f81b908301908152835161540981600184016020880161473d565b01600101949350505050565b600080600080600060a0868803121561542d57600080fd5b853561543881614485565b94506020860135935061544d60408701614c3f565b92506060860135915060808601356001600160401b0381111561546f57600080fd5b61547b88828901615161565b9150509295509295909350565b6000806000806080858703121561549e57600080fd5b84356154a981614485565b9350602085013592506040850135915060608501356001600160401b038111156154d257600080fd5b61532287828801615161565b6020808252600d908201526c125b9d985b1a59081a5b9c1d5d609a1b604082015260600190565b6020808252601390820152724e6f20746f6b656e7320617661696c61626c6560681b604082015260600190565b600061016080830161554484896147a6565b6001600160a01b038716610100850152610120840186905261014084019190915283519081905261018083019060209081860160005b828110156155965781518552938301939083019060010161557a565b50929998505050505050505050565b803561ffff8116811461465557600080fd5b6000808335601e198436030181126155ce57600080fd5b83016020810192503590506001600160401b038111156155ed57600080fd5b8036038213156144db57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261563c57600080fd5b83016020810192503590506001600160401b0381111561565b57600080fd5b8060051b36038213156144db57600080fd5b80356003811061465557600080fd5b80356001600160481b038116811461465557600080fd5b81835260006020808501808196508560051b810191508460005b878110156157fc5782840389528135603e198836030181126156ce57600080fd5b87018035855260408581018783013536849003601e190181126156f057600080fd5b9092018781019290356001600160401b0381111561570d57600080fd5b8060081b360384131561571f57600080fd5b8789018390529081905260609081880160005b828110156157e55785356157458161463d565b61574e81614720565b8252858b013561575d81614485565b6001600160a01b0316828c015261577586860161566d565b6157818684018261479d565b5061578d84870161566d565b6157998584018261479d565b5060806157a781880161567c565b6001600160481b03169083015260a0868101359083015260c0808701359083015260e080870135908301526101009586019590910190600101615732565b509c89019c975050509286019250506001016156ad565b5091979650505050505050565b60006101206158288461581b85614d70565b6001600160a01b03169052565b6158346020840161464a565b6158416020860182614730565b5061584e604084016155a5565b61ffff16604085015261586360608401614c3f565b63ffffffff16606085015261587a6080840161514b565b65ffffffffffff16608085015261589360a0840161514b565b65ffffffffffff1660a08501526158ac60c08401614d70565b6001600160a01b031660c08501526158c760e08401846155b7565b8260e08701526158da83870182846155fc565b925050506101006158ed81850185615625565b868403838801526158ff848284615693565b979650505050505050565b60018060a01b03851681528360208201528260408201526080606082015260006149b96080830184615809565b808202811582820484141761050f5761050f614e2b565b60006124a03684846151cc565b6001600160481b0381811683821602808216919082811461534e5761534e614e2b565b600081518084526020808501945080840160005b838110156159ae57815187529582019590820190600101615992565b509495945050505050565b6001600160a01b0385811682528416602082015260a0604082018190526000906159e59083018561597e565b82810360608401526159f7818561597e565b838103608090940193909352505060008152602001949350505050565b600063ffffffff808316818103615a2d57615a2d614e2b565b6001019392505050565b63ffffffff818116838216019080821115613ffa57613ffa614e2b565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b81811015615aa957845169ffffffffffffffffffff1683529383019391830191600101615a81565b5090979650505050505050565b60006020808385031215615ac957600080fd5b82516001600160401b03811115615adf57600080fd5b8301601f81018513615af057600080fd5b8051615afe61518282615128565b81815260059190911b82018301908381019087831115615b1d57600080fd5b928401925b828410156158ff57835182529284019290840190615b22565b60018060a01b038616815260ff8516602082015283604082015282606082015260a0608082015260006158ff60a0830184615809565b600082615b8057615b80615080565b500490565b63ffffffff828116828216039080821115613ffa57613ffa614e2b565b600063ffffffff80841680615bb957615bb9615080565b92169190910492915050565b6001600160a01b0384168152606060208201819052600090615be99083018561597e565b82810360408401526149b9818561597e565b600060208284031215615c0d57600080fd5b81516124a081614485565b634e487b7160e01b600052603160045260246000fdfea264697066735822122008f7b2592fe2cd29cceccad31d8b23b2a0a4b0d473cd744c0c53214fe1eb285264736f6c63430008110033
Deployed Bytecode
0x6080604052600436106101615760003560e01c80637ab39392116100c1578063c9dad6961161007a578063c9dad6961461040a578063cc7ac3f71461041d578063e9dc63751461043d578063f0e9fcd11461046a578063f23a6e611461048a578063f2fde38b146104aa578063f3fef3a3146104ca57600080fd5b80637ab39392146103445780638da5cb5b1461036457806395bc312b14610382578063b058d2f81461039d578063bc197c81146103ca578063c2065c10146103ea57600080fd5b80633f25c9961161011e5780633f25c9961461025857806341d29f071461027857806342b54fee146102a6578063480df058146102b957806350d10839146102e25780636d73e6691461030f578063715018a61461032f57600080fd5b806301ffc9a714610166578063150b7a021461019b57806324d7806c146101d457806327a99a14146101f45780632d3456701461021657806331ae450b14610236575b600080fd5b34801561017257600080fd5b5061018661018136600461445b565b6104ea565b60405190151581526020015b60405180910390f35b3480156101a757600080fd5b506101bb6101b63660046144e2565b610515565b6040516001600160e01b03199091168152602001610192565b3480156101e057600080fd5b506101866101ef366004614554565b61056a565b34801561020057600080fd5b5061021461020f36600461457f565b6105a3565b005b34801561022257600080fd5b50610214610231366004614554565b610674565b34801561024257600080fd5b5061024b6106d2565b60405161019291906145f0565b34801561026457600080fd5b5061021461027336600461465a565b610780565b34801561028457600080fd5b506102986102933660046146de565b6108b4565b6040516101929291906149c3565b6102146102b4366004614a20565b610d2e565b3480156102c557600080fd5b506102d46602738d24e5200081565b604051908152602001610192565b3480156102ee57600080fd5b50600554610302906001600160a01b031681565b6040516101929190614ae3565b34801561031b57600080fd5b5061021461032a366004614554565b610e93565b34801561033b57600080fd5b50610214610eeb565b34801561035057600080fd5b5061021461035f366004614554565b610eff565b34801561037057600080fd5b506000546001600160a01b0316610302565b34801561038e57600080fd5b506102d4660384665653e00081565b3480156103a957600080fd5b506103bd6103b83660046146de565b610f6b565b6040516101929190614af7565b3480156103d657600080fd5b506101bb6103e5366004614b0a565b6112a6565b3480156103f657600080fd5b50610214610405366004614bb4565b6113bc565b610214610418366004614c53565b611610565b34801561042957600080fd5b5061021461043836600461457f565b61167c565b34801561044957600080fd5b5061045d6104583660046146de565b61185c565b6040516101929190614cb2565b34801561047657600080fd5b50610214610485366004614cc5565b611e16565b34801561049657600080fd5b506101bb6104a5366004614d07565b611ecd565b3480156104b657600080fd5b506102146104c5366004614554565b611f6a565b3480156104d657600080fd5b506102146104e53660046146de565b611fe0565b60006001600160e01b0319821663d4f6907560e01b148061050f575061050f826120d2565b92915050565b60006002600354036105425760405162461bcd60e51b815260040161053990614d7b565b60405180910390fd5b600260035561055385858585612148565b50630a85bd0160e11b600160035595945050505050565b6000816001600160a01b03166105886000546001600160a01b031690565b6001600160a01b0316148061050f575061050f600183612482565b604051630935e01b60e21b815284906001600160a01b038216906324d7806c906105d1903390600401614ae3565b602060405180830381865afa1580156105ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106129190614db2565b61062e5760405162461bcd60e51b815260040161053990614dcf565b6106398585856124a7565b506001600160a01b0393909316600090815260076020908152604080832094835293905291909120805460ff19169215159290921790915550565b61067c612519565b610687600182612482565b156106cf5760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36106cd600182612573565b505b50565b60606106de6001612588565b6001600160401b038111156106f5576106f5614dff565b60405190808252806020026020018201604052801561071e578160200160208202803683370190505b50905060005b61072e6001612588565b81101561077c57610740600182612592565b82828151811061075257610752614e15565b6001600160a01b03909216602092830291909101909101528061077481614e41565b915050610724565b5090565b604051630935e01b60e21b815286906001600160a01b038216906324d7806c906107ae903390600401614ae3565b602060405180830381865afa1580156107cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ef9190614db2565b61080b5760405162461bcd60e51b815260040161053990614dcf565b6000610817888861259e565b80549091508690829060ff60a01b1916600160a01b83600381111561083e5761083e61470a565b021790555060028101610852858783614eda565b506001600160a01b03881660008181526007602090815260408083208b8452909152808220805460ff1916871515179055518992917fc4487c68aeaaea10bc0e1e6408497e8b1eedeb6aeece8711fdb0da6b6c288dab91a35050505050505050565b60006108be6143fc565b6001600160a01b038416600090815260066020908152604080832086845282528083208151808301909252546001600160e01b038116808352600160e01b90910463ffffffff169282019290925291036109935760405163b4b5b48f60e01b8152600481018590526000906001600160a01b0387169063b4b5b48f90602401602060405180830381865afa15801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190614f99565b60181c66ffffffffffffff1693506109a19050565b80516001600160e01b031692505b826000036109e85760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610539565b6001600160a01b0385811660009081526004602090815260408083208784528252918290208251610160810190935280549384168352919290830190600160a01b900460ff166003811115610a3f57610a3f61470a565b6003811115610a5057610a5061470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e082015260028201805461010090920191610ae090614e5a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b0c90614e5a565b8015610b595780601f10610b2e57610100808354040283529160200191610b59565b820191906000526020600020905b815481529060010190602001808311610b3c57829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015610d1c57838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015610d0557600084815260209020604080516101008101909152600484029091018054829060ff166003811115610c1557610c1561470a565b6003811115610c2657610c2661470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115610c5e57610c5e61470a565b6002811115610c6f57610c6f61470a565b81528154602090910190600160b01b900460ff166002811115610c9457610c9461470a565b6002811115610ca557610ca561470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190610bd9565b505050508152505081526020019060010190610b87565b50505050815250509150509250929050565b600260035403610d505760405162461bcd60e51b815260040161053990614d7b565b60026003558685148015610d6357508683145b8015610d6e57508681145b610dad5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c6461746160801b6044820152606401610539565b6000610db83361262c565b90503460005b89811015610e7157610e5d828c8c84818110610ddc57610ddc614e15565b9050602002016020810190610df19190614554565b8b8b85818110610e0357610e03614e15565b905060200201358a8a86818110610e1c57610e1c614e15565b9050602002016020810190610e319190614fc5565b898987818110610e4357610e43614e15565b9050602002810190610e559190614fe0565b8960006126b5565b610e679083615029565b9150600101610dbe565b508015610e8257610e82338261202a565b505060016003555050505050505050565b610e9b612519565b610ea6600182612482565b6106cf5760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36106cd600182612808565b610ef3612519565b610efd600061281d565b565b33610f126000546001600160a01b031690565b6001600160a01b03161480610f2d5750610f2d600133612482565b610f495760405162461bcd60e51b81526004016105399061503c565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b610f736143fc565b610f7d838361259e565b60408051610160810190915281546001600160a01b03811682529091906020830190600160a01b900460ff166003811115610fba57610fba61470a565b6003811115610fcb57610fcb61470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e08201526002820180546101009092019161105b90614e5a565b80601f016020809104026020016040519081016040528092919081815260200182805461108790614e5a565b80156110d45780601f106110a9576101008083540402835291602001916110d4565b820191906000526020600020905b8154815290600101906020018083116110b757829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b8282101561129757838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b8282101561128057600084815260209020604080516101008101909152600484029091018054829060ff1660038111156111905761119061470a565b60038111156111a1576111a161470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156111d9576111d961470a565b60028111156111ea576111ea61470a565b81528154602090910190600160b01b900460ff16600281111561120f5761120f61470a565b60028111156112205761122061470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190611154565b505050508152505081526020019060010190611102565b50505091525090949350505050565b60006002600354036112ca5760405162461bcd60e51b815260040161053990614d7b565b60026003556112da602083615096565b156112f75760405162461bcd60e51b8152600401610539906150aa565b600080806060611309868801886152b1565b8094508195508296508397505050505061139e8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508a92508991508890508761286d565b505060016003555063bc197c8160e01b9a9950505050505050505050565b604051630935e01b60e21b815286906001600160a01b038216906324d7806c906113ea903390600401614ae3565b602060405180830381865afa158015611407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142b9190614db2565b6114475760405162461bcd60e51b815260040161053990614dcf565b8382146114895760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c6461746160801b6044820152606401610539565b6000611495888861259e565b90506000805b848110156114fb578254600160c81b900461ffff168686838181106114c2576114c2614e15565b90506020020160208101906114d79190614fc5565b6114e1919061532e565b6114f19063ffffffff1683615356565b915060010161149b565b50815463ffffffff9061151790600160a81b9004821683615356565b11156115355760405162461bcd60e51b815260040161053990615369565b60005b868110156115a1576115998a8a858b8b8681811061155857611558614e15565b905060200201602081019061156d9190614554565b8a8a8781811061157f5761157f614e15565b90506020020160208101906115949190614fc5565b612cb8565b600101611538565b5060405163e5c986cd60e01b81526004810183905273f56dfc2f506f3fbe85d33fd70653d7bac0907d569063e5c986cd9060240160006040518083038186803b1580156115ed57600080fd5b505af4158015611601573d6000803e3d6000fd5b50505050505050505050505050565b6002600354036116325760405162461bcd60e51b815260040161053990614d7b565b6002600355600061165234878787878761164b3361262c565b60016126b5565b90508034111561166f5761166f3361166a8334615029565b61202a565b5050600160035550505050565b604051630935e01b60e21b815284906001600160a01b038216906324d7806c906116aa903390600401614ae3565b602060405180830381865afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116eb9190614db2565b6117075760405162461bcd60e51b815260040161053990614dcf565b60008411801561171e575066ffffffffffffff8411155b61175f5760405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a59081a5b9cdd185b98d9525960721b6044820152606401610539565b6000856001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156117bb575060408051601f3d908101601f191682019092526117b891810190615391565b60015b156118145760ff8111156118115760405162461bcd60e51b815260206004820152601c60248201527f556e737570706f7274656420636f6e74726163742076657273696f6e000000006044820152606401610539565b90505b61182086828787613305565b50506001600160a01b0393909316600090815260076020908152604080832094835293905291909120805460ff19169215159290921790915550565b6001600160a01b03821660009081526006602090815260408083208484528252918290208251808401909352546001600160e01b0381168352600160e01b900463ffffffff16908201526060906118b16143fc565b60008083600001516001600160e01b031660000361199b5760405163b4b5b48f60e01b8152600481018790526000906001600160a01b0389169063b4b5b48f90602401602060405180830381865afa158015611911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119359190614f99565b66ffffffffffffff601882901c1692509050600082900361198f5760405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606401610539565b62ffffff1691506119b5565b50508151602083015163ffffffff16906001600160e01b03165b6001600160a01b0387811660009081526004602090815260408083208584528252918290208251610160810190935280549384168352919290830190600160a01b900460ff166003811115611a0c57611a0c61470a565b6003811115611a1d57611a1d61470a565b81528154600160a81b810463ffffffff9081166020840152600160c81b820461ffff166040840152600160d81b8204166060830152600160f81b900460ff166080820152600182015465ffffffffffff80821660a0840152600160301b82041660c0830152600160601b90046001600160a01b031660e082015260028201805461010090920191611aad90614e5a565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad990614e5a565b8015611b265780601f10611afb57610100808354040283529160200191611b26565b820191906000526020600020905b815481529060010190602001808311611b0957829003601f168201915b5050505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015611ce957838290600052602060002090600202016040518060400160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020016000905b82821015611cd257600084815260209020604080516101008101909152600484029091018054829060ff166003811115611be257611be261470a565b6003811115611bf357611bf361470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115611c2b57611c2b61470a565b6002811115611c3c57611c3c61470a565b81528154602090910190600160b01b900460ff166002811115611c6157611c6161470a565b6002811115611c7257611c7261470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b03168152602001600182015481526020016002820154815260200160038201548152505081526020019060010190611ba6565b505050508152505081526020019060010190611b54565b50505091525050604080516020810190915260008152909350600284602001516003811115611d1a57611d1a61470a565b03611d50575060408051808201909152601481527368747470733a2f2f617277656176652e6e65742f60601b6020820152611d8d565b600384602001516003811115611d6857611d6861470a565b03611d8d5750604080518082019091526007815266697066733a2f2f60c81b60208201525b610120840151604051611da49183916020016153aa565b60408051601f198184030181529181526001600160a01b038a166000908152600760209081528282208683529052205490965060ff16611e0b5785611de88461339a565b604051602001611df99291906153d9565b60405160208183030381529060405295505b505050505092915050565b33611e296000546001600160a01b031690565b6001600160a01b03161480611e445750611e44600133612482565b611e605760405162461bcd60e51b81526004016105399061503c565b6040516323b872dd60e01b81523060048201526001600160a01b038281166024830152604482018490528416906323b872dd90606401600060405180830381600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b50505050505050565b6000600260035403611ef15760405162461bcd60e51b815260040161053990614d7b565b6002600355611f01602083615096565b15611f1e5760405162461bcd60e51b8152600401610539906150aa565b60008080806060611f3187890189615415565b939850919650945092509050611f4d8b8b8b88888888886134a2565b505060016003555063f23a6e6160e01b9998505050505050505050565b611f72612519565b6001600160a01b038116611fd75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610539565b6106cf8161281d565b33611ff36000546001600160a01b031690565b6001600160a01b0316148061200e575061200e600133612482565b61202a5760405162461bcd60e51b81526004016105399061503c565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612077576040519150601f19603f3d011682016040523d82523d6000602084013e61207c565b606091505b50509050806120cd5760405162461bcd60e51b815260206004820152601f60248201527f4661696c656420746f207472616e7366657220746f20726563697069656e74006044820152606401610539565b505050565b60006001600160e01b0319821663c147147760e01b148061210357506001600160e01b03198216630a85bd0160e11b145b8061211e57506001600160e01b03198216630271189760e51b145b8061213957506001600160e01b0319821663e9dc637560e01b145b8061050f575061050f8261386b565b612153602082615096565b156121705760405162461bcd60e51b8152600401610539906150aa565b60008080606061218285870187615488565b92965090945092509050600061219885856138a0565b6001810154909150600160601b90046001600160a01b03161580156121c1575060038101546001145b80156121f45750806003016000815481106121de576121de614e15565b9060005260206000209060020201600001546001145b801561220457506122048961262c565b6122205760405162461bcd60e51b8152600401610539906154de565b80546000906122569063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b9091041660016139be565b63ffffffff1690508060000361227e5760405162461bcd60e51b815260040161053990615505565b60008260030160008154811061229657612296614e15565b906000526020600020906002020160010185815481106122b8576122b8614e15565b600091825260209091206040805161010081019091526004909202018054829060ff1660038111156122ec576122ec61470a565b60038111156122fd576122fd61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156123355761233561470a565b60028111156123465761234661470a565b81528154602090910190600160b01b900460ff16600281111561236b5761236b61470a565b600281111561237c5761237c61470a565b81528154600160b81b90046001600160481b03166020820152600180830154604083015260028301546060830152600390920154608090910152909150816040015160028111156123cf576123cf61470a565b146123ec5760405162461bcd60e51b8152600401610539906154de565b604051630e5597a560e31b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56906372acbd289061242990849033908f908a90600401615532565b60006040518083038186803b15801561244157600080fd5b505af4158015612455573d6000803e3d6000fd5b505050506124678130338d6001613a17565b6124758787858e6001612cb8565b5050505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b73f56dfc2f506f3fbe85d33fd70653d7bac0907d5663b40609bf84846124cd878761259e565b856040518563ffffffff1660e01b81526004016124ed949392919061590a565b60006040518083038186803b15801561250557600080fd5b505af4158015611ec4573d6000803e3d6000fd5b6000546001600160a01b03163314610efd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610539565b60006124a0836001600160a01b038416613f07565b600061050f825490565b60006124a08383614001565b6001600160a01b03821660009081526004602090815260408083208484529091528120908154600160a01b900460ff1660038111156125df576125df61470a565b0361050f5760405162461bcd60e51b815260206004820152601b60248201527f4275726e2072656465656d206e6f7420696e697469616c697a656400000000006044820152606401610539565b6005546000906001600160a01b03161580159061050f57506005546040516345ecd02f60e01b81526001600160a01b03909116906345ecd02f90612674908590600401614ae3565b602060405180830381865afa158015612691573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050f9190614db2565b6000806126c289896138a0565b80549091506126f79063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b909104168a6139be565b96508663ffffffff1660000361272f5782156127255760405162461bcd60e51b815260040161053990615505565b60009150506127fc565b6001810154600160601b90046001600160a01b03168085612760576127538761402b565b61275d9083615356565b91505b60018963ffffffff1611156127945761277f63ffffffff8a1683615937565b915061279163ffffffff8a1682615937565b90505b818c10156127b45760405162461bcd60e51b815260040161053990615369565b80156127cf5782546127cf906001600160a01b03168261202a565b6127ea836127dd898b61594e565b8b63ffffffff1633614051565b6127f78b8b85338d612cb8565b509150505b98975050505050505050565b60006124a0836001600160a01b0384166143ad565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061287985856138a0565b6001810154909150600160601b90046001600160a01b031615801561289f575086518251145b80156128af57506128af8861262c565b6128cb5760405162461bcd60e51b8152600401610539906154de565b80546000906129009063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b90910416876139be565b90508063ffffffff166000036129285760405162461bcd60e51b815260040161053990615505565b600088516001600160401b0381111561294357612943614dff565b60405190808252806020026020018201604052801561296c578160200160208202803683370190505b50905060005b8451811015612c1d57600085828151811061298f5761298f614e15565b60200260200101519050600085600301826000015165ffffffffffff16815481106129bc576129bc614e15565b9060005260206000209060020201600101826020015165ffffffffffff16815481106129ea576129ea614e15565b600091825260209091206040805161010081019091526004909202018054829060ff166003811115612a1e57612a1e61470a565b6003811115612a2f57612a2f61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff166002811115612a6757612a6761470a565b6002811115612a7857612a7861470a565b81528154602090910190600160b01b900460ff166002811115612a9d57612a9d61470a565b6002811115612aae57612aae61470a565b81528154600160b81b90046001600160481b0316602082015260018201546040820152600282015460608201526003909101546080909101528c519091508c9084908110612afe57612afe614e15565b6020026020010151826060015114612b485760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606401610539565b8a8381518110612b5a57612b5a614e15565b60200260200101518863ffffffff168260800151612b78919061595b565b6001600160481b031614612b9e5760405162461bcd60e51b815260040161053990615369565b8763ffffffff168563ffffffff1614612c13578463ffffffff168160800151612bc7919061595b565b6001600160481b03168b8481518110612be257612be2614e15565b6020026020010151612bf49190615029565b848481518110612c0657612c06614e15565b6020026020010181815250505b5050600101612972565b50612c3083858463ffffffff1630614051565b612c3d8787858d86612cb8565b8463ffffffff168263ffffffff1614612cac57604051631759616b60e11b81523390632eb2c2d690612c799030908e908e9087906004016159b9565b600060405180830381600087803b158015612c9357600080fd5b505af1158015612ca7573d6000803e3d6000fd5b505050505b50505050505050505050565b8254600160c81b900461ffff166001148015612cda57508063ffffffff166001145b15612ef05782548390601590612cfc90600160a81b900463ffffffff16615a14565b91906101000a81548163ffffffff021916908363ffffffff1602179055506000600384600001601f9054906101000a900460ff1660ff1610612dd357835460405163d397371960e01b81526001600160a01b038581166004830152600160a81b90920463ffffffff16601888901b66ffffffff0000001617602482018190529188169063d3973719906044016020604051808303816000875af1158015612da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dcb9190615391565b915050612ea7565b604051630525194b60e31b81526001600160a01b03871690632928ca5890612dff908690600401614ae3565b6020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e429190615391565b6040805180820182526001600160e01b038089168252875463ffffffff600160a81b909104811660208085019182526001600160a01b038d16600090815260068252868120888252909152949094209251935116600160e01b02921691909117905590505b60405160018152819086906001600160a01b038916907fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe09060200160405180910390a4506132fe565b8254600090612f0b908390600160c81b900461ffff1661532e565b63ffffffff16905061ffff811115612f355760405162461bcd60e51b8152600401610539906154de565b8354600090612f5290600160a81b900463ffffffff166001615a37565b855463ffffffff918216925083918791601591612f79918591600160a81b90910416615a37565b92506101000a81548163ffffffff021916908363ffffffff160217905550600385600001601f9054906101000a900460ff1660ff161061315f576000826001600160401b03811115612fcd57612fcd614dff565b604051908082528060200260200182016040528015612ff6578160200160208202803683370190505b50905060005b838110156130605761300e8184615356565b62ffffff1660188966ffffffffffffff16901b1766ffffffffffffff1682828151811061303d5761303d614e15565b69ffffffffffffffffffff90921660209283029190910190910152600101612ffc565b5060405163213c198760e11b81526000906001600160a01b038a1690634278330e906130929089908690600401615a54565b6000604051808303816000875af11580156130b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130d99190810190615ab6565b905060005b84811015613157578181815181106130f8576130f8614e15565b6020026020010151898b6001600160a01b03167fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe06001604051613147919063ffffffff91909116815260200190565b60405180910390a46001016130de565b505050611ec4565b60405163e00aab4b60e01b81526001600160a01b03858116600483015261ffff841660248301526000919089169063e00aab4b906044016000604051808303816000875af11580156131b5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131dd9190810190615ab6565b905060005b838110156132f9576040518060400160405280896001600160e01b0316815260200182856132109190615356565b63ffffffff1690526001600160a01b038a166000908152600660205260408120845190919085908590811061324757613247614e15565b6020908102919091018101518252818101929092526040016000208251929091015163ffffffff16600160e01b026001600160e01b03909216919091179055815182908290811061329a5761329a614e15565b6020026020010151888a6001600160a01b03167fb5455bab62448f7d0d17200c75068da7cfafd5c6bfe32d214ddd755e5f82dbe060016040516132e9919063ffffffff91909116815260200190565b60405180910390a46001016131e2565b505050505b5050505050565b6001600160a01b03841660009081526004602081815260408084208685529091529182902091516314765c6b60e01b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56926314765c6b9261336492899289928992899101615b3b565b60006040518083038186803b15801561337c57600080fd5b505af4158015613390573d6000803e3d6000fd5b5050505050505050565b6060816000036133c15750506040805180820190915260018152600360fc1b602082015290565b8160005b81156133eb57806133d581614e41565b91506133e49050600a83615b71565b91506133c5565b6000816001600160401b0381111561340557613405614dff565b6040519080825280601f01601f19166020018201604052801561342f576020820181803683370190505b5090505b841561349a57613444600183615029565b9150613451600a86615096565b61345c906030615356565b60f81b81838151811061347157613471614e15565b60200101906001600160f81b031916908160001a905350613493600a86615b71565b9450613433565b949350505050565b60006134ae86866138a0565b6001810154909150600160601b90046001600160a01b03161580156134d7575060038101546001145b801561350a5750806003016000815481106134f4576134f4614e15565b9060005260206000209060020201600001546001145b801561351a575061351a8961262c565b6135365760405162461bcd60e51b8152600401610539906154de565b805460009061356b9063ffffffff600160d81b8204811691600160a81b81049091169061ffff600160c81b90910416886139be565b90508063ffffffff166000036135935760405162461bcd60e51b815260040161053990615505565b6000826003016000815481106135ab576135ab614e15565b906000526020600020906002020160010185815481106135cd576135cd614e15565b600091825260209091206040805161010081019091526004909202018054829060ff1660038111156136015761360161470a565b60038111156136125761361261470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff16600281111561364a5761364a61470a565b600281111561365b5761365b61470a565b81528154602090910190600160b01b900460ff1660028111156136805761368061470a565b60028111156136915761369161470a565b81528154600160b81b90046001600160481b0316602082015260018201546040820152600282015460608201526003909101546080918201528101519091506136e19063ffffffff88169061595b565b6001600160481b031689146137085760405162461bcd60e51b8152600401610539906154de565b604051630e5597a560e31b815273f56dfc2f506f3fbe85d33fd70653d7bac0907d56906372acbd289061374590849033908f908a90600401615532565b60006040518083038186803b15801561375d57600080fd5b505af4158015613771573d6000803e3d6000fd5b505050506137888130338d8663ffffffff16613a17565b6137958888858e86612cb8565b8563ffffffff168263ffffffff161461247557336001600160a01b031663f242432a308d8d8560800151878c6137cb9190615b85565b63ffffffff166137db919061595b565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015293909216602484015260448301526001600160481b0316606482015260a06084820152600060a482015260c401600060405180830381600087803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160e01b03198216632a9f3abf60e11b148061050f57506301ffc9a760e01b6001600160e01b031983161461050f565b6001600160a01b03821660009081526004602090815260408083208484529091528120908154600160a01b900460ff1660038111156138e1576138e161470a565b0361392e5760405162461bcd60e51b815260206004820152601b60248201527f4275726e2072656465656d206e6f7420696e697469616c697a656400000000006044820152606401610539565b60018101544265ffffffffffff9091161180159061397957506001810154600160301b900465ffffffffffff1642108061397957506001810154600160301b900465ffffffffffff16155b61050f5760405162461bcd60e51b81526020600482015260166024820152754275726e2072656465656d206e6f742061637469766560501b6044820152606401610539565b60008463ffffffff166000036139d557508061349a565b6000836139e28688615b85565b6139ec9190615ba2565b90508263ffffffff168163ffffffff161115613a0a57829150613a0e565b8091505b50949350505050565b600285604001516002811115613a2f57613a2f61470a565b03613c985760008186608001516001600160481b0316613a4f9190615937565b9050600086606001516002811115613a6957613a6961470a565b03613af357604051637921219560e11b81526001600160a01b03868116600483015261dead6024830152604482018590526064820183905260a06084830152600060a483015285169063f242432a9060c4015b600060405180830381600087803b158015613ad657600080fd5b505af1158015613aea573d6000803e3d6000fd5b50505050613c92565b600186606001516002811115613b0b57613b0b61470a565b03613bfd57604080516001808252818301909252600091602080830190803683370190505090508381600081518110613b4657613b46614e15565b60209081029190910101526040805160018082528183019092526000918160200160208202803683370190505090508281600081518110613b8957613b89614e15565b6020908102919091010152604051633db0f8ab60e01b81526001600160a01b03871690633db0f8ab90613bc4908a9086908690600401615bc5565b600060405180830381600087803b158015613bde57600080fd5b505af1158015613bf2573d6000803e3d6000fd5b505050505050613c92565b600286606001516002811115613c1557613c1561470a565b03613c5657604051637a94c56560e11b81526001600160a01b038681166004830152602482018590526044820183905285169063f5298aca90606401613abc565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206275726e207370656360781b6044820152606401610539565b506132fe565b600185604001516002811115613cb057613cb061470a565b03613eca5780600114613cfa5760405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a5908189d5c9b8818dbdd5b9d60721b6044820152606401610539565b600085606001516002811115613d1257613d1261470a565b03613d9557604051635c46a7ef60e11b81526001600160a01b03858116600483015261dead602483015260448201849052608060648301526000608483015284169063b88d4fde9060a4015b600060405180830381600087803b158015613d7857600080fd5b505af1158015613d8c573d6000803e3d6000fd5b505050506132fe565b600185606001516002811115613dad57613dad61470a565b1480613dce5750600285606001516002811115613dcc57613dcc61470a565b145b15613c56576001600160a01b0384163014613e9d576040516331a9108f60e11b8152600481018390526001600160a01b038086169190851690636352211e90602401602060405180830381865afa158015613e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e519190615bfb565b6001600160a01b031614613e9d5760405162461bcd60e51b815260206004820152601360248201527229b2b73232b91034b9903737ba1037bbb732b960691b6044820152606401610539565b604051630852cd8d60e31b8152600481018390526001600160a01b038416906342966c6890602401613d5e565b60405162461bcd60e51b8152602060048201526012602482015271496e76616c696420746f6b656e207370656360701b6044820152606401610539565b60008181526001830160205260408120548015613ff0576000613f2b600183615029565b8554909150600090613f3f90600190615029565b9050818114613fa4576000866000018281548110613f5f57613f5f614e15565b9060005260206000200154905080876000018481548110613f8257613f82614e15565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613fb557613fb5615c18565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061050f565b600091505061050f565b5092915050565b600082600001828154811061401857614018614e15565b9060005260206000200154905092915050565b6000600182111561404357660384665653e00061050f565b6602738d24e5200092915050565b60038401546000906001600160401b0381111561407057614070614dff565b604051908082528060200260200182016040528015614099578160200160208202803683370190505b50905060005b84518110156142fc5760008582815181106140bc576140bc614e15565b60200260200101519050600087600301826000015165ffffffffffff16815481106140e9576140e9614e15565b9060005260206000209060020201600101826020015165ffffffffffff168154811061411757614117614e15565b600091825260209091206040805161010081019091526004909202018054829060ff16600381111561414b5761414b61470a565b600381111561415c5761415c61470a565b8152815461010081046001600160a01b03166020830152604090910190600160a81b900460ff1660028111156141945761419461470a565b60028111156141a5576141a561470a565b81528154602090910190600160b01b900460ff1660028111156141ca576141ca61470a565b60028111156141db576141db61470a565b81526020016000820160179054906101000a90046001600160481b03166001600160481b03166001600160481b031681526020016001820154815260200160028201548152602001600382015481525050905073f56dfc2f506f3fbe85d33fd70653d7bac0907d566372acbd28828460400151856060015186608001516040518563ffffffff1660e01b81526004016142779493929190615532565b60006040518083038186803b15801561428f57600080fd5b505af41580156142a3573d6000803e3d6000fd5b505050506142bc8186846040015185606001518a613a17565b8584836000015165ffffffffffff16815181106142db576142db614e15565b602002602001018181516142ef9190615356565b905250505060010161409f565b5060005b81518110156143a5578386600301828154811061431f5761431f614e15565b90600052602060002090600202016000015461433b9190615937565b82828151811061434d5761434d614e15565b60200260200101511461439d5760405162461bcd60e51b8152602060048201526018602482015277496e76616c6964206e756d626572206f6620746f6b656e7360401b6044820152606401610539565b600101614300565b505050505050565b60008181526001830160205260408120546143f45750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561050f565b50600061050f565b6040805161016081019091526000808252602082019081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e083019190915261010082018190526101209091015290565b60006020828403121561446d57600080fd5b81356001600160e01b0319811681146124a057600080fd5b6001600160a01b03811681146106cf57600080fd5b60008083601f8401126144ac57600080fd5b5081356001600160401b038111156144c357600080fd5b6020830191508360208285010111156144db57600080fd5b9250929050565b6000806000806000608086880312156144fa57600080fd5b853561450581614485565b9450602086013561451581614485565b93506040860135925060608601356001600160401b0381111561453757600080fd5b6145438882890161449a565b969995985093965092949392505050565b60006020828403121561456657600080fd5b81356124a081614485565b80151581146106cf57600080fd5b6000806000806080858703121561459557600080fd5b84356145a081614485565b93506020850135925060408501356001600160401b038111156145c257600080fd5b850161012081880312156145d557600080fd5b915060608501356145e581614571565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b818110156146315783516001600160a01b03168352928401929184019160010161460c565b50909695505050505050565b600481106106cf57600080fd5b80356146558161463d565b919050565b60008060008060008060a0878903121561467357600080fd5b863561467e81614485565b95506020870135945060408701356146958161463d565b935060608701356001600160401b038111156146b057600080fd5b6146bc89828a0161449a565b90945092505060808701356146d081614571565b809150509295509295509295565b600080604083850312156146f157600080fd5b82356146fc81614485565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600481106106cf576106cf61470a565b61473981614720565b9052565b60005b83811015614758578181015183820152602001614740565b50506000910152565b6000815180845261477981602086016020860161473d565b601f01601f19169290920160200192915050565b600381106106cf576106cf61470a565b6147398161478d565b80516147b181614720565b82526020818101516001600160a01b03169083015260408101516147d48161478d565b604083015260608101516147e78161478d565b60608301526080818101516001600160481b03169083015260a0808201519083015260c0808201519083015260e090810151910152565b600081518084526020808501808196508360051b810191508286016000805b868110156148ae578385038a528251805186528601516040878701819052815190870181905290870190606087019084905b80821015614899576148828385516147a6565b61010083019250898401935060018201915061486f565b50509a87019a9550509185019160010161483d565b509298975050505050505050565b80516001600160a01b03168252600061016060208301516148e06020860182614730565b5060408301516148f8604086018263ffffffff169052565b50606083015161490e606086018261ffff169052565b506080830151614926608086018263ffffffff169052565b5060a083015161493b60a086018260ff169052565b5060c083015161495560c086018265ffffffffffff169052565b5060e083015161496f60e086018265ffffffffffff169052565b50610100838101516001600160a01b0316908501526101208084015181860183905261499d83870182614761565b9250505061014080840151858303828701526149b9838261481e565b9695505050505050565b82815260406020820152600061349a60408301846148bc565b60008083601f8401126149ee57600080fd5b5081356001600160401b03811115614a0557600080fd5b6020830191508360208260051b85010111156144db57600080fd5b6000806000806000806000806080898b031215614a3c57600080fd5b88356001600160401b0380821115614a5357600080fd5b614a5f8c838d016149dc565b909a50985060208b0135915080821115614a7857600080fd5b614a848c838d016149dc565b909850965060408b0135915080821115614a9d57600080fd5b614aa98c838d016149dc565b909650945060608b0135915080821115614ac257600080fd5b50614acf8b828c016149dc565b999c989b5096995094979396929594505050565b6001600160a01b0391909116815260200190565b6020815260006124a060208301846148bc565b60008060008060008060008060a0898b031215614b2657600080fd5b8835614b3181614485565b97506020890135614b4181614485565b965060408901356001600160401b0380821115614b5d57600080fd5b614b698c838d016149dc565b909850965060608b0135915080821115614b8257600080fd5b614b8e8c838d016149dc565b909650945060808b0135915080821115614ba757600080fd5b50614acf8b828c0161449a565b60008060008060008060808789031215614bcd57600080fd5b8635614bd881614485565b95506020870135945060408701356001600160401b0380821115614bfb57600080fd5b614c078a838b016149dc565b90965094506060890135915080821115614c2057600080fd5b50614c2d89828a016149dc565b979a9699509497509295939492505050565b803563ffffffff8116811461465557600080fd5b600080600080600060808688031215614c6b57600080fd5b8535614c7681614485565b945060208601359350614c8b60408701614c3f565b925060608601356001600160401b03811115614ca657600080fd5b614543888289016149dc565b6020815260006124a06020830184614761565b600080600060608486031215614cda57600080fd5b8335614ce581614485565b9250602084013591506040840135614cfc81614485565b809150509250925092565b60008060008060008060a08789031215614d2057600080fd5b8635614d2b81614485565b95506020870135614d3b81614485565b9450604087013593506060870135925060808701356001600160401b03811115614d6457600080fd5b614c2d89828a0161449a565b803561465581614485565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215614dc457600080fd5b81516124a081614571565b6020808252601690820152752bb0b63632ba1034b9903737ba1030b71030b236b4b760511b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614e5357614e53614e2b565b5060010190565b600181811c90821680614e6e57607f821691505b602082108103614e8e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156120cd57600081815260208120601f850160051c81016020861015614ebb5750805b601f850160051c820191505b818110156143a557828155600101614ec7565b6001600160401b03831115614ef157614ef1614dff565b614f0583614eff8354614e5a565b83614e94565b6000601f841160018114614f395760008515614f215750838201355b600019600387901b1c1916600186901b1783556132fe565b600083815260209020601f19861690835b82811015614f6a5786850135825560209485019460019092019101614f4a565b5086821015614f875760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b600060208284031215614fab57600080fd5b815169ffffffffffffffffffff811681146124a057600080fd5b600060208284031215614fd757600080fd5b6124a082614c3f565b6000808335601e19843603018112614ff757600080fd5b8301803591506001600160401b0382111561501157600080fd5b6020019150600581901b36038213156144db57600080fd5b8181038181111561050f5761050f614e2b565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b6000826150a5576150a5615080565b500690565b6020808252600c908201526b496e76616c6964206461746160a01b604082015260600190565b60405160a081016001600160401b03811182821017156150f2576150f2614dff565b60405290565b604051601f8201601f191681016001600160401b038111828210171561512057615120614dff565b604052919050565b60006001600160401b0382111561514157615141614dff565b5060051b60200190565b803565ffffffffffff8116811461465557600080fd5b600082601f83011261517257600080fd5b8135602061518761518283615128565b6150f8565b82815260059290921b840181019181810190868411156151a657600080fd5b8286015b848110156151c157803583529183019183016151aa565b509695505050505050565b60006151da61518284615128565b8381529050602080820190600585901b8401868111156151f957600080fd5b845b818110156152a65780356001600160401b038082111561521b5760008081fd5b9087019060a0828b0312156152305760008081fd5b6152386150d0565b6152418361514b565b815261524e86840161514b565b8682015260408084013561526181614485565b9082015260608381013590820152608080840135838111156152835760008081fd5b61528f8d828701615161565b9183019190915250865250509282019282016151fb565b505050509392505050565b600080600080608085870312156152c757600080fd5b84356152d281614485565b9350602085013592506152e760408601614c3f565b915060608501356001600160401b0381111561530257600080fd5b8501601f8101871361531357600080fd5b615322878235602084016151cc565b91505092959194509250565b63ffffffff81811683821602808216919082811461534e5761534e614e2b565b505092915050565b8082018082111561050f5761050f614e2b565b6020808252600e908201526d125b9d985b1a5908185b5bdd5b9d60921b604082015260600190565b6000602082840312156153a357600080fd5b5051919050565b600083516153bc81846020880161473d565b8351908301906153d081836020880161473d565b01949350505050565b600083516153eb81846020880161473d565b602f60f81b908301908152835161540981600184016020880161473d565b01600101949350505050565b600080600080600060a0868803121561542d57600080fd5b853561543881614485565b94506020860135935061544d60408701614c3f565b92506060860135915060808601356001600160401b0381111561546f57600080fd5b61547b88828901615161565b9150509295509295909350565b6000806000806080858703121561549e57600080fd5b84356154a981614485565b9350602085013592506040850135915060608501356001600160401b038111156154d257600080fd5b61532287828801615161565b6020808252600d908201526c125b9d985b1a59081a5b9c1d5d609a1b604082015260600190565b6020808252601390820152724e6f20746f6b656e7320617661696c61626c6560681b604082015260600190565b600061016080830161554484896147a6565b6001600160a01b038716610100850152610120840186905261014084019190915283519081905261018083019060209081860160005b828110156155965781518552938301939083019060010161557a565b50929998505050505050505050565b803561ffff8116811461465557600080fd5b6000808335601e198436030181126155ce57600080fd5b83016020810192503590506001600160401b038111156155ed57600080fd5b8036038213156144db57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261563c57600080fd5b83016020810192503590506001600160401b0381111561565b57600080fd5b8060051b36038213156144db57600080fd5b80356003811061465557600080fd5b80356001600160481b038116811461465557600080fd5b81835260006020808501808196508560051b810191508460005b878110156157fc5782840389528135603e198836030181126156ce57600080fd5b87018035855260408581018783013536849003601e190181126156f057600080fd5b9092018781019290356001600160401b0381111561570d57600080fd5b8060081b360384131561571f57600080fd5b8789018390529081905260609081880160005b828110156157e55785356157458161463d565b61574e81614720565b8252858b013561575d81614485565b6001600160a01b0316828c015261577586860161566d565b6157818684018261479d565b5061578d84870161566d565b6157998584018261479d565b5060806157a781880161567c565b6001600160481b03169083015260a0868101359083015260c0808701359083015260e080870135908301526101009586019590910190600101615732565b509c89019c975050509286019250506001016156ad565b5091979650505050505050565b60006101206158288461581b85614d70565b6001600160a01b03169052565b6158346020840161464a565b6158416020860182614730565b5061584e604084016155a5565b61ffff16604085015261586360608401614c3f565b63ffffffff16606085015261587a6080840161514b565b65ffffffffffff16608085015261589360a0840161514b565b65ffffffffffff1660a08501526158ac60c08401614d70565b6001600160a01b031660c08501526158c760e08401846155b7565b8260e08701526158da83870182846155fc565b925050506101006158ed81850185615625565b868403838801526158ff848284615693565b979650505050505050565b60018060a01b03851681528360208201528260408201526080606082015260006149b96080830184615809565b808202811582820484141761050f5761050f614e2b565b60006124a03684846151cc565b6001600160481b0381811683821602808216919082811461534e5761534e614e2b565b600081518084526020808501945080840160005b838110156159ae57815187529582019590820190600101615992565b509495945050505050565b6001600160a01b0385811682528416602082015260a0604082018190526000906159e59083018561597e565b82810360608401526159f7818561597e565b838103608090940193909352505060008152602001949350505050565b600063ffffffff808316818103615a2d57615a2d614e2b565b6001019392505050565b63ffffffff818116838216019080821115613ffa57613ffa614e2b565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b81811015615aa957845169ffffffffffffffffffff1683529383019391830191600101615a81565b5090979650505050505050565b60006020808385031215615ac957600080fd5b82516001600160401b03811115615adf57600080fd5b8301601f81018513615af057600080fd5b8051615afe61518282615128565b81815260059190911b82018301908381019087831115615b1d57600080fd5b928401925b828410156158ff57835182529284019290840190615b22565b60018060a01b038616815260ff8516602082015283604082015282606082015260a0608082015260006158ff60a0830184615809565b600082615b8057615b80615080565b500490565b63ffffffff828116828216039080821115613ffa57613ffa614e2b565b600063ffffffff80841680615bb957615bb9615080565b92169190910492915050565b6001600160a01b0384168152606060208201819052600090615be99083018561597e565b82810360408401526149b9818561597e565b600060208284031215615c0d57600080fd5b81516124a081614485565b634e487b7160e01b600052603160045260246000fdfea264697066735822122008f7b2592fe2cd29cceccad31d8b23b2a0a4b0d473cd744c0c53214fe1eb285264736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,353.35 | 0.00069 | $2.31 |
Loading...
Loading
[ Download: CSV Export ]
[ 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.