Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Multichain Info
No addresses found
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
BlazeManager
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; // forgefmt: disable-start // // // // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓██▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓██▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ // // // // forgefmt: disable-end import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { IBlast } from "src/lib/IBlast.sol"; import { BlazeTypeStorage } from "src/lib/Structs.sol"; import { POINTS_OPERATOR, PROTOCOL_RECEIVER } from "src/lib/Constants.sol"; import { BlazeType } from "src/BlazeType.sol"; import { Meowville } from "src/vendor/Meowville.sol"; /// @title BlazeManager /// @author www.blaze.ong /// @notice Blaze0ng NFT Launchpad protocol manager. contract BlazeManager is OwnableUpgradeable, UUPSUpgradeable { /// @notice Amount in wei that is charged on each mint uint256 internal mintFee; /// @notice Emitted on each new BlazeType deployment. /// @param sender The address that deployed the BlazeType. /// @param blazeType The address of the deployed BlazeType. event DeployedBlazeType(address indexed sender, address indexed blazeType); /// @notice Emitted on each BlazeType mint. /// @param blazeType The address of the collection being minted. /// @param receiver The receiving address of the token. /// @param supply The number of NFTs minted before this transaction. /// @param amount The number of NFTs minted in this transaction. event MintedBlazeType( address indexed blazeType, address indexed receiver, uint256 supply, uint256 amount ); /// @notice Emitted on each Meowville mint. /// @param meowville The address of the Meowville collection being minted. /// @param receiver The receiving address of the token. /// @param supply The number of NFTs minted before this transaction. event MintedMeowville( address indexed meowville, address indexed receiver, uint256 supply ); constructor() { _disableInitializers(); } function initialize() external reinitializer(2) { __UUPSUpgradeable_init(); __Ownable_init(msg.sender); IBlast(0x4300000000000000000000000000000000000002).configureClaimableGas(); IBlast(0x4300000000000000000000000000000000000002).configureGovernor( PROTOCOL_RECEIVER ); } function _authorizeUpgrade(address newImplementation) internal override onlyOwner { } /// @notice Deploys a new BlazeType contract. /// @param _btStorage The BlazeType storage parameters. /// @param _name The BlazeType name. /// @param _symbol The BlazeType symbol. /// @param _owner The BlazeType owner. /// @return The address of the deployed BlazeType. function deployBlazeType( BlazeTypeStorage calldata _btStorage, string calldata _name, string calldata _symbol, uint256 _mintsToOwner, address _owner ) external returns (address) { BlazeType blazeType = new BlazeType(_btStorage, _name, _symbol, _mintsToOwner, address(this), _owner); emit DeployedBlazeType(msg.sender, address(blazeType)); return address(blazeType); } /// @notice Mints a BlazeType. /// @param _blazeType The BlazeType to mint. /// @param _amount The amount of NFTs to mint. function mintBlazeType(BlazeType _blazeType, uint256 _amount) external payable { uint256 totalFee = mintFee * _amount; (bool success, bytes memory returnData) = address(PROTOCOL_RECEIVER).call{ value: totalFee }(""); require(success, "BlazeManager: fee transfer failed"); if (!success) { handleReturnData(returnData, "BlazeManager: fee transfer failed"); } uint256 currentSupply = _blazeType.totalSupply(); (success, returnData) = address(_blazeType).call{ value: msg.value - totalFee }( abi.encodeWithSignature("mint(address,uint256)", msg.sender, _amount) ); if (!success) { handleReturnData(returnData, "BlazeManager: mint failed"); } emit MintedBlazeType(address(_blazeType), msg.sender, currentSupply, _amount); } /// @notice Mints a BlazeType. /// @param _blazeType The BlazeType to mint. /// @param _phase The phase of the whitelist. /// @param _merkleProof The Merkle proof for the whitelist. /// @param _amount The amount of NFTs to mint. function whitelistMintBlazeType( BlazeType _blazeType, uint8 _phase, bytes32[] calldata _merkleProof, uint256 _amount ) external payable { uint256 totalFee = mintFee * _amount; (bool success, bytes memory returnData) = address(PROTOCOL_RECEIVER).call{ value: totalFee }(""); require(success, "BlazeManager: fee transfer failed"); if (!success) { handleReturnData(returnData, "BlazeManager: fee transfer failed"); } uint256 currentSupply = _blazeType.totalSupply(); (success, returnData) = address(_blazeType).call{ value: msg.value - totalFee }( abi.encodeWithSignature( "whitelistMint(uint8,bytes32[],address,uint256)", _phase, _merkleProof, msg.sender, _amount ) ); if (!success) { handleReturnData(returnData, "BlazeManager: whitelist mint failed"); } emit MintedBlazeType(address(_blazeType), msg.sender, currentSupply, _amount); } function mintMeowville(Meowville _meow) external payable { (bool success, bytes memory returnData) = address(PROTOCOL_RECEIVER).call{ value: mintFee }(""); require(success, "BlazeManager: fee transfer failed"); if (!success) { handleReturnData(returnData, "BlazeManager: fee transfer failed"); } uint256 currentSupply = _meow.totalSupply(); (success, returnData) = address(_meow).call(abi.encodeWithSignature("mint(address)", msg.sender)); if (!success) { handleReturnData(returnData, "BlazeManager: whitelist mint failed"); } emit MintedMeowville(address(_meow), msg.sender, currentSupply); } function whitelistMintMeowville( Meowville _meow, bytes32[] calldata _merkleProof, bool _first ) external payable { uint256 first; assembly { first := iszero(_first) } Meowville.Whitelist memory currentWhitelist = _meow.whitelists()[first]; require( block.timestamp >= currentWhitelist.start && block.timestamp <= currentWhitelist.end, "Meowville: whitelist mint not active" ); (bool success, bytes memory returnData) = address(PROTOCOL_RECEIVER).call{ value: mintFee }(""); require(success, "BlazeManager: fee transfer failed"); if (!success) { handleReturnData(returnData, "BlazeManager: fee transfer failed"); } uint256 currentSupply = _meow.totalSupply(); _first ? (success, returnData) = address(_meow).call( abi.encodeWithSignature( "whitelist1Mint(address,bytes32[])", msg.sender, _merkleProof ) ) : (success, returnData) = address(_meow).call( abi.encodeWithSignature( "whitelist2Mint(address,bytes32[])", msg.sender, _merkleProof ) ); if (!success) { handleReturnData(returnData, "BlazeManager: whitelist mint failed"); } emit MintedMeowville(address(_meow), msg.sender, currentSupply); } function setMintFee(uint256 _mintFee) external onlyOwner { mintFee = _mintFee; } function handleReturnData(bytes memory returnData, string memory errorMessage) internal pure { if (returnData.length > 0) { assembly { let returndata_size := mload(returnData) revert(add(32, returnData), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
pragma solidity ^0.8.20; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast { // configure function configureContract( address contractAddress, YieldMode _yield, GasMode gasMode, address governor ) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; function isAuthorized(address contractAddress) external returns (bool); // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate( address contractAddress, address recipientOfGas, uint256 minClaimRateBips ) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas( address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume ) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice Struct for a single mint phase. /// @param start Timestamp for the phase's start. /// @param end Timestamp for the phase's end. /// @param whitelistMintPrice Price for a whitelist mint in wei. /// @param maxWhitelistMintsPerCall Maximum amount of whitelist mints in one call. /// @param maxTotalWhitelistMints Maximum amount of whitelist mints per address. /// @param merkleRoot Root hash for the merkle tree. struct WhitelistPhase { uint256 start; uint256 end; uint120 whitelistMintPrice; uint64 maxWhitelistMintsPerCall; uint64 maxTotalWhitelistMints; bytes32 merkleRoot; } /// @notice The configuration paramater storage of the contract. /// @param baseURI The base URI for the token URIs. /// @param contractURI The URI for the contract's metadata. /// @param maxSupply The maximum amount of tokens that can be minted. /// @param start Timestamp for the public mint's start. /// @param end Timestamp for the public mint's end. /// @param mintPrice Price for a mint in wei. /// @param maxMintsPerCall Maximum amount of mints in one call. /// @param maxTotalMints Maximum amount of mints per address. /// @param defaultRoyalty The default royalty percentage. /// @param royaltyReceiver The address that receives the royalties. /// @param tokenCurrency The address of the token that may be used /// for mints in place of ETH. /// @param whitelistPhases Array of up to three WhitelistPhase's. struct BlazeTypeStorage { string baseURI; string contractURI; uint256 maxSupply; uint256 start; uint256 end; uint120 mintPrice; uint64 maxMintsPerCall; uint64 maxTotalMints; uint16 defaultRoyalty; address royaltyReceiver; address tokenCurrency; WhitelistPhase[] whitelistPhases; } /// @notice Storage variables for a token's refund data. /// @param refunded If the refund has already been claimed for the token. /// @param renounced If the refund has been renounced for the token. /// @param refundUnlockTime The amount of time for the token to become refundable. /// @param refundAmount The amount of the refund for the token. struct RefundData { bool refunded; bool renounced; uint256 refundUnlockTime; uint256 refundAmount; } /// @notice Storage variables for Refundable collecttions. /// @param mintsToOwner The amount the owner mints to themselves. These may not be /// refunded. /// @param lockupPeriod The amount of time in seconds before a refund can be claimed. /// @param refundInfo Mapping of token ID's to their respective refund data. struct BlazeTypeRefundableStorage { uint256 mintsToOwner; uint256 lockupPeriod; mapping(uint256 tokenId => RefundData) refundInfo; } /// @notice The locks for the contract. /// @param baseURILocked If the `baseURI` is locked. /// @param contractURILocked If the `contractURI` is locked. /// @param royaltyParamsLocked If the default royalty is locked. struct Locks { bool baseURILocked; bool contractURILocked; bool royaltyParamsLocked; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; uint16 constant MAX_BPS = 5000; // 50% uint16 constant MAX_ROYALTY = 2000; // 20% address constant BLAST = 0x4300000000000000000000000000000000000002; address constant BLAST_POINTS_MAINNET = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800; address constant BLAST_POINTS_TESTNET = 0x2fc95838c71e76ec69ff817983BFf17c710F34E0; address constant BLAST_PYTH = 0xA2aa501b19aff244D90cc15a4Cf739D2725B5729; address constant POINTS_OPERATOR = 0xf8a82748e7DF10D0684B758d02cF6c43AD83AD25; address constant PROTOCOL_RECEIVER = 0xa804b7d57a4A872dbfbE2987347403039aDe20dC; bytes32 constant ETHUSD_PRICE_FEED = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; // forgefmt: disable-start // // // // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓██▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓██▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ // // // // forgefmt: disable-end import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { MerkleProofLib } from "@solady/utils/MerkleProofLib.sol"; import { BlazeTypeBase } from "src/BlazeTypeBase.sol"; import { BlazeTypeStorage, WhitelistPhase } from "src/lib/Structs.sol"; import "src/lib/Errors.sol"; /// @title BlazeType /// @author www.blaze.ong /// @notice Blaze0ng NFT Launchpad ERC721 contract. contract BlazeType is BlazeTypeBase { /// @notice BlazeTypeBase constructor /// @param _btStorage Initial storage parameters for the contract. /// @param _name The name of the NFT. /// @param _symbol The symbol of the NFT. /// @param _manager The BlazeManager for the collection. /// @param _owner The owner of the collection. constructor( BlazeTypeStorage memory _btStorage, string memory _name, string memory _symbol, uint256 _mintsToOwner, address _manager, address _owner ) BlazeTypeBase(_btStorage, _name, _symbol, _mintsToOwner, _manager, _owner) { } /// @notice Withdraws the mint funds to the collection owner. function withdraw() external onlyOwner { if (btStorage.tokenCurrency != address(0)) { IERC20 token = IERC20(btStorage.tokenCurrency); token.transfer(msg.sender, token.balanceOf(address(this))); } else { (bool success,) = msg.sender.call{ value: address(this).balance }(""); if (!success) { revert WithdrawalFailed(); } } _totalFundsReceived = 0; } /// @notice Withdraws a specified amount of mint funds to the collection owner. /// @param _amount The amount to withdraw. function withdraw(uint256 _amount) external onlyOwner { _amount > _totalFundsReceived ? _totalFundsReceived = 0 : _totalFundsReceived -= _amount; if (btStorage.tokenCurrency != address(0)) { IERC20(btStorage.tokenCurrency).transfer(msg.sender, _amount); } else { (bool success,) = msg.sender.call{ value: _amount }(""); if (!success) { revert WithdrawalFailed(); } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; import { ERC721A } from "ERC721A/ERC721A.sol"; import { Ownable } from "@solady/auth/Ownable.sol"; import { ERC2981 } from "@solady/tokens/ERC2981.sol"; import { MerkleProofLib } from "@solady/utils/MerkleProofLib.sol"; import { LibString } from "@solady/utils/LibString.sol"; contract Meowville is ERC721A, ERC2981, Ownable { struct WaveRange { Whitelist[2] whitelists; uint256 supplyCap; string uri; bool revealed; } struct Whitelist { uint256 start; uint256 end; bytes32 merkleRoot; } // ERC-4906 event MetadataUpdate(uint256 _tokenId); event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); WaveRange[] public waveRanges; mapping(bytes32 => bool) public whitelistClaims; mapping(uint8 => mapping(address => uint8)) publicMintLimit; uint256 public maxSupply; uint8 public currentWave; address internal blazeManager; string internal hiddenMetadataURI; constructor( WaveRange memory _wr, string memory _hiddenMetadataURI, address _blazeManager ) ERC721A("Meowville", "MEOW") { _initializeOwner(msg.sender); maxSupply = _wr.supplyCap; hiddenMetadataURI = _hiddenMetadataURI; blazeManager = _blazeManager; _addWaveRange(_wr); _setDefaultRoyalty(msg.sender, 50); // Owner mints for (uint256 i; i < 11; i++) { _mint(msg.sender, 1); } } function _startTokenId() internal pure override returns (uint256) { return 1; } function supportsInterface(bytes4 interfaceId) public view override(ERC721A, ERC2981) returns (bool) { return ERC721A.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId) || interfaceId == bytes4(0x49064906); } function setWaveRangeRevealed(string calldata _uri) external onlyOwner { waveRanges[currentWave].uri = _uri; waveRanges[currentWave].revealed = true; uint256 startId; currentWave == 0 ? startId = 1 : startId = waveRanges[currentWave - 1].supplyCap + 1; emit BatchMetadataUpdate(startId, waveRanges[currentWave].supplyCap); } function whitelists() external view returns (Whitelist[2] memory) { return waveRanges[currentWave].whitelists; } function expandSupply(WaveRange calldata _wr) external onlyOwner { require( waveRanges[currentWave].revealed == true, "Meowville: current wave metadata unrevealed" ); require( bytes(_wr.uri).length == 0 && _wr.revealed == false, "Meowville: invalid wave details" ); _addWaveRange(_wr); currentWave++; } function _addWaveRange(WaveRange memory _wr) internal { waveRanges.push(_wr); maxSupply = _wr.supplyCap; } function mint(address _receiver) external payable { require(msg.sender == blazeManager, "Meowville: only BlazeManager can mint"); require(publicMintLimit[currentWave][_receiver] == 0, "Meowville: mint limit reached"); require(_nextTokenId() <= maxSupply, "Meowville: sold out"); require( block.timestamp > waveRanges[currentWave].whitelists[1].end, "Meowville: public mint not live" ); publicMintLimit[currentWave][_receiver] = 1; _mint(_receiver, 1); } function whitelist1Mint(address _receiver, bytes32[] calldata _merkleProof) external payable { require(msg.sender == blazeManager, "Meowville: only BlazeManager can mint"); require(_nextTokenId() <= maxSupply, "Meowville: sold out"); require( whitelistClaims[keccak256(abi.encode(currentWave, 0, _receiver))] == false, "Meowville: already claimed" ); Whitelist memory wl = waveRanges[currentWave].whitelists[0]; require( block.timestamp >= wl.start && block.timestamp <= wl.end, "Meowville: whitelist mint not active" ); bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(_receiver)))); if (!MerkleProofLib.verify(_merkleProof, wl.merkleRoot, leaf)) { revert("Meowville: invalid proof"); } whitelistClaims[keccak256(abi.encode(currentWave, 0, _receiver))] = true; _mint(_receiver, 1); } function whitelist2Mint(address _receiver, bytes32[] calldata _merkleProof) external payable { require(msg.sender == blazeManager, "Meowville: only BlazeManager can mint"); require(_nextTokenId() <= maxSupply, "Meowville: sold out"); require( whitelistClaims[keccak256(abi.encode(currentWave, 1, _receiver))] == false, "Meowville: already claimed" ); Whitelist memory wl = waveRanges[currentWave].whitelists[1]; require( block.timestamp >= wl.start && block.timestamp <= wl.end, "Meowville: whitelist mint not active" ); bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(_receiver)))); if (!MerkleProofLib.verify(_merkleProof, wl.merkleRoot, leaf)) { revert("Meowville: invalid proof"); } whitelistClaims[keccak256(abi.encode(currentWave, 1, _receiver))] = true; _mint(_receiver, 1); } function tokenURI(uint256 _tokenId) public view override returns (string memory _uri) { require(_exists(_tokenId), "ERC721Metadata: URI query for nonexistent token"); for (uint256 i; i < waveRanges.length; i++) { if (_tokenId <= waveRanges[i].supplyCap) { waveRanges[i].revealed ? _uri = string(abi.encodePacked(waveRanges[i].uri, LibString.toString(_tokenId))) : _uri = hiddenMetadataURI; } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.21; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; // forgefmt: disable-start // // // // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓██▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓██▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ // // // // forgefmt: disable-end import { ERC721A } from "ERC721A/ERC721A.sol"; import { ERC2981 } from "@solady/tokens/ERC2981.sol"; import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { LibString } from "@solady/utils/LibString.sol"; import { MerkleProofLib } from "@solady/utils/MerkleProofLib.sol"; import { IBlast } from "src/lib/IBlast.sol"; import { IBlastPoints } from "src/lib/IBlastPoints.sol"; import { BlazeTypeStorage, Locks, WhitelistPhase } from "src/lib/Structs.sol"; import { BLAST, BLAST_POINTS_MAINNET, POINTS_OPERATOR, MAX_ROYALTY } from "src/lib/Constants.sol"; import "src/lib/Errors.sol"; /// @title BlazeTypeBase /// @author www.blaze.ong /// @notice The base contract for traditional and refundable Blaze collections. contract BlazeTypeBase is ERC721A, ERC2981, Ownable2Step { // ------------------------------------------------------------------------- // Storage // ------------------------------------------------------------------------- BlazeTypeStorage public btStorage; Locks public locks; /// @notice The BlazeManager for the collection. address internal immutable manager; /// @notice The amount of funds recived from all mints. uint256 internal _totalFundsReceived; /// @notice Mapping for tracking whitelist claims. mapping(uint8 phase => mapping(address listee => uint256)) public whitelistClaims; /// @notice Mapping for tracking public mints. mapping(address => uint256) public publicMints; bool internal _mintingClosed; // ------------------------------------------------------------------------- // Events // ------------------------------------------------------------------------- /// @notice Emitted when the collection owner stops the public mint. event StopMint(); /// @notice Emitted when the `baseURI` is updated via `setBaseURI()`. event SetBaseURI(); /// @notice Emitted when the `contractURI` is updated via `setContractURI()`. event SetContractURI(); /// @notice Emitted when the `maxSupply` is updated via `setMaxSupply()` or /// `stopMint()`. event SetMaxSupply(uint256 indexed newMaxSupply); /// @notice Emitted when the royalty parameters are updated via `setRoyaltyParams()`. event SetRoyaltyParameters( address indexed _royaltyReceiver, uint16 indexed _defaultRoyalty ); /// @notice BlazeTypeBase constructor /// @param _btStorage Initial storage parameters for the contract. /// @param _name The name of the NFT. /// @param _symbol The symbol of the NFT. /// @param _manager The BlazeManager for the collection. /// @param _owner The owner of the collection. constructor( BlazeTypeStorage memory _btStorage, string memory _name, string memory _symbol, uint256 _mintsToOwner, address _manager, address _owner ) ERC721A(_name, _symbol) Ownable(_owner) { if ( keccak256(bytes(_btStorage.baseURI)) == keccak256(bytes("")) || _btStorage.defaultRoyalty > MAX_ROYALTY || _mintsToOwner > _btStorage.maxSupply ) { revert InvalidParams(); } if (_btStorage.tokenCurrency != address(0)) { _validateTokenCurrency(_btStorage.tokenCurrency); } manager = _manager; btStorage = _btStorage; _validateWhitelistPhases(_btStorage.whitelistPhases); IBlast blast = IBlast(BLAST); blast.configureAutomaticYield(); blast.configureClaimableGas(); IBlastPoints(BLAST_POINTS_MAINNET).configurePointsOperator(POINTS_OPERATOR); _setDefaultRoyalty(_btStorage.royaltyReceiver, _btStorage.defaultRoyalty); if (_mintsToOwner > 0) _mint(_owner, _mintsToOwner); } // ------------------------------------------------------------------------- // ERC-721 // ------------------------------------------------------------------------- function supportsInterface(bytes4 interfaceId) public view override(ERC721A, ERC2981) returns (bool) { return ERC721A.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId); } function tokenURI(uint256 _tokenId) public view override returns (string memory) { if (!_exists(_tokenId)) revert TokenDoesNotExist(); return string(abi.encodePacked(btStorage.baseURI, LibString.toString(_tokenId))); } // ------------------------------------------------------------------------- // ERC-7572 // ------------------------------------------------------------------------- function contractURI() external view returns (string memory) { return btStorage.contractURI; } // ------------------------------------------------------------------------- // External // ------------------------------------------------------------------------- /// @notice Returns the whitelist phases for the NFT. /// @return The array of whitelist phases. function whitelistPhases() external view returns (WhitelistPhase[] memory) { return btStorage.whitelistPhases; } /// @notice Mints an NFT to `_to`. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFTs to mint. function mint(address _to, uint256 _amount) external payable virtual { _preliminaryMintChecks(_amount); _handleMint(_to, _amount); } /// @notice Mints an NFT for a whitelisted address /// @param _phase The whitelist phase. /// @param _merkleProof The merkle proof for the whitelist. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFTs to mint. function whitelistMint( uint8 _phase, bytes32[] calldata _merkleProof, address _to, uint256 _amount ) external payable virtual { _preliminaryMintChecks(_amount); _handleWhitelistMint(_phase, _merkleProof, _to, _amount); } // ------------------------------------------------------------------------- // OnlyOwner // ------------------------------------------------------------------------- /// @notice Updates collection btStorage in a batch. function ownerBatch(bytes[] calldata _calls) external onlyOwner returns (bytes[] memory results) { results = new bytes[](_calls.length); for (uint256 i; i < _calls.length; i++) { (bool success, bytes memory returnData) = address(this).delegatecall(_calls[i]); if (!success) { handleReturnData(returnData, "BlazeManager: whitelist mint failed"); } results[i] = returnData; } } /// @notice Allows owner to arbitrarily end public mint capping supply at the current /// amount. function stopMint() external onlyOwner { _mintingClosed = true; uint256 newMaxSupply = _nextTokenId(); btStorage.maxSupply = newMaxSupply; emit StopMint(); emit SetMaxSupply(newMaxSupply); } /// @notice Allows the owner to claim the yield generated from the mints. /// @param _receiver The address receiving the yield on behalf of the owner. function claimYield(address _receiver) external onlyOwner { IBlast(BLAST).claimAllYield(address(this), _receiver); } /// @notice Allows the owner to claim a specific amount of yield. /// @param _receiver The address receiving the yield on behalf of the owner. /// @param _amount The amount of yield to claim. function claimYield(address _receiver, uint256 _amount) external onlyOwner { IBlast(BLAST).claimYield(address(this), _receiver, _amount); } /// @notice Allows the owner to claim gas fees on the collection. /// @param _receiver The address receiving the gas fees on behalf of the owner. /// @param _minClaimRateBips The minimum claim rate in bips. function claimGasFees(address _receiver, uint256 _minClaimRateBips) external onlyOwner { IBlast(BLAST).claimGasAtMinClaimRate(address(this), _receiver, _minClaimRateBips); } /// @notice Setter for `baseURI`. /// @param _baseUri The `baseURI` for the NFTs. function setBaseURI(string calldata _baseUri) external onlyOwner { if (locks.baseURILocked) revert BaseURILocked(); btStorage.baseURI = _baseUri; emit SetBaseURI(); } /// @notice Permanently locks `baseURI`. function lockBaseURI() external onlyOwner { locks.baseURILocked = true; } /// @notice Setter for `contractURI`. /// @param _contractURI The `contractURI` for the NFTs. function setContractURI(string calldata _contractURI) external onlyOwner { if (locks.contractURILocked) revert ContractURILocked(); btStorage.contractURI = _contractURI; emit SetContractURI(); } /// @notice Permanently locks `contractURI`. function lockContractURI() external onlyOwner { locks.contractURILocked = true; } /// @notice Setter for `maxSupply`. /// @param _newMaxSupply The new maximum supply for the NFTs. function setMaxSupply(uint256 _newMaxSupply) external onlyOwner { _validateParamUpdate(); if (_newMaxSupply < _nextTokenId()) revert InvalidMaxSupply(); btStorage.maxSupply = _newMaxSupply; emit SetMaxSupply(_newMaxSupply); } /// @notice Sets the mint price for the public mint. /// @param _mintPrice The mint price for the public mint. function setMintPrice(uint120 _mintPrice) external onlyOwner { _validateParamUpdate(); btStorage.mintPrice = _mintPrice; } /// @notice Sets the mint price for the given whitelist phase. /// @param _phase The whitelist phase to set the mint price for. /// @param _whitelistMintPrice The mint price for the whitelist phase. function setWhitelistMintPrice(uint8 _phase, uint120 _whitelistMintPrice) external onlyOwner { _validateParamUpdate(); btStorage.whitelistPhases[_phase].whitelistMintPrice = _whitelistMintPrice; } /// @notice Setter for the receiving address and bps for royalties. /// @param _royaltyReceiver The receiving address for any royalties. /// @param _defaultRoyalty The bps for royalties. function setRoyaltyParams(address _royaltyReceiver, uint16 _defaultRoyalty) external onlyOwner { if (locks.royaltyParamsLocked) revert RoyaltyParamsLocked(); if (_defaultRoyalty > MAX_ROYALTY) revert InvalidDefaultRoyalty(); btStorage.royaltyReceiver = _royaltyReceiver; btStorage.defaultRoyalty = _defaultRoyalty; _setDefaultRoyalty(_royaltyReceiver, _defaultRoyalty); emit SetRoyaltyParameters(_royaltyReceiver, _defaultRoyalty); } /// @notice Permanently locks `royaltyReceiver` and `defaultRoyalty`. function lockRoyaltyParams() external onlyOwner { locks.royaltyParamsLocked = true; } function rescue(address _token, address _to) external onlyOwner { if (_token == address(0)) { uint256 amount = address(this).balance; if (_token == btStorage.tokenCurrency) amount -= _totalFundsReceived; (bool success,) = _to.call{ value: amount }(""); require(success, "Native transfer failed"); } else { uint256 amount = IERC20(_token).balanceOf(address(this)); if (_token == btStorage.tokenCurrency) amount -= _totalFundsReceived; IERC20(_token).transfer(_to, amount); } } function rescueERC721(address _token, uint256[] calldata _ids, address _to) external onlyOwner { for (uint256 i = 0; i < _ids.length; i++) { IERC721(_token).transferFrom(address(this), _to, _ids[i]); } } // ------------------------------------------------------------------------- // Internal // ------------------------------------------------------------------------- function _validateTokenCurrency(address tokenCurrency) internal pure { if (tokenCurrency == 0x4300000000000000000000000000000000000003) return; // USDB if (tokenCurrency == 0xb1a5700fA2358173Fe465e6eA4Ff52E36e88E2ad) return; // BLAST if (tokenCurrency == 0x5ffd9EbD27f2fcAB044c0f0a26A45Cb62fa29c06) return; // PAC if (tokenCurrency == 0xd43D8aDAC6A4C7d9Aeece7c3151FcA8f23752cf8) return; // ANDY revert InvalidCurrency(); } /// @notice Checks done for both whitelist and public mints. /// @param _amount Amount of NFTs to mint. function _preliminaryMintChecks(uint256 _amount) internal view { if (msg.sender != manager) revert Unauthorized(); if (_nextTokenId() + _amount > btStorage.maxSupply) revert MaxSupplyReached(); } /// @notice Validates and handles public mints. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFTs to mint. function _handleMint(address _to, uint256 _amount) internal { // Mint validation if ( btStorage.start > block.timestamp || btStorage.end <= block.timestamp || _mintingClosed ) { revert MintNotActive(); } if (_amount > btStorage.maxMintsPerCall) revert MaxMintsReached(); if (publicMints[_to] + _amount > btStorage.maxTotalMints) { revert MaxTotalMintsReached(); } // Mint handling uint256 totalPrice = btStorage.mintPrice * _amount; if (btStorage.tokenCurrency == address(0)) { if (msg.value < totalPrice) revert InsufficientFunds(); } else { IERC20 token = IERC20(btStorage.tokenCurrency); token.transferFrom(msg.sender, address(this), totalPrice); } publicMints[_to] += _amount; _totalFundsReceived += totalPrice; _mint(_to, _amount); } /// @notice Validates and handles whitelist mints. /// @param _phase The whitelist phase. /// @param _merkleProof The merkle proof for the whitelist. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFTs to mint. function _handleWhitelistMint( uint8 _phase, bytes32[] calldata _merkleProof, address _to, uint256 _amount ) internal { // Mint validation WhitelistPhase memory thisPhase = btStorage.whitelistPhases[_phase]; if (thisPhase.start > block.timestamp || thisPhase.end <= block.timestamp) { revert WhitelistPhaseNotActive(); } if (_amount > thisPhase.maxWhitelistMintsPerCall) revert MaxWhitelistMintsReached(); if (whitelistClaims[_phase][_to] + _amount > thisPhase.maxTotalWhitelistMints) { revert MaxTotalWhitelistMintsReached(); } bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(_to)))); if (!MerkleProofLib.verifyCalldata(_merkleProof, thisPhase.merkleRoot, leaf)) { revert InvalidMerkleProof(); } // Mint handling uint256 totalPrice = thisPhase.whitelistMintPrice * _amount; if (btStorage.tokenCurrency == address(0)) { if (msg.value < totalPrice) revert InsufficientFunds(); } else { IERC20 token = IERC20(btStorage.tokenCurrency); token.transferFrom(msg.sender, address(this), totalPrice); } whitelistClaims[_phase][_to] += _amount; _totalFundsReceived += totalPrice; _mint(_to, _amount); } /// @notice Validates whitelist phases. /// @param _phases The whitelist phases to be validated. function _validateWhitelistPhases(WhitelistPhase[] memory _phases) internal view { // Check for length > 3 if (_phases.length > 3) revert InvalidWhitelistPhases(); // Check that phase start must be before phase end, phase ends must be before public // mint start, and that phases do not overlap. uint256 prevEnd; for (uint256 i; i < _phases.length;) { if ( _phases[i].start > _phases[i].end || _phases[i].end > btStorage.start || (_phases[i].start != 0 && _phases[i].start <= prevEnd) || (_phases[i].start == 0 && _phases[i].end != 0) ) { revert InvalidWhitelistPhases(); } prevEnd = _phases[i].end; unchecked { ++i; } } } /// @notice Checks that minting is active and reverts if true. Ensures parameters cannot /// be changed during minting phases. function _validateParamUpdate() internal view { if (block.timestamp > btStorage.start && block.timestamp < btStorage.end) { revert MintingActive(); } for (uint256 i; i < btStorage.whitelistPhases.length;) { if ( block.timestamp > btStorage.whitelistPhases[i].start && block.timestamp < btStorage.whitelistPhases[i].end ) revert MintingActive(); unchecked { ++i; } } } function handleReturnData(bytes memory returnData, string memory errorMessage) internal pure { if (returnData.length > 0) { assembly { let returndata_size := mload(returnData) revert(add(32, returnData), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice Emitted when `baseURI` is empty or `protocolFee` is above `MAX_BPS`. error InvalidParams(); /// @notice Emitted when the phase end is before the start. error InvalidWhitelistPhases(); /// @notice Emitted when the `lockupPeriod` value is not valid. error InvalidLockupPeriod(); /// @notice Emitted if the `_tokenId` for `tokenURI()` does not exist. error TokenDoesNotExist(); /// @notice Emitted if the public mint hasn't started or has already ended. error MintNotActive(); /// @notice Emitted if the whitelist phase hasn't started or has already ended. error WhitelistPhaseNotActive(); /// @notice Emitted if the amount for `mint()` or `whitelistMint()` would exceed the /// `maxSupply`. error MaxSupplyReached(); /// @notice Emitted if `_amount` for `mint()` exceeds the maximum amount mintable per tx. error MaxMintsReached(); /// @notice Emitted if `_amount` for `whitelistMint()` exceeds the maximum amount mintable /// per tx. error MaxWhitelistMintsReached(); /// @notice Emitted if the caller to `mint()` would exceed the max mints per address. error MaxTotalMintsReached(); /// @notice Emitted if the caller to `whitelistMint()` would exceed the max mints per /// address. error MaxTotalWhitelistMintsReached(); /// @notice Emitted when calls to withdraw funds fail. error WithdrawalFailed(); /// @notice Emitted if the token currency is set and `msg.value` is not zero. error InvalidCurrency(); /// @notice Emitted if `msg.value` is too low in `mint()` or `whitelistMint()` or if /// the amount to `claimYield()` is too high. error InsufficientFunds(); /// @notice Emitted if the `_merkleProof` provided to `whitelistMint()` is invalid. error InvalidMerkleProof(); /// @notice Emitted if a function is called for an invalid mint mode. error InvalidMode(); /// @notice Emitted if the lockup period for the refund has not ended. error LockupIncomplete(); /// @notice Emittted if the `_tokenId` for `refund()` was minted to the owner. error NonRefundable(); /// @notice Emitted if the `_tokenId` for `renounceRefund()` was minted to the owner. error NonRenounceable(); /// @notice Emitted if the `_tokenId` for `refund()` has already been refunded. error RefundRenounced(); /// @notice Emitted if the `_tokenId` for `renounceRefund()` has already been refunded. error Refunded(); /// @notice Emitted if the caller to `renounceRefund()` is not the token owner. error Unauthorized(); /// @notice Emitted if `baseURI` has been locked. error BaseURILocked(); /// @notice Emitted if `contractURI` has been locked. error ContractURILocked(); /// @notice Emitted if a new max supply would be lower than present total supply. error InvalidMaxSupply(); /// @notice Emitted if `royaltyLocked` is true. error RoyaltyParamsLocked(); /// @notice Emitted if the default royalty is too high in 'setRoyaltyParams()` error InvalidDefaultRoyalty(); /// @notice Emitted if setters affecting mints are called while minting is live. error MintingActive();
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.3.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721A.sol'; /** * @dev Interface of ERC721 token receiver. */ interface ERC721A__IERC721Receiver { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @title ERC721A * * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) * Non-Fungible Token Standard, including the Metadata extension. * Optimized for lower gas during batch mints. * * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) * starting from `_startTokenId()`. * * The `_sequentialUpTo()` function can be overriden to enable spot mints * (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`. * * Assumptions: * * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721A is IERC721A { // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364). struct TokenApprovalRef { address value; } // ============================================================= // CONSTANTS // ============================================================= // Mask of an entry in packed address data. uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; // The bit position of `numberMinted` in packed address data. uint256 private constant _BITPOS_NUMBER_MINTED = 64; // The bit position of `numberBurned` in packed address data. uint256 private constant _BITPOS_NUMBER_BURNED = 128; // The bit position of `aux` in packed address data. uint256 private constant _BITPOS_AUX = 192; // Mask of all 256 bits in packed address data except the 64 bits for `aux`. uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; // The bit position of `startTimestamp` in packed ownership. uint256 private constant _BITPOS_START_TIMESTAMP = 160; // The bit mask of the `burned` bit in packed ownership. uint256 private constant _BITMASK_BURNED = 1 << 224; // The bit position of the `nextInitialized` bit in packed ownership. uint256 private constant _BITPOS_NEXT_INITIALIZED = 225; // The bit mask of the `nextInitialized` bit in packed ownership. uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225; // The bit position of `extraData` in packed ownership. uint256 private constant _BITPOS_EXTRA_DATA = 232; // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; // The mask of the lower 160 bits for addresses. uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; // The maximum `quantity` that can be minted with {_mintERC2309}. // This limit is to prevent overflows on the address data entries. // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} // is required to cause an overflow, which is unrealistic. uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; // The `Transfer` event signature is given by: // `keccak256(bytes("Transfer(address,address,uint256)"))`. bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; // ============================================================= // STORAGE // ============================================================= // The next token ID to be minted. uint256 private _currentIndex; // The number of tokens burned. uint256 private _burnCounter; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to ownership details // An empty struct value does not necessarily mean the token is unowned. // See {_packedOwnershipOf} implementation for details. // // Bits Layout: // - [0..159] `addr` // - [160..223] `startTimestamp` // - [224] `burned` // - [225] `nextInitialized` // - [232..255] `extraData` mapping(uint256 => uint256) private _packedOwnerships; // Mapping owner address to address data. // // Bits Layout: // - [0..63] `balance` // - [64..127] `numberMinted` // - [128..191] `numberBurned` // - [192..255] `aux` mapping(address => uint256) private _packedAddressData; // Mapping from token ID to approved address. mapping(uint256 => TokenApprovalRef) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // The amount of tokens minted above `_sequentialUpTo()`. // We call these spot mints (i.e. non-sequential mints). uint256 private _spotMinted; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _currentIndex = _startTokenId(); if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector); } // ============================================================= // TOKEN COUNTING OPERATIONS // ============================================================= /** * @dev Returns the starting token ID for sequential mints. * * Override this function to change the starting token ID for sequential mints. * * Note: The value returned must never change after any tokens have been minted. */ function _startTokenId() internal view virtual returns (uint256) { return 0; } /** * @dev Returns the maximum token ID (inclusive) for sequential mints. * * Override this function to return a value less than 2**256 - 1, * but greater than `_startTokenId()`, to enable spot (non-sequential) mints. * * Note: The value returned must never change after any tokens have been minted. */ function _sequentialUpTo() internal view virtual returns (uint256) { return type(uint256).max; } /** * @dev Returns the next token ID to be minted. */ function _nextTokenId() internal view virtual returns (uint256) { return _currentIndex; } /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() public view virtual override returns (uint256 result) { // Counter underflow is impossible as `_burnCounter` cannot be incremented // more than `_currentIndex + _spotMinted - _startTokenId()` times. unchecked { // With spot minting, the intermediate `result` can be temporarily negative, // and the computation must be unchecked. result = _currentIndex - _burnCounter - _startTokenId(); if (_sequentialUpTo() != type(uint256).max) result += _spotMinted; } } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view virtual returns (uint256 result) { // Counter underflow is impossible as `_currentIndex` does not decrement, // and it is initialized to `_startTokenId()`. unchecked { result = _currentIndex - _startTokenId(); if (_sequentialUpTo() != type(uint256).max) result += _spotMinted; } } /** * @dev Returns the total number of tokens burned. */ function _totalBurned() internal view virtual returns (uint256) { return _burnCounter; } /** * @dev Returns the total number of tokens that are spot-minted. */ function _totalSpotMinted() internal view virtual returns (uint256) { return _spotMinted; } // ============================================================= // ADDRESS DATA OPERATIONS // ============================================================= /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) public view virtual override returns (uint256) { if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector); return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens minted by `owner`. */ function _numberMinted(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens burned by or on behalf of `owner`. */ function _numberBurned(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). */ function _getAux(address owner) internal view returns (uint64) { return uint64(_packedAddressData[owner] >> _BITPOS_AUX); } /** * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). * If there are multiple variables, please pack them into a uint64. */ function _setAux(address owner, uint64 aux) internal virtual { uint256 packed = _packedAddressData[owner]; uint256 auxCasted; // Cast `aux` with assembly to avoid redundant masking. assembly { auxCasted := aux } packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); _packedAddressData[owner] = packed; } // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { // The interface IDs are constants representing the first 4 bytes // of the XOR of all function selectors in the interface. // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165) // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`) return interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. } // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the token collection symbol. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector); string memory baseURI = _baseURI(); return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, it can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } // ============================================================= // OWNERSHIPS OPERATIONS // ============================================================= /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } /** * @dev Gas spent here starts off proportional to the maximum mint batch size. * It gradually moves to O(1) as tokens get transferred around over time. */ function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnershipOf(tokenId)); } /** * @dev Returns the unpacked `TokenOwnership` struct at `index`. */ function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnerships[index]); } /** * @dev Returns whether the ownership slot at `index` is initialized. * An uninitialized slot does not necessarily mean that the slot has no owner. */ function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) { return _packedOwnerships[index] != 0; } /** * @dev Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal virtual { if (_packedOwnerships[index] == 0) { _packedOwnerships[index] = _packedOwnershipOf(index); } } /** * @dev Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) { if (_startTokenId() <= tokenId) { packed = _packedOwnerships[tokenId]; if (tokenId > _sequentialUpTo()) { if (_packedOwnershipExists(packed)) return packed; _revert(OwnerQueryForNonexistentToken.selector); } // If the data at the starting slot does not exist, start the scan. if (packed == 0) { if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector); // Invariant: // There will always be an initialized ownership slot // (i.e. `ownership.addr != address(0) && ownership.burned == false`) // before an unintialized ownership slot // (i.e. `ownership.addr == address(0) && ownership.burned == false`) // Hence, `tokenId` will not underflow. // // We can directly compare the packed value. // If the address is zero, packed will be zero. for (;;) { unchecked { packed = _packedOwnerships[--tokenId]; } if (packed == 0) continue; if (packed & _BITMASK_BURNED == 0) return packed; // Otherwise, the token is burned, and we must revert. // This handles the case of batch burned tokens, where only the burned bit // of the starting slot is set, and remaining slots are left uninitialized. _revert(OwnerQueryForNonexistentToken.selector); } } // Otherwise, the data exists and we can skip the scan. // This is possible because we have already achieved the target condition. // This saves 2143 gas on transfers of initialized tokens. // If the token is not burned, return `packed`. Otherwise, revert. if (packed & _BITMASK_BURNED == 0) return packed; } _revert(OwnerQueryForNonexistentToken.selector); } /** * @dev Returns the unpacked `TokenOwnership` struct from `packed`. */ function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { ownership.addr = address(uint160(packed)); ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); ownership.burned = packed & _BITMASK_BURNED != 0; ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); } /** * @dev Packs ownership data into a single uint256. */ function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) } } /** * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. */ function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { // For branchless setting of the `nextInitialized` flag. assembly { // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) } } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}. * * Requirements: * * - The caller must own the token or be an approved operator. */ function approve(address to, uint256 tokenId) public payable virtual override { _approve(to, tokenId, true); } /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); return _tokenApprovals[tokenId].value; } /** * @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) public virtual override { _operatorApprovals[_msgSenderERC721A()][operator] = approved; emit ApprovalForAll(_msgSenderERC721A(), operator, approved); } /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted. See {_mint}. */ function _exists(uint256 tokenId) internal view virtual returns (bool result) { if (_startTokenId() <= tokenId) { if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]); if (tokenId < _currentIndex) { uint256 packed; while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId; result = packed & _BITMASK_BURNED == 0; } } } /** * @dev Returns whether `packed` represents a token that exists. */ function _packedOwnershipExists(uint256 packed) private pure returns (bool result) { assembly { // The following is equivalent to `owner != address(0) && burned == false`. // Symbolically tested. result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED)) } } /** * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. */ function _isSenderApprovedOrOwner( address approvedAddress, address owner, address msgSender ) private pure returns (bool result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. msgSender := and(msgSender, _BITMASK_ADDRESS) // `msgSender == owner || msgSender == approvedAddress`. result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) } } /** * @dev Returns the storage slot and value for the approved address of `tokenId`. */ function _getApprovedSlotAndAddress(uint256 tokenId) private view returns (uint256 approvedAddressSlot, address approvedAddress) { TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId]; // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. assembly { approvedAddressSlot := tokenApproval.slot approvedAddress := sload(approvedAddressSlot) } } // ============================================================= // TRANSFER OPERATIONS // ============================================================= /** * @dev Transfers `tokenId` from `from` to `to`. * * 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 ) public payable virtual override { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS)); if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); _beforeTokenTransfers(from, to, tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // We can directly increment and decrement the balances. --_packedAddressData[from]; // Updates: `balance -= 1`. ++_packedAddressData[to]; // Updates: `balance += 1`. // Updates: // - `address` to the next owner. // - `startTimestamp` to the timestamp of transfering. // - `burned` to `false`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( to, _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. from, // `from`. toMasked, // `to`. tokenId // `tokenId`. ) } if (toMasked == 0) _revert(TransferToZeroAddress.selector); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public payable virtual override { safeTransferFrom(from, to, tokenId, ''); } /** * @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 memory _data ) public payable virtual override { transferFrom(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } /** * @dev Hook that is called before a set of serially-ordered token IDs * are about to be transferred. This includes minting. * And also called before burning one token. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Hook that is called after a set of serially-ordered token IDs * have been transferred. This includes minting. * And also called after one token has been burned. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been * transferred to `to`. * - When `from` is zero, `tokenId` has been minted for `to`. * - When `to` is zero, `tokenId` has been burned by `from`. * - `from` and `to` are never both zero. */ function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract. * * `from` - Previous owner of the given token ID. * `to` - Target address that will receive the token. * `tokenId` - Token ID to be transferred. * `_data` - Optional data to send along with the call. * * Returns whether the call correctly returned the expected magic value. */ function _checkContractOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( bytes4 retval ) { return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { _revert(TransferToNonERC721ReceiverImplementer.selector); } assembly { revert(add(32, reason), mload(reason)) } } } // ============================================================= // MINT OPERATIONS // ============================================================= /** * @dev Mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {Transfer} event for each mint. */ function _mint(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (quantity == 0) _revert(MintZeroQuantity.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // `balance` and `numberMinted` have a maximum limit of 2**64. // `tokenId` has a maximum limit of 2**256. unchecked { // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; if (toMasked == 0) _revert(MintToZeroAddress.selector); uint256 end = startTokenId + quantity; uint256 tokenId = startTokenId; if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector); do { assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. tokenId // `tokenId`. ) } // The `!=` check ensures that large values of `quantity` // that overflows uint256 will make the loop run out of gas. } while (++tokenId != end); _currentIndex = end; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Mints `quantity` tokens and transfers them to `to`. * * This function is intended for efficient minting only during contract creation. * * It emits only one {ConsecutiveTransfer} as defined in * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), * instead of a sequence of {Transfer} event(s). * * Calling this function outside of contract creation WILL make your contract * non-compliant with the ERC721 standard. * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 * {ConsecutiveTransfer} event is only permissible during contract creation. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {ConsecutiveTransfer} event. */ function _mintERC2309(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (to == address(0)) _revert(MintToZeroAddress.selector); if (quantity == 0) _revert(MintZeroQuantity.selector); if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are unrealistic due to the above check for `quantity` to be below the limit. unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector); emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); _currentIndex = startTokenId + quantity; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Safely mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. * - `quantity` must be greater than 0. * * See {_mint}. * * Emits a {Transfer} event for each mint. */ function _safeMint( address to, uint256 quantity, bytes memory _data ) internal virtual { _mint(to, quantity); unchecked { if (to.code.length != 0) { uint256 end = _currentIndex; uint256 index = end - quantity; do { if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } while (index < end); // This prevents reentrancy to `_safeMint`. // It does not prevent reentrancy to `_safeMintSpot`. if (_currentIndex != end) revert(); } } } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal virtual { _safeMint(to, quantity, ''); } /** * @dev Mints a single token at `tokenId`. * * Note: A spot-minted `tokenId` that has been burned can be re-minted again. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` must be greater than `_sequentialUpTo()`. * - `tokenId` must not exist. * * Emits a {Transfer} event for each mint. */ function _mintSpot(address to, uint256 tokenId) internal virtual { if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector); uint256 prevOwnershipPacked = _packedOwnerships[tokenId]; if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector); _beforeTokenTransfers(address(0), to, tokenId, 1); // Overflows are incredibly unrealistic. // The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1. // `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1. unchecked { // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `true` (as `quantity == 1`). _packedOwnerships[tokenId] = _packOwnershipData( to, _nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked) ); // Updates: // - `balance += 1`. // - `numberMinted += 1`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1; // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; if (toMasked == 0) _revert(MintToZeroAddress.selector); assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. tokenId // `tokenId`. ) } ++_spotMinted; } _afterTokenTransfers(address(0), to, tokenId, 1); } /** * @dev Safely mints a single token at `tokenId`. * * Note: A spot-minted `tokenId` that has been burned can be re-minted again. * * Requirements: * * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}. * - `tokenId` must be greater than `_sequentialUpTo()`. * - `tokenId` must not exist. * * See {_mintSpot}. * * Emits a {Transfer} event. */ function _safeMintSpot( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mintSpot(to, tokenId); unchecked { if (to.code.length != 0) { uint256 currentSpotMinted = _spotMinted; if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } // This prevents reentrancy to `_safeMintSpot`. // It does not prevent reentrancy to `_safeMint`. if (_spotMinted != currentSpotMinted) revert(); } } } /** * @dev Equivalent to `_safeMintSpot(to, tokenId, '')`. */ function _safeMintSpot(address to, uint256 tokenId) internal virtual { _safeMintSpot(to, tokenId, ''); } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Equivalent to `_approve(to, tokenId, false)`. */ function _approve(address to, uint256 tokenId) internal virtual { _approve(to, tokenId, false); } /** * @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: * * - `tokenId` must exist. * * Emits an {Approval} event. */ function _approve( address to, uint256 tokenId, bool approvalCheck ) internal virtual { address owner = ownerOf(tokenId); if (approvalCheck && _msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) { _revert(ApprovalCallerNotOwnerNorApproved.selector); } _tokenApprovals[tokenId].value = to; emit Approval(owner, to, tokenId); } // ============================================================= // BURN OPERATIONS // ============================================================= /** * @dev Equivalent to `_burn(tokenId, false)`. */ function _burn(uint256 tokenId) internal virtual { _burn(tokenId, false); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId, bool approvalCheck) internal virtual { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); address from = address(uint160(prevOwnershipPacked)); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); if (approvalCheck) { // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); } _beforeTokenTransfers(from, address(0), tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // Updates: // - `balance -= 1`. // - `numberBurned += 1`. // // We can directly decrement the balance, and increment the number burned. // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; // Updates: // - `address` to the last owner. // - `startTimestamp` to the timestamp of burning. // - `burned` to `true`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( from, (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } emit Transfer(from, address(0), tokenId); _afterTokenTransfers(from, address(0), tokenId, 1); // Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times. unchecked { _burnCounter++; } } // ============================================================= // EXTRA DATA OPERATIONS // ============================================================= /** * @dev Directly sets the extra data for the ownership data `index`. */ function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { uint256 packed = _packedOwnerships[index]; if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector); uint256 extraDataCasted; // Cast `extraData` with assembly to avoid redundant masking. assembly { extraDataCasted := extraData } packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); _packedOwnerships[index] = packed; } /** * @dev Called during each token transfer to set the 24bit `extraData` field. * Intended to be overridden by the cosumer contract. * * `previousExtraData` - the value of `extraData` before transfer. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _extraData( address from, address to, uint24 previousExtraData ) internal view virtual returns (uint24) {} /** * @dev Returns the next extra data for the packed ownership data. * The returned result is shifted into position. */ function _nextExtraData( address from, address to, uint256 prevOwnershipPacked ) private view returns (uint256) { uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; } // ============================================================= // OTHER OPERATIONS // ============================================================= /** * @dev Returns the message sender (defaults to `msg.sender`). * * If you are writing GSN compatible contracts, you need to override this function. */ function _msgSenderERC721A() internal view virtual returns (address) { return msg.sender; } /** * @dev Converts a uint256 to its ASCII string decimal representation. */ function _toString(uint256 value) internal pure virtual returns (string memory str) { assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0. let m := add(mload(0x40), 0xa0) // Update the free memory pointer to allocate. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) // prettier-ignore if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /** * @dev For more efficient reverts. */ function _revert(bytes4 errorSelector) internal pure { assembly { mstore(0x00, errorSelector) revert(0x00, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * Since version 5.1, this library also support writing and reading value types to and from transient storage. * * * Example using transient storage: * ```solidity * contract Lock { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev UDVT that represent a slot holding a address. */ type AddressSlotType is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlotType. */ function asAddress(bytes32 slot) internal pure returns (AddressSlotType) { return AddressSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlotType is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlotType. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlotType) { return BooleanSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32SlotType. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32SlotType) { return Bytes32SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Uint256SlotType. */ function asUint256(bytes32 slot) internal pure returns (Uint256SlotType) { return Uint256SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Int256SlotType. */ function asInt256(bytes32 slot) internal pure returns (Int256SlotType) { return Int256SlotType.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlotType slot) internal view returns (address value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlotType slot, address value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlotType slot) internal view returns (bool value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlotType slot, bool value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32SlotType slot) internal view returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32SlotType slot, bytes32 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256SlotType slot) internal view returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256SlotType slot, uint256 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256SlotType slot) internal view returns (int256 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256SlotType slot, int256 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This extension of the {Ownable} contract includes a two-step mechanism to transfer * ownership, where the new owner must call {acceptOwnership} in order to replace the * old one. This can help prevent common mistakes, such as transfers of ownership to * incorrect accounts, or to contracts that are unable to interact with the * permission system. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 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 ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * 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); }
pragma solidity ^0.8.20; interface IBlastPoints { function configurePointsOperator(address operator) external; function configurePointsOperatorOnBehalf(address contractAddress, address operator) external; }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.3.0 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of ERC721A. */ interface IERC721A { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); /** * `_sequentialUpTo()` must be greater than `_startTokenId()`. */ error SequentialUpToTooSmall(); /** * The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`. */ error SequentialMintExceedsLimit(); /** * Spot minting requires a `tokenId` greater than `_sequentialUpTo()`. */ error SpotMintTokenIdTooSmall(); /** * Cannot mint over a token that already exists. */ error TokenAlreadyExists(); /** * The feature is not compatible with spot mints. */ error NotCompatibleWithSpotMints(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables * (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, * checking first that contract recipients are aware of the ERC721 protocol * to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move * this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external payable; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Transfers `tokenId` from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} * whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external payable; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) external view returns (bool); // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); // ============================================================= // IERC2309 // ============================================================= /** * @dev Emitted when tokens in `fromTokenId` to `toTokenId` * (inclusive) is transferred from `from` to `to`, as defined in the * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. * * See {_mintERC2309} for more details. */ event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../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. * * The initial owner is set to the address provided by the deployer. 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; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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 { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _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 (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC 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 v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
{ "remappings": [ "ERC721A/=lib/ERC721A/contracts/", "gaslite-core/=lib/gaslite-core/src/", "multicall/=lib/multicall/src/", "@murky/=lib/murky/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity/", "@solady/=lib/solady/src/", "@ERC721A/=lib/gaslite-core/lib/ERC721A/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"blazeType","type":"address"}],"name":"DeployedBlazeType","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"blazeType","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MintedBlazeType","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"meowville","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"MintedMeowville","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"baseURI","type":"string"},{"internalType":"string","name":"contractURI","type":"string"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"mintPrice","type":"uint120"},{"internalType":"uint64","name":"maxMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalMints","type":"uint64"},{"internalType":"uint16","name":"defaultRoyalty","type":"uint16"},{"internalType":"address","name":"royaltyReceiver","type":"address"},{"internalType":"address","name":"tokenCurrency","type":"address"},{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"whitelistMintPrice","type":"uint120"},{"internalType":"uint64","name":"maxWhitelistMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalWhitelistMints","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct WhitelistPhase[]","name":"whitelistPhases","type":"tuple[]"}],"internalType":"struct BlazeTypeStorage","name":"_btStorage","type":"tuple"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_mintsToOwner","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"name":"deployBlazeType","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract BlazeType","name":"_blazeType","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBlazeType","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract Meowville","name":"_meow","type":"address"}],"name":"mintMeowville","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintFee","type":"uint256"}],"name":"setMintFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract BlazeType","name":"_blazeType","type":"address"},{"internalType":"uint8","name":"_phase","type":"uint8"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"whitelistMintBlazeType","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract Meowville","name":"_meow","type":"address"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"bool","name":"_first","type":"bool"}],"name":"whitelistMintMeowville","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60a080604052346100cc57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c166100bd57506001600160401b036002600160401b031982821601610078575b6040516156ff90816100d1823960805181818161052b0152610f240152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f8080610059565b63f92ee8a960e01b8152600490fd5b5f80fdfe6080604052600436101562000012575f80fd5b5f3560e01c8063174770ad14620000fe5780634f1ef28614620000f857806352d1902d14620000f25780636497ed2d14620000ec578063715018a614620000e65780638129fc1c14620000e05780638da5cb5b14620000da578063921b998214620000d4578063a907bfb414620000ce578063ad3cb1cc14620000c8578063d22a453914620000c2578063eddd0d9c14620000bc5763f2fde38b14620000b6575f80fd5b62000c73565b62000c4f565b62000ba1565b62000b2a565b62000a09565b620008a4565b6200086d565b62000787565b6200071b565b62000584565b62000517565b62000484565b6200014d565b6001600160a01b038116036200011657565b5f80fd5b9181601f8401121562000116578235916001600160401b03831162000116576020808501948460051b0101116200011657565b60603660031901126200011657600435620001688162000104565b6024356001600160401b03811162000116576200018a9036906004016200011a565b919060443592831592831585036200011657604051635e2d5fb560e01b81526001600160a01b0391909116939060c081600481885afa9182156200037b57620001f692620001e1925f916200039b575b5062000d3c565b51805142101590816200038b575b5062000d62565b5f808080805473a804b7d57a4a872dbfbe2987347403039ade20dc5af16200021d62000dbb565b90620002298162000e1e565b156200038157506040516318160ddd60e01b815293602085600481875afa9485156200037b575f956200033b575b505f928392909115620002fb576200029c6200028d9160405192839160208301956311d2fae760e31b8752336024850162000ea9565b03601f19810183528262000446565b519082855af1620002ac62000dbb565b905b15620002ea575060405191825233917f1d2fd770978c6eda249e6778a98091f102b8e977d255ad97a6972852376d83d19080602081015b0390a3005b620002f462000ed0565b9062001586565b620003246200028d91604051928391602083019563d3f186c160e01b8752336024850162000ea9565b519082855af16200033462000dbb565b90620002ae565b5f939195509162000368849360203d60201162000373575b6200035f818362000446565b81019062000e74565b959193509162000257565b503d62000353565b62000d31565b620002f462000e53565b6020915001514211155f620001ef565b620003c2915060c03d60c011620003c9575b620003b9818362000446565b81019062000ca8565b5f620001da565b503d620003ad565b3590620003de8262000104565b565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176200041057604052565b620003e0565b606081019081106001600160401b038211176200041057604052565b6001600160401b0381116200041057604052565b90601f801991011681019081106001600160401b038211176200041057604052565b6001600160401b0381116200041057601f01601f191660200190565b604036600319011262000116576004356200049f8162000104565b602435906001600160401b0382116200011657366023830112156200011657816004013590620004cf8262000468565b91620004df604051938462000446565b808352366024828601011162000116576020815f9260246200050a9701838701378401015262000f17565b005b5f9103126200011657565b3462000116575f36600319011262000116577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620005725760206040515f805160206200568a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b608036600319011262000116576004356200059f8162000104565b60243560ff8116810362000116576044356001600160401b0381116200011657620005cf9036906004016200011a565b60643591620005e0835f5462001045565b945f8080808973a804b7d57a4a872dbfbe2987347403039ade20dc5af16200060762000dbb565b90620006138162000e1e565b156200038157506040516318160ddd60e01b8152956001600160a01b03919091169490602087600481895afa9687156200037b575f97620006e0575b50915f93916200068c620006658695346200105f565b936200028d88604051948593602085019763725f060360e11b89523392602487016200106d565b5191865af16200069b62000dbb565b9015620002ea575060408051938452602084019190915233927f6407f8ca752db84010bc02df7ad41475b0a4db9c029c65f246ea482f020d1aa29181908101620002e5565b5f9492908594929850620006656200070d6200068c9260203d60201162000373576200035f818362000446565b99939550505091936200064f565b3462000116575f366003190112620001165762000737620015b8565b5f805160206200566a83398151915280546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3462000116575f36600319011262000116575f80516020620056aa833981519152805460ff8160401c16801562000858575b620008465767ffffffffffffffff191660021790555f80516020620056aa833981519152805460ff60401b191668010000000000000000179055620007fd620010a5565b5f80516020620056aa833981519152805460ff60401b19169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620007b9565b3462000116575f36600319011262000116575f805160206200566a833981519152546040516001600160a01b039091168152602090f35b60403660031901126200011657600435620008bf8162000104565b602435620008cf815f5462001045565b915f8080808673a804b7d57a4a872dbfbe2987347403039ade20dc5af1620008f662000dbb565b90620009028162000e1e565b156200038157506040516318160ddd60e01b8152926001600160a01b03919091169190602084600481865afa9384156200037b575f94620009da575b505f6200094d8192346200105f565b6040516340c10f1960e01b6020820190815233602483015260448201869052906200097c81606481016200028d565b5191865af16200098b62000dbb565b9015620009d0575060408051938452602084019190915233927f6407f8ca752db84010bc02df7ad41475b0a4db9c029c65f246ea482f020d1aa29181908101620002e5565b620002f46200117c565b5f9194506200094d620009ff839260203d60201162000373576200035f818362000446565b959250506200093e565b6020366003190112620001165760043562000a248162000104565b5f808080805473a804b7d57a4a872dbfbe2987347403039ade20dc5af162000a4b62000dbb565b9062000a578162000e1e565b156200038157506040516318160ddd60e01b8152906001600160a01b0316602082600481845afa9182156200037b575f9262000abb575b506040516335313c2160e11b602082019081523360248301525f918291906200029c81604481016200028d565b62000ad991925060203d60201162000373576200035f818362000446565b905f62000a8e565b602080825282518183018190529093925f5b82811062000b1557505060409293505f838284010152601f8019910116010190565b81810186015184820160400152850162000af3565b3462000116575f366003190112620001165762000b6d60405162000b4e81620003f4565b60058152640352e302e360dc1b60208201526040519182918262000ae1565b0390f35b9181601f8401121562000116578235916001600160401b0383116200011657602083818601950101116200011657565b34620001165760031960a0368201126200011657600435906001600160401b039081831162000116576101809083360301126200011657602435818111620001165762000bf390369060040162000b71565b92604435928311620001165762000b6d9362000c1862000c3594369060040162000b71565b916084359462000c288662000104565b6064359460040162001318565b6040516001600160a01b0390911681529081906020820190565b3462000116576020366003190112620001165762000c6c620015b8565b6004355f55005b346200011657602036600319011262000116576200050a60043562000c988162000104565b62000ca2620015b8565b62001513565b9060c082820312620001165780601f8301121562000116576040916040519262000cd284620003f4565b839260c08301928184116200011657935b83851062000cf357505050505090565b6060858303126200011657825160609162000d0e8262000416565b865182526020918288015183820152858801518682015281520194019362000ce3565b6040513d5f823e3d90fd5b90600281101562000d4e5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b1562000d6a57565b60405162461bcd60e51b8152602060048201526024808201527f4d656f7776696c6c653a2077686974656c697374206d696e74206e6f742061636044820152637469766560e01b6064820152608490fd5b3d1562000dea573d9062000dcf8262000468565b9162000ddf604051938462000446565b82523d5f602084013e565b606090565b6020601960fa1b917f426c617a654d616e616765723a20666565207472616e73666572206661696c6581520152565b1562000e2657565b60405162461bcd60e51b8152602060048201526021602482015260849062000e516044820162000def565bfd5b6040519062000e628262000416565b60218252620003de6020830162000def565b9081602091031262000116575190565b81835290916001600160fb1b038311620001165760209260051b809284830137010190565b6001600160a01b03909116815260406020820181905262000ecd9391019162000e84565b90565b6040519062000edf8262000416565b60238252621b195960ea1b6040837f426c617a654d616e616765723a2077686974656c697374206d696e742066616960208201520152565b6001600160a01b039290917f0000000000000000000000000000000000000000000000000000000000000000841630811490811562001014575b506200057257602060049462000f66620015b8565b6040516352d1902d60e01b8152958691829087165afa5f948162000fee575b5062000fb057604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b0390fd5b90915f805160206200568a833981519152840362000fd557620003de929350620015f2565b604051632a87526960e21b815260048101859052602490fd5b6200100c91955060203d60201162000373576200035f818362000446565b935f62000f85565b9050845f805160206200568a833981519152541614155f62000f51565b634e487b7160e01b5f52601160045260245ffd5b818102929181159184041417156200105957565b62001031565b919082039182116200105957565b9160609360ff62001091939897969816845260806020850152608084019162000e84565b6001600160a01b0390951660408201520152565b620010af6200169d565b620010b96200169d565b620010c36200169d565b620010ce3362001513565b6002604360981b01803b156200011657604051634e606c4760e01b81525f8160048183865af180156200037b5762001165575b50803b156200011657604051631d70c8d360e31b815273a804b7d57a4a872dbfbe2987347403039ade20dc6004820152905f908290602490829084905af180156200037b576200114e5750565b806200115e620003de9262000432565b806200050c565b806200115e620011759262000432565b5f62001101565b604051906200118b82620003f4565b601982527f426c617a654d616e616765723a206d696e74206661696c6564000000000000006020830152565b9035601e1982360301811215620001165701602081359101916001600160401b038211620001165781360383136200011657565b908060209392818452848401375f828201840152601f01601f1916010190565b35906001600160781b03821682036200011657565b35906001600160401b03821682036200011657565b359061ffff821682036200011657565b9035601e1982360301811215620001165701602081359101916001600160401b038211620001165760c08202360383136200011657565b9190808252602080920192915f905b8282106200129a575050505090565b9091929360019085358152828601358382015260406001600160781b03620012c48289016200120b565b16908201526060620012d881880162001220565b906001600160401b0380921690830152608090620012f882890162001220565b169082015260a0868101359082015260c09081019501939201906200128b565b9194939592909560405196613f1996878901948986106001600160401b0387111762000410578998620017518a3960c08652620013568180620011b7565b90610180918260c08a01526102408901906200137292620011eb565b9187620013836020830183620011b7565b9460bf1995868483030160e08501526200139d92620011eb565b92610100604084013581840152610120906060850135828501526101409260808601358486015260a08601620013d3906200120b565b6001600160781b031661016095860152620013f160c0870162001220565b6001600160401b0316908d01526200140c60e0860162001220565b6001600160401b03166101a08d01528401620014289062001235565b61ffff166101c08c015283016200143f90620003d1565b6001600160a01b03166101e08b015282016200145b90620003d1565b6001600160a01b03166102008a01528101620014779162001245565b9092888303016102208901526200148e926200127c565b908582036020870152620014a292620011eb565b908382036040850152620014b692620011eb565b60608201939093523060808201526001600160a01b0390911660a0919091015203905ff080156200037b576001600160a01b031680337f4e00adea785ec41e8982a4c2939e6944708c005f20e84edd89183a2a877042fa5f80a390565b6001600160a01b039081169081156200156e575f805160206200566a83398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b604051631e4fbdf760e01b81525f6004820152602490fd5b8051909190156200159a5750805190602001fd5b60405162461bcd60e51b815290819062000fac906004830162000ae1565b5f805160206200566a833981519152546001600160a01b03163303620015da57565b60405163118cdaa760e01b8152336004820152602490fd5b90813b156200167c575f805160206200568a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562001660576200165d91620016cd565b50565b5050346200166a57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff5f80516020620056aa8339815191525460401c1615620016bb57565b604051631afcd79f60e31b8152600490fd5b5f8062000ecd93602081519101845af4620016e762000dbb565b9190620017115750805115620016ff57805190602001fd5b60405163d6bda27560e01b8152600490fd5b8151158062001746575b62001724575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200171b56fe60a08060405234620001c55762003f1980380380916200001f82620001dd565b833980820160c08212620001c55782516001600160401b0393909290848411620001c55783916101809485910312620001c5576200005c6200025e565b9382820151868111620001c557848362000079928601016200027f565b855260c0830151868111620001c557848362000098928601016200027f565b602086015260e083015160408601526101009283810151606087015261012080820151608088015261014090620000d1828401620002f3565b85890152620000f761016094620000ea86860162000308565b60c08b0152840162000308565b60e08901526200010b6101a084016200031d565b868901526200011e6101c084016200035d565b90880152620001316101e083016200035d565b90870152610200810151878111620001c5578386916200015393010162000372565b9085015260c051858111620001c55783620001709183016200027f565b9260e051958611620001c557620001ac956200018d92016200027f565b9051906200019a6200032d565b92620001a562000345565b9462000b76565b604051612cbb90816200123e8239608051816128e30152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b60a0601f91909101601f19168101906001600160401b038211908210176200020457604052565b620001c9565b60c081019081106001600160401b038211176200020457604052565b6001600160401b0381116200020457604052565b601f909101601f19168101906001600160401b038211908210176200020457604052565b6040519061018082016001600160401b038111838210176200020457604052565b919080601f84011215620001c55782516001600160401b038111620002045760209060405192620002ba83601f19601f85011601856200023a565b818452828287010111620001c5575f5b818110620002df5750825f9394955001015290565b8581018301518482018401528201620002ca565b51906001600160781b0382168203620001c557565b51906001600160401b0382168203620001c557565b519061ffff82168203620001c557565b61012051906001600160a01b0382168203620001c557565b61014051906001600160a01b0382168203620001c557565b51906001600160a01b0382168203620001c557565b81601f82011215620001c55780519060206001600160401b038311620002045760409360405194620003aa838660051b01876200023a565b848652828601918360c080970286010194818611620001c5578401925b858410620003d9575050505050505090565b8684830312620001c5578487918451620003f3816200020a565b8651815282870151838201526200040c868801620002f3565b8682015260606200041f81890162000308565b9082015260806200043281890162000308565b9082015260a08088015190820152815201930192620003c7565b60405190602082016001600160401b0381118382101762000204576040525f8252565b90600182811c921680156200049f575b60208310146200048b57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916200047f565b601f8111620004b7575050565b60025f5260205f20906020601f840160051c83019310620004f4575b601f0160051c01905b818110620004e8575050565b5f8155600101620004dc565b9091508190620004d3565b601f81116200050c575050565b60035f5260205f20906020601f840160051c8301931062000549575b601f0160051c01905b8181106200053d575050565b5f815560010162000531565b909150819062000528565b601f811162000561575050565b600b5f5260205f20906020601f840160051c830193106200059e575b601f0160051c01905b81811062000592575050565b5f815560010162000586565b90915081906200057d565b601f8111620005b6575050565b600c5f5260205f20906020601f840160051c83019310620005f3575b601f0160051c01905b818110620005e7575050565b5f8155600101620005db565b9091508190620005d2565b80519091906001600160401b03811162000204576200062a81620006246003546200046f565b620004ff565b602080601f83116001146200066f575081906200065e93945f9262000663575b50508160011b915f199060031b1c19161790565b600355565b015190505f806200064a565b60035f52601f198316949091907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b925f905b878210620006db575050836001959610620006c2575b505050811b01600355565b01515f1960f88460031b161c191690555f8080620006b7565b80600185968294968601518155019501930190620006a1565b80519091906001600160401b038111620002045762000720816200071a600b546200046f565b62000554565b602080601f831160011462000758575081906200075393945f92620006635750508160011b915f199060031b1c19161790565b600b55565b600b5f52601f198316949091907f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9925f905b878210620007c4575050836001959610620007ab575b505050811b01600b55565b01515f1960f88460031b161c191690555f8080620007a0565b806001859682949686015181550195019301906200078a565b80519091906001600160401b0381116200020457620008098162000803600c546200046f565b620005a9565b602080601f831160011462000841575081906200083c93945f92620006635750508160011b915f199060031b1c19161790565b600c55565b600c5f52601f198316949091907fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7925f905b878210620008ad57505083600195961062000894575b505050811b01600c55565b01515f1960f88460031b161c191690555f808062000889565b8060018596829496860151815501950193019062000873565b600281901b91906001600160fe1b03811603620008df57565b634e487b7160e01b5f52601160045260245ffd5b805190680100000000000000008211620002045760135482601355808310620009c1575b5060135f526020908101905f8051602062003ef98339815191525f925b84841062000943575050505050565b60048382620009b460019451869060a060039180518455602081015160018501556002840160018060781b03604083015116815490600160781b600160b81b03606085015160781b1690600160b81b600160f81b03608086015160b81b169260ff60f81b1617171790550151910155565b0192019301929062000934565b620009cc90620008c6565b620009d783620008c6565b60135f525f8051602062003ef983398151915291820191015b818110620009ff575062000917565b805f600492555f60018201555f60028201555f600382015501620009f0565b61016062000b5e9162000a328151620006f4565b62000a416020820151620007dd565b6040810151600d556060810151600e556080810151600f5560a08101516010805460c084015160e085015160789190911b600160781b600160b81b03166001600160781b039094167fff00000000000000000000000000000000000000000000000000000000000000909216919091179290921760b89290921b600160b81b600160f81b031691909117905562000af462000ae261010083015161ffff1690565b61ffff1661ffff196011541617601155565b61012081015162000b31906001600160a01b03166011805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b610140810151601280546001600160a01b0319166001600160a01b039092169190911790550151620008f3565b565b5f910312620001c557565b6040513d5f823e3d90fd5b92939162000b85918662000dae565b81516020815191012062000b986200044c565b6020815191012014801562000d8e575b801562000d80575b62000d6e576101408201516001600160a01b03168062000d5c575b5060805262000bda8162000a1e565b62000bea61016082015162000f9c565b734300000000000000000000000000000000000002803b15620001c55760405163388a0bbd60e11b81525f8160048183865af1801562000d285762000d45575b50803b15620001c5575f8091600460405180948193634e606c4760e01b83525af1801562000d285762000d2e575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd80090813b15620001c5576040516336b91f2b60e01b815273f8a82748e7df10d0684b758d02cf6c43ad83ad256004820152915f908390602490829084905af191821562000d285762000cf59262000d0a575b5061012081015162000cee9062000ce790610100906001600160a01b031693015161ffff1690565b61ffff1690565b90620010b1565b8062000cff575050565b62000b5e91620010f9565b8062000d1a62000d219262000226565b8062000b60565b5f62000cbf565b62000b6b565b8062000d1a62000d3e9262000226565b5f62000c58565b8062000d1a62000d559262000226565b5f62000c2a565b62000d679062000ee6565b5f62000bcb565b604051635435b28960e11b8152600490fd5b506040820151831162000bb0565b506107d061ffff62000da661010085015161ffff1690565b161162000ba8565b815191939290916001600160401b038111620002045762000ddc8162000dd66002546200046f565b620004aa565b602080601f831160011462000e545750908062000e159262000e1e9596975f92620006635750508160011b915f199060031b1c19161790565b600255620005fe565b5f80556001600160a01b0381161562000e3c5762000b5e90620011dc565b604051631e4fbdf760e01b81525f6004820152602490fd5b60025f52601f198316969091907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace925f905b89821062000ecd5750509083929160019462000e1e9798991062000eb4575b505050811b01600255620005fe565b01515f1960f88460031b161c191690555f808062000ea5565b8060018596829496860151815501950193019062000e86565b6001600160a01b0316734300000000000000000000000000000000000003811462000f705773b1a5700fa2358173fe465e6ea4ff52e36e88e2ad811462000f7057735ffd9ebd27f2fcab044c0f0a26a45cb62fa29c06811462000f705773d43d8adac6a4c7d9aeece7c3151fca8f23752cf81462000b5e57604051631eb3268560e31b8152600490fd5b50565b805182101562000f885760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b90600382511162001011575f805b8351821015620010ab5762000fc0828562000f73565b5151906020918262000fd3858862000f73565b510151109081156200108e575b811562001053575b50801562001023575b620010115760019062001005838662000f73565b51015191019062000faa565b60405163097191df60e41b8152600490fd5b5062001030828562000f73565b515115801562000ff157508062001048838662000f73565b510151151562000ff1565b905062001061838662000f73565b51511515908162001075575b505f62000fe8565b905062001083838662000f73565b515111155f6200106d565b9050816200109d848762000f73565b510151600e54109062000fe0565b50509050565b6001600160601b03909116906127108211620010ec5760601b8015620010df571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b905f54918115620011cd576001916200115060018060a01b038316926001831460e11b4260a01b17841762001136875f52600460205260405f2090565b556001600160a01b03165f90815260056020526040902090565b68010000000000000001820281540190558115620011c757830192916001815b6200117e575b505050505f55565b15620011b4575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a462001170565b8092019183830362001185578062001176565b6200122f565b63b562e8dd60e01b5f5260045ffd5b600a80546001600160a01b0319908116909155600980549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b622e076360e81b5f5260045ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146102f457806306fdde03146102ef578063081812fc146102ea57806309430a7e146102e5578063095ea7b3146102e057806318160ddd146102db5780631869ebda146102d657806323b872dd146102d157806326e2dca2146102cc5780632a55205a146102c75780632e1a7d4d146102c25780633add14c8146102bd5780633ccfd60b146102b857806340c10f19146102b357806342842e0e146102ae5780634fdf5d1d146102a957806353df5c7c146102a457806355f804b31461029f5780635e0cee0f1461029a5780636352211e146102955780636f8b44b014610290578063708b31f31461028b57806370a0823114610286578063715018a61461028157806375eedb451461027c57806379ba5097146102775780638503e714146102725780638da5cb5b1461026d578063938e3d7b1461026857806395d89b4114610263578063999927df1461025e5780639d0172f314610259578063a22cb46514610254578063acd9d3ea1461024f578063b88d4fde1461024a578063c4fe0fba14610245578063c87b56dd14610240578063d55829651461023b578063e1c2ffad14610236578063e30c397814610231578063e4be0c061461022c578063e8a3d48514610227578063e985e9c514610222578063f2fde38b1461021d578063f557ab03146102185763f8bd83e114610213575f80fd5b6121f9565b6121bd565b612151565b6120f5565b6120c6565b611e35565b611e0d565b611de4565b611d6f565b611cd3565b611c81565b611bef565b611b75565b611ae5565b611a91565b611a30565b61198b565b61185f565b611837565b61180c565b61178a565b611697565b6115cf565b611579565b61145b565b611226565b6111f7565b611127565b611005565b610f95565b610e2f565b610df7565b610c46565b610b29565b610af1565b6109db565b610953565b610870565b61082e565b610752565b610731565b610687565b610535565b6104e6565b610406565b61030f565b6001600160e01b031981160361030b57565b5f80fd5b3461030b57602036600319011261030b57602060043561032e816102f9565b6001600160e01b031981166301ffc9a760e01b811491908215610391575b8215610380575b508115610366575b506040519015158152f35b905060e01c6301ffc9a7632a55205a82149114175f61035b565b635b5e139f60e01b1491505f610353565b6380ac58cd60e01b8114925061034c565b5f91031261030b57565b5f5b8381106103bd5750505f910152565b81810151838201526020016103ae565b906020916103e6815180928185528580860191016103ac565b601f01601f1916010190565b9060206104039281815201906103cd565b90565b3461030b575f36600319011261030b576040515f6002546104268161128e565b808452906020906001908181169081156104bc5750600114610463575b61045f85610453818703826112ed565b604051918291826103f2565b0390f35b60025f90815293507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8385106104a9575050505081016020016104538261045f610443565b805486860184015293820193810161048d565b86955061045f9693506020925061045394915060ff191682840152151560051b8201019293610443565b3461030b57602036600319011261030b57600435610503816127d6565b15610526575f526006602052602060018060a01b0360405f205416604051908152f35b6333d1c03960e21b5f5260045ffd5b3461030b575f36600319011261030b576013546105518161225f565b60409161056160405192836112ed565b8082526020808301918260135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0905f915b83831061062257505050506040519281840190828552518091526040840192915f5b8281106105c25785850386f35b8351805186528083015186840152878101516001600160781b0316888701526060808201516001600160401b03908116918801919091526080808301519091169087015260a0908101519086015260c090940193928101926001016105b5565b600485600192610634859a989a612276565b815201920192019190959395610593565b600435906001600160a01b038216820361030b57565b604435906001600160a01b038216820361030b57565b602435906001600160a01b038216820361030b57565b604036600319011261030b5761069b610645565b602435906001600160a01b03806106b184612864565b1690813303610702575b835f52600660205260405f20921691826001600160601b0360a01b8254161790557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b5f82815260076020908152604080832033845290915290205460ff166106bb576367d9dca160e11b5f5260045ffd5b3461030b575f36600319011261030b5760205f546001549003604051908152f35b3461030b57604036600319011261030b576107b16020610770610645565b610778612850565b604051637cb8cb3160e11b81523060048201526001600160a01b0390911660248083019190915235604482015291829081906064820190565b03815f6002604360981b015af180156107f4576107ca57005b6107eb9060203d6020116107ed575b6107e381836112ed565b8101906122da565b005b503d6107d9565b6122e9565b606090600319011261030b576001600160a01b0390600435828116810361030b5791602435908116810361030b579060443590565b6107eb61083a366107f9565b916122f4565b9181601f8401121561030b578235916001600160401b03831161030b576020808501948460051b01011161030b57565b3461030b57606036600319011261030b57610889610645565b602435906001600160401b03821161030b576108ab6004923690600401610840565b9290916108b661065b565b936108bf612850565b6001600160a01b03909116905f5b8181106108d657005b6108e181838761248b565b3590833b1561030b57604080516323b872dd60e01b8152308782019081526001600160a01b038a166020820152918201939093525f9083908190606001038183885af19182156107f45760019261093a575b50016108cd565b8061094761094d926112da565b806103a2565b5f610933565b3461030b57604036600319011261030b576024356004355f5268aa4ec00224afccfdb7908160205260405f20548060601c9283156109c9575b5061045f908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b54606081901c9350905061045f61098c565b3461030b57602036600319011261030b575f6004356109f8612850565b806015548082118414610ada575050610a105f601555565b6012546001600160a01b031615158214610ab157601254602091610a7991610a4e90610a42906001600160a01b031681565b6001600160a01b031690565b60405163a9059cbb60e01b815233600482015260248101929092529093849283919082906044820190565b03925af180156107f457610a8957005b6107eb9060203d602011610aaa575b610aa281836112ed565b8101906124f5565b503d610a98565b81808092335af1610ac06124c6565b5015610ac857005b6040516327fcd9d160e01b8152600490fd5b610aec91610ae7916124b4565b601555565b610a10565b3461030b57602036600319011261030b576001600160a01b03610b12610645565b165f526017602052602060405f2054604051908152f35b3461030b575f36600319011261030b57610b41612850565b6012546001600160a01b031615610c1f57601254610b6990610a42906001600160a01b031681565b6040516370a0823160e01b8152306004820152602091908281602481855afa9081156107f4575f928492610bc9928591610c02575b5060405163a9059cbb60e01b8152336004820152602481019190915293849283919082906044820190565b03925af180156107f457610be4575b50505b6107eb5f601555565b81610bfa92903d10610aaa57610aa281836112ed565b505f80610bd8565b610c199150843d86116107ed576107e381836112ed565b5f610b9e565b5f80808047335af1610c2f6124c6565b50610bdb576040516327fcd9d160e01b8152600490fd5b60408060031936011261030b57610c5b610645565b60243590610c68826128e1565b600e5442108015610deb575b8015610ddf575b610dce576010546001600160401b03808260781c168411610dbd576001600160a01b0383165f908152601760205260409020610cba9085905b546128d4565b908260b81c1610610dac57826001600160781b03610cd8921661294a565b6012549093906001600160a01b031680610d425750833410610d325750610d2d610ae76107eb945b6001600160a01b0384165f9081526017602052604090205b610d238682546128d4565b90556015546128d4565b612b41565b5163356680b760e01b8152600490fd5b90516323b872dd60e01b81523360048201523060248201526044810185905290602090829060649082905f905af180156107f4576107eb94610d2d92610ae792610d8d575b50610d00565b610da59060203d602011610aaa57610aa281836112ed565b505f610d87565b8351634413775560e11b8152600490fd5b845163635a2d9b60e01b8152600490fd5b825163914edb0f60e01b8152600490fd5b5060185460ff16610c7b565b5042600f541115610c74565b610e00366107f9565b6040519160208301938385106001600160401b03861117610e2a576107eb946040525f84526126cd565b6112c6565b3461030b57604036600319011261030b57610e48610645565b610e50610671565b90610e59612850565b6001600160a01b03169081610eb1575f80806107eb9481944791610e87610a4260125460018060a01b031690565b14610e9d575b5af1610e976124c6565b5061250a565b90610eab90601554906124b4565b90610e8d565b6040516370a0823160e01b81523060048201526020928382602481845afa9081156107f457610f3a9385935f93610f76575b506012548390610efb906001600160a01b0316610a42565b8314610f60575b5060405163a9059cbb60e01b81526001600160a01b0390911660048201526024810192909252909283919082905f9082906044820190565b03925af180156107f457610f4a57005b816107eb92903d10610aaa57610aa281836112ed565b610f6f919350601554906124b4565b915f610f02565b610f8e919350843d86116107ed576107e381836112ed565b915f610ee3565b3461030b575f36600319011261030b57610fad612850565b6014805460ff19166001179055005b90602060031983011261030b576004356001600160401b039283821161030b578060238301121561030b57816004013593841161030b576024848301011161030b576024019190565b3461030b5761101336610fbc565b61101b612850565b60ff60145416611115576001600160401b038111610e2a5761104781611042600b5461128e565b61254f565b5f601f82116001146110a9578190611074935f9261109e575b50508160011b915f199060031b1c19161790565b600b555b7fa239f4bbfd90a175f9b529d5ee0788e561e3b14a3f60866421828226b31e883c5f80a1005b013590505f80611060565b600b5f52601f198216925f80516020612c66833981519152915f5b8581106110fd575083600195106110e4575b505050811b01600b55611078565b01355f19600384901b60f8161c191690555f80806110d6565b909260206001819286860135815501940191016110c4565b60405163696c636960e01b8152600490fd5b3461030b57604036600319011261030b57611140610645565b6024359061ffff82169182810361030b57611159612850565b60ff60145460101c166111e5576107d083116111d357601180546001600160b01b03191662010000600160b01b03601085901b161761ffff9092169190911790556111a4828261295d565b6001600160a01b03167ff1ae48f8f3e1bed700c52bee6fe28096c85db77867f9a18f35144c33ce6db2b45f80a3005b60405163a2a65b5360e01b8152600490fd5b604051635a214b2560e11b8152600490fd5b3461030b57602036600319011261030b5760206001600160a01b0361121d600435612864565b16604051908152f35b3461030b57602036600319011261030b57600435611242612850565b61124a6129a2565b5f54811061127c5780600d557f3f8118fc46e72ecde0c5e090803cad8c88e817b2f1e93e820aa9bfbf51f2468d5f80a2005b60405163066f305360e21b8152600490fd5b90600182811c921680156112bc575b60208310146112a857565b634e487b7160e01b5f52602260045260245ffd5b91607f169161129d565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111610e2a57604052565b90601f801991011681019081106001600160401b03821117610e2a57604052565b604051905f82600c54916113218361128e565b808352926020906001908181169081156113ad575060011461134e575b505061134c925003836112ed565b565b915092600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7935f925b828410611395575061134c9450505081016020015f8061133e565b8554888501830152948501948794509281019261137a565b9150506020925061134c94915060ff191682840152151560051b8201015f8061133e565b9997929b9a969394610140999561140f8c6001600160781b039561140161ffff9b966101608085528401906103cd565b9160208184039101526103cd565b60408d019e909e5260608c015260808b01521660a08901526001600160401b0391821660c08901521660e0870152166101008501526001600160a01b0391821661012085015216910152565b3461030b575f36600319011261030b576040515f600b5461147b8161128e565b8084529060209060019081811690811561154f5750600114611509575b61ffff856114a8818703826112ed565b61045f6114b361130e565b91600d5490600e5493600f54916010546001600160401b03916011549460018060a01b03988960125416976040519b8c9b8960101c169816966001600160781b03878760b81c16978760781c169616948c6113d1565b600b5f90815293505f80516020612c668339815191525b83851061153c575050505081016020016114a88261ffff611498565b8054868601840152938201938101611520565b86955061ffff969350602092506114a894915060ff191682840152151560051b8201019293611498565b3461030b57602036600319011261030b576001600160a01b0361159a610645565b1680156115c0575f52600560205260206001600160401b0360405f205416604051908152f35b6323d3ad8160e21b5f5260045ffd5b3461030b575f36600319011261030b576115e7612850565b600a80546001600160a01b03199081169091556009805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106116695750505050505090565b9091929394958480611687600193603f198682030187528a516103cd565b9801930193019194939290611659565b3461030b5760208060031936011261030b576004356001600160401b03811161030b576116c8903690600401610840565b916116d1612850565b6116da8361225f565b926040916116eb60405195866112ed565b818552601f196116fa8361225f565b015f5b81811061177b575050505f5b81811061171e576040518061045f8782611634565b5f8061172b838588612616565b9061173a875180938193612657565b0390305af46117476124c6565b901561176d579060019161175b82886126b9565b5261176681876126b9565b5001611709565b611775612664565b90612a13565b606087820184015282016116fd565b3461030b575f36600319011261030b57600a546001600160a01b0333818316036117f4576001600160601b0360a01b809216600a556009549133908316176009553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b3461030b575f36600319011261030b57611824612850565b6014805462ff0000191662010000179055005b3461030b575f36600319011261030b576009546040516001600160a01b039091168152602090f35b3461030b5761186d36610fbc565b611875612850565b60ff60145460081c16611979576001600160401b038111610e2a576118a48161189f600c5461128e565b6125a9565b5f601f82116001146118fa5781906118d0935f9261109e5750508160011b915f199060031b1c19161790565b600c555b7f801a056d1f533ad9d100de2039b5996850ae077400027351617645308a59cf2e5f80a1005b600c5f52601f198216927fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7915f5b85811061196157508360019510611948575b505050811b01600c556118d4565b01355f19600384901b60f8161c191690555f808061193a565b90926020600181928686013581550194019101611928565b604051631fd0326960e01b8152600490fd5b3461030b575f36600319011261030b576040515f6003546119ab8161128e565b808452906020906001908181169081156104bc57506001146119d75761045f85610453818703826112ed565b60035f90815293507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b838510611a1d575050505081016020016104538261045f610443565b8054868601840152938201938101611a01565b3461030b57602036600319011261030b57611a49610645565b611a51612850565b60405163430021db60e11b81523060048201526001600160a01b0390911660248201526020816044815f6002604360981b015af180156107f4576107ca57005b3461030b57602036600319011261030b576004356001600160781b03811680910361030b57611abe612850565b611ac66129a2565b6001600160781b031960105416176010555f80f35b8015150361030b57565b3461030b57604036600319011261030b57611afe610645565b60243590611b0b82611adb565b335f9081526007602090815260408083206001600160a01b038516845290915290209115159160ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b3461030b57604036600319011261030b576107b16020611b93610645565b611b9b612850565b604051630951888f60e01b81523060048201526001600160a01b0390911660248083019190915235604482015291829081906064820190565b6001600160401b038111610e2a57601f01601f191660200190565b608036600319011261030b57611c03610645565b611c0b610671565b606435916001600160401b03831161030b573660238401121561030b57826004013591611c3783611bd4565b92611c4560405194856112ed565b808452366024828701011161030b576020815f9260246107eb98018388013785010152604435916126cd565b6004359060ff8216820361030b57565b3461030b57604036600319011261030b576020611cca611c9f611c71565b60ff611ca9610671565b91165f526016835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461030b57602036600319011261030b57600435611cf0816127d6565b15611d5d5760405190608082019060a083016040525f8252905b5f190190600a906030828206018353049081611d0a57611d5161045361045f92856080601f19928381019203018152604051938491611d4b6020840161270e565b90612787565b039081018352826112ed565b60405163677510db60e11b8152600490fd5b3461030b575f36600319011261030b57611d87612850565b600160ff1960185416176018555f5480600d557fcbbaae1b89885aa88b0db407075a1f3e6df45931447d19c7da5f5b7471a729e55f80a17f3f8118fc46e72ecde0c5e090803cad8c88e817b2f1e93e820aa9bfbf51f2468d5f80a2005b3461030b575f36600319011261030b57611dfc612850565b6014805461ff001916610100179055005b3461030b575f36600319011261030b57600a546040516001600160a01b039091168152602090f35b608036600319011261030b57611e49611c71565b602435906001600160401b03821161030b57611e6a60049236908401610840565b91611e7361065b565b9160643593611e81856128e1565b611e93611e8d8461279e565b50612276565b918251421080156120b8575b6120a757611ec6611eba60608501516001600160401b031690565b6001600160401b031690565b861161209657611efe86610cb487611ee98860ff165f52601660205260405f2090565b9060018060a01b03165f5260205260405f2090565b611f15611eba60808601516001600160401b031690565b1061208557604080516001600160a01b03871660208083019182528252611f6c94611f689490939092611f559291611f4d90826112ed565b519020612b18565b602081519101209160a086015191612c1b565b1590565b6120745783611f97611f8b6040611f9c9401516001600160781b031690565b6001600160781b031690565b61294a565b6012549094906001600160a01b031680611feb5750843410611fdc5750610ae76107eb94610d1884611ee9610d2d9560ff165f52601660205260405f2090565b60405163356680b760e01b8152fd5b604080516323b872dd60e01b815233938101938452306020858101919091529184018890529396929091849182905f90829060600103925af19081156107f457610d1884611ee96107eb98610d2d96610ae796612055575b5060ff165f52601660205260405f2090565b61206d9060203d602011610aaa57610aa281836112ed565b505f612043565b60405163582f497d60e11b81528590fd5b60405163bdaa15c960e01b81528790fd5b6040516318e99c4960e21b81528790fd5b60405163cbe8d62360e01b81528790fd5b504260208401511115611e9f565b3461030b575f36600319011261030b5761045f6120e161130e565b6040519182916020835260208301906103cd565b3461030b57604036600319011261030b57602060ff612145612115610645565b61211d610671565b6001600160a01b039182165f9081526007865260408082209290931681526020919091522090565b54166040519015158152f35b3461030b57602036600319011261030b5761216a610645565b612172612850565b600a80546001600160a01b0319166001600160a01b039283169081179091556009549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b3461030b575f36600319011261030b57606060145460ff6040519181811615158352818160081c161515602084015260101c1615156040820152f35b3461030b57604036600319011261030b57612212611c71565b602435906001600160781b03821680920361030b57612242600291612235612850565b61223d6129a2565b61279e565b500180546effffffffffffffffffffffffffffff19169091179055005b6001600160401b038111610e2a5760051b60200190565b6040516001600160401b03929160c0820184811183821017610e2a5760a0916003916040528395815485526001820154602086015260028201546001600160781b0381166040870152818160781c16606087015260b81c1660808501520154910152565b9081602091031261030b575190565b6040513d5f823e3d90fd5b91909161230082612864565b6001600160a01b039182169390828116859003612472575f848152600660205260409020805461233f6001600160a01b03881633908114908314171590565b61243d575b612434575b506001600160a01b0385165f90815260056020526040902080545f190190556001600160a01b0382165f908152600560205260409020805460010190556001600160a01b0382164260a01b17600160e11b176123ad855f52600460205260405f2090565b55600160e11b8116156123ef575b501680927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4156123ea57565b612832565b60018401612405815f52600460205260405f2090565b5415612412575b506123bb565b5f54811461240c5761242c905f52600460205260405f2090565b555f8061240c565b5f90555f612349565b612468611f6861246133611ee98b60018060a01b03165f52600760205260405f2090565b5460ff1690565b1561234457612823565b612815565b634e487b7160e01b5f52603260045260245ffd5b919081101561249b5760051b0190565b612477565b634e487b7160e01b5f52601160045260245ffd5b919082039182116124c157565b6124a0565b3d156124f0573d906124d782611bd4565b916124e560405193846112ed565b82523d5f602084013e565b606090565b9081602091031261030b575161040381611adb565b1561251157565b60405162461bcd60e51b815260206004820152601660248201527513985d1a5d99481d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b601f811161255b575050565b600b5f525f80516020612c66833981519152906020601f840160051c8301931061259f575b601f0160051c01905b818110612594575050565b5f8155600101612589565b9091508190612580565b601f81116125b5575050565b600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7906020601f840160051c8301931061260c575b601f0160051c01905b818110612601575050565b5f81556001016125f6565b90915081906125ed565b919081101561249b5760051b81013590601e198136030182121561030b5701908135916001600160401b03831161030b57602001823603811361030b579190565b908092918237015f815290565b60405190606082018281106001600160401b03821117610e2a5760405260238252621b195960ea1b6040837f426c617a654d616e616765723a2077686974656c697374206d696e742066616960208201520152565b805182101561249b5760209160051b010190565b9291906126db8282866122f4565b803b6126e8575b50505050565b6126f193612a63565b156126ff575f8080806126e2565b6368d2bf6b60e11b5f5260045ffd5b600b545f929161271d8261128e565b91600190818116908115612774575060011461273857505050565b9091929350600b5f525f80516020612c66833981519152905f915b848310612761575050500190565b8181602092548587015201920191612753565b60ff191683525050811515909102019150565b9061279a602092828151948592016103ac565b0190565b60135481101561249b5760135f5260021b7f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001905f90565b905f915f5481106127e45750565b9091505b805f52600460205260405f205480612809575080156124c1575f19016127e8565b600160e01b1615919050565b62a1148160e81b5f5260045ffd5b632ce44b5f60e11b5f5260045ffd5b633a954ecd60e21b5f5260045ffd5b636f96cda160e11b5f5260045ffd5b6009546001600160a01b031633036117f457565b612876815f52600460205260405f2090565b5490811561288d5750600160e01b81166128415790565b90505f54811015612841575b5f19015f818152600460205260409020549081156128cd5750600160e01b81161561040357636f96cda160e11b5f5260045ffd5b9050612899565b919082018092116124c157565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612939575f549081018091116124c157600d541061292757565b60405163d05cb60960e01b8152600490fd5b6040516282b42960e81b8152600490fd5b818102929181159184041417156124c157565b906001600160601b03169061271082116129955760601b8015612988571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b600e54421180612a08575b6129e0576013545f5b8181106129c1575050565b6129ca8161279e565b50544211806129f2575b6129e0576001016129b6565b604051633f19d52960e21b8152600490fd5b5060016129fe8261279e565b50015442106129d4565b50600f5442106129ad565b805190919015612a265750805190602001fd5b60405162461bcd60e51b815260206004820152908190612a4a9060248301906103cd565b0390fd5b9081602091031261030b5751610403816102f9565b92602091612aab935f60018060a01b0360405180978196829584630a85bd0160e11b9c8d865233600487015216602485015260448401526080606484015260848301906103cd565b0393165af15f9181612ae7575b50612ad957612ac56124c6565b805115612ad457805190602001fd5b6126ff565b6001600160e01b0319161490565b612b0a91925060203d602011612b11575b612b0281836112ed565b810190612a4e565b905f612ab8565b503d612af8565b9060405191602083015260208252604082018281106001600160401b03821117610e2a57604052565b5f54918015612c0c576001916001600160a01b0381164260a01b83851460e11b1717612b75855f52600460205260405f2090565b556001600160a01b03165f8181526005602052604090208054680100000000000000018402019055908115612bfe57830192916001815b612bb9575b505050505f55565b15612bed575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4612bac565b80920191838303612bbf5780612bb1565b622e076360e81b5f5260045ffd5b63b562e8dd60e01b5f5260045ffd5b81939293612c2a575b50501490565b60059291831b8101915b8135808211851b91825260208092185260405f2091019282841015612c5a579290612c34565b509150505f80612c2456fe0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212208dd0488414d470d364d29901e2d3d5e1cf5d26d63da42d3741fd6f0df1c7837764736f6c6343000818003366de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0909016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220757472b7162687e5d295b2976bb94c21b989e650698a609161a50cd9dc7e805f64736f6c63430008180033
Deployed Bytecode
0x6080604052600436101562000012575f80fd5b5f3560e01c8063174770ad14620000fe5780634f1ef28614620000f857806352d1902d14620000f25780636497ed2d14620000ec578063715018a614620000e65780638129fc1c14620000e05780638da5cb5b14620000da578063921b998214620000d4578063a907bfb414620000ce578063ad3cb1cc14620000c8578063d22a453914620000c2578063eddd0d9c14620000bc5763f2fde38b14620000b6575f80fd5b62000c73565b62000c4f565b62000ba1565b62000b2a565b62000a09565b620008a4565b6200086d565b62000787565b6200071b565b62000584565b62000517565b62000484565b6200014d565b6001600160a01b038116036200011657565b5f80fd5b9181601f8401121562000116578235916001600160401b03831162000116576020808501948460051b0101116200011657565b60603660031901126200011657600435620001688162000104565b6024356001600160401b03811162000116576200018a9036906004016200011a565b919060443592831592831585036200011657604051635e2d5fb560e01b81526001600160a01b0391909116939060c081600481885afa9182156200037b57620001f692620001e1925f916200039b575b5062000d3c565b51805142101590816200038b575b5062000d62565b5f808080805473a804b7d57a4a872dbfbe2987347403039ade20dc5af16200021d62000dbb565b90620002298162000e1e565b156200038157506040516318160ddd60e01b815293602085600481875afa9485156200037b575f956200033b575b505f928392909115620002fb576200029c6200028d9160405192839160208301956311d2fae760e31b8752336024850162000ea9565b03601f19810183528262000446565b519082855af1620002ac62000dbb565b905b15620002ea575060405191825233917f1d2fd770978c6eda249e6778a98091f102b8e977d255ad97a6972852376d83d19080602081015b0390a3005b620002f462000ed0565b9062001586565b620003246200028d91604051928391602083019563d3f186c160e01b8752336024850162000ea9565b519082855af16200033462000dbb565b90620002ae565b5f939195509162000368849360203d60201162000373575b6200035f818362000446565b81019062000e74565b959193509162000257565b503d62000353565b62000d31565b620002f462000e53565b6020915001514211155f620001ef565b620003c2915060c03d60c011620003c9575b620003b9818362000446565b81019062000ca8565b5f620001da565b503d620003ad565b3590620003de8262000104565b565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176200041057604052565b620003e0565b606081019081106001600160401b038211176200041057604052565b6001600160401b0381116200041057604052565b90601f801991011681019081106001600160401b038211176200041057604052565b6001600160401b0381116200041057601f01601f191660200190565b604036600319011262000116576004356200049f8162000104565b602435906001600160401b0382116200011657366023830112156200011657816004013590620004cf8262000468565b91620004df604051938462000446565b808352366024828601011162000116576020815f9260246200050a9701838701378401015262000f17565b005b5f9103126200011657565b3462000116575f36600319011262000116577f000000000000000000000000b7a17dca3f7ffc02ac25058416dfa35232c50c1c6001600160a01b03163003620005725760206040515f805160206200568a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b608036600319011262000116576004356200059f8162000104565b60243560ff8116810362000116576044356001600160401b0381116200011657620005cf9036906004016200011a565b60643591620005e0835f5462001045565b945f8080808973a804b7d57a4a872dbfbe2987347403039ade20dc5af16200060762000dbb565b90620006138162000e1e565b156200038157506040516318160ddd60e01b8152956001600160a01b03919091169490602087600481895afa9687156200037b575f97620006e0575b50915f93916200068c620006658695346200105f565b936200028d88604051948593602085019763725f060360e11b89523392602487016200106d565b5191865af16200069b62000dbb565b9015620002ea575060408051938452602084019190915233927f6407f8ca752db84010bc02df7ad41475b0a4db9c029c65f246ea482f020d1aa29181908101620002e5565b5f9492908594929850620006656200070d6200068c9260203d60201162000373576200035f818362000446565b99939550505091936200064f565b3462000116575f366003190112620001165762000737620015b8565b5f805160206200566a83398151915280546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3462000116575f36600319011262000116575f80516020620056aa833981519152805460ff8160401c16801562000858575b620008465767ffffffffffffffff191660021790555f80516020620056aa833981519152805460ff60401b191668010000000000000000179055620007fd620010a5565b5f80516020620056aa833981519152805460ff60401b19169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620007b9565b3462000116575f36600319011262000116575f805160206200566a833981519152546040516001600160a01b039091168152602090f35b60403660031901126200011657600435620008bf8162000104565b602435620008cf815f5462001045565b915f8080808673a804b7d57a4a872dbfbe2987347403039ade20dc5af1620008f662000dbb565b90620009028162000e1e565b156200038157506040516318160ddd60e01b8152926001600160a01b03919091169190602084600481865afa9384156200037b575f94620009da575b505f6200094d8192346200105f565b6040516340c10f1960e01b6020820190815233602483015260448201869052906200097c81606481016200028d565b5191865af16200098b62000dbb565b9015620009d0575060408051938452602084019190915233927f6407f8ca752db84010bc02df7ad41475b0a4db9c029c65f246ea482f020d1aa29181908101620002e5565b620002f46200117c565b5f9194506200094d620009ff839260203d60201162000373576200035f818362000446565b959250506200093e565b6020366003190112620001165760043562000a248162000104565b5f808080805473a804b7d57a4a872dbfbe2987347403039ade20dc5af162000a4b62000dbb565b9062000a578162000e1e565b156200038157506040516318160ddd60e01b8152906001600160a01b0316602082600481845afa9182156200037b575f9262000abb575b506040516335313c2160e11b602082019081523360248301525f918291906200029c81604481016200028d565b62000ad991925060203d60201162000373576200035f818362000446565b905f62000a8e565b602080825282518183018190529093925f5b82811062000b1557505060409293505f838284010152601f8019910116010190565b81810186015184820160400152850162000af3565b3462000116575f366003190112620001165762000b6d60405162000b4e81620003f4565b60058152640352e302e360dc1b60208201526040519182918262000ae1565b0390f35b9181601f8401121562000116578235916001600160401b0383116200011657602083818601950101116200011657565b34620001165760031960a0368201126200011657600435906001600160401b039081831162000116576101809083360301126200011657602435818111620001165762000bf390369060040162000b71565b92604435928311620001165762000b6d9362000c1862000c3594369060040162000b71565b916084359462000c288662000104565b6064359460040162001318565b6040516001600160a01b0390911681529081906020820190565b3462000116576020366003190112620001165762000c6c620015b8565b6004355f55005b346200011657602036600319011262000116576200050a60043562000c988162000104565b62000ca2620015b8565b62001513565b9060c082820312620001165780601f8301121562000116576040916040519262000cd284620003f4565b839260c08301928184116200011657935b83851062000cf357505050505090565b6060858303126200011657825160609162000d0e8262000416565b865182526020918288015183820152858801518682015281520194019362000ce3565b6040513d5f823e3d90fd5b90600281101562000d4e5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b1562000d6a57565b60405162461bcd60e51b8152602060048201526024808201527f4d656f7776696c6c653a2077686974656c697374206d696e74206e6f742061636044820152637469766560e01b6064820152608490fd5b3d1562000dea573d9062000dcf8262000468565b9162000ddf604051938462000446565b82523d5f602084013e565b606090565b6020601960fa1b917f426c617a654d616e616765723a20666565207472616e73666572206661696c6581520152565b1562000e2657565b60405162461bcd60e51b8152602060048201526021602482015260849062000e516044820162000def565bfd5b6040519062000e628262000416565b60218252620003de6020830162000def565b9081602091031262000116575190565b81835290916001600160fb1b038311620001165760209260051b809284830137010190565b6001600160a01b03909116815260406020820181905262000ecd9391019162000e84565b90565b6040519062000edf8262000416565b60238252621b195960ea1b6040837f426c617a654d616e616765723a2077686974656c697374206d696e742066616960208201520152565b6001600160a01b039290917f000000000000000000000000b7a17dca3f7ffc02ac25058416dfa35232c50c1c841630811490811562001014575b506200057257602060049462000f66620015b8565b6040516352d1902d60e01b8152958691829087165afa5f948162000fee575b5062000fb057604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b0390fd5b90915f805160206200568a833981519152840362000fd557620003de929350620015f2565b604051632a87526960e21b815260048101859052602490fd5b6200100c91955060203d60201162000373576200035f818362000446565b935f62000f85565b9050845f805160206200568a833981519152541614155f62000f51565b634e487b7160e01b5f52601160045260245ffd5b818102929181159184041417156200105957565b62001031565b919082039182116200105957565b9160609360ff62001091939897969816845260806020850152608084019162000e84565b6001600160a01b0390951660408201520152565b620010af6200169d565b620010b96200169d565b620010c36200169d565b620010ce3362001513565b6002604360981b01803b156200011657604051634e606c4760e01b81525f8160048183865af180156200037b5762001165575b50803b156200011657604051631d70c8d360e31b815273a804b7d57a4a872dbfbe2987347403039ade20dc6004820152905f908290602490829084905af180156200037b576200114e5750565b806200115e620003de9262000432565b806200050c565b806200115e620011759262000432565b5f62001101565b604051906200118b82620003f4565b601982527f426c617a654d616e616765723a206d696e74206661696c6564000000000000006020830152565b9035601e1982360301811215620001165701602081359101916001600160401b038211620001165781360383136200011657565b908060209392818452848401375f828201840152601f01601f1916010190565b35906001600160781b03821682036200011657565b35906001600160401b03821682036200011657565b359061ffff821682036200011657565b9035601e1982360301811215620001165701602081359101916001600160401b038211620001165760c08202360383136200011657565b9190808252602080920192915f905b8282106200129a575050505090565b9091929360019085358152828601358382015260406001600160781b03620012c48289016200120b565b16908201526060620012d881880162001220565b906001600160401b0380921690830152608090620012f882890162001220565b169082015260a0868101359082015260c09081019501939201906200128b565b9194939592909560405196613f1996878901948986106001600160401b0387111762000410578998620017518a3960c08652620013568180620011b7565b90610180918260c08a01526102408901906200137292620011eb565b9187620013836020830183620011b7565b9460bf1995868483030160e08501526200139d92620011eb565b92610100604084013581840152610120906060850135828501526101409260808601358486015260a08601620013d3906200120b565b6001600160781b031661016095860152620013f160c0870162001220565b6001600160401b0316908d01526200140c60e0860162001220565b6001600160401b03166101a08d01528401620014289062001235565b61ffff166101c08c015283016200143f90620003d1565b6001600160a01b03166101e08b015282016200145b90620003d1565b6001600160a01b03166102008a01528101620014779162001245565b9092888303016102208901526200148e926200127c565b908582036020870152620014a292620011eb565b908382036040850152620014b692620011eb565b60608201939093523060808201526001600160a01b0390911660a0919091015203905ff080156200037b576001600160a01b031680337f4e00adea785ec41e8982a4c2939e6944708c005f20e84edd89183a2a877042fa5f80a390565b6001600160a01b039081169081156200156e575f805160206200566a83398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b604051631e4fbdf760e01b81525f6004820152602490fd5b8051909190156200159a5750805190602001fd5b60405162461bcd60e51b815290819062000fac906004830162000ae1565b5f805160206200566a833981519152546001600160a01b03163303620015da57565b60405163118cdaa760e01b8152336004820152602490fd5b90813b156200167c575f805160206200568a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562001660576200165d91620016cd565b50565b5050346200166a57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff5f80516020620056aa8339815191525460401c1615620016bb57565b604051631afcd79f60e31b8152600490fd5b5f8062000ecd93602081519101845af4620016e762000dbb565b9190620017115750805115620016ff57805190602001fd5b60405163d6bda27560e01b8152600490fd5b8151158062001746575b62001724575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200171b56fe60a08060405234620001c55762003f1980380380916200001f82620001dd565b833980820160c08212620001c55782516001600160401b0393909290848411620001c55783916101809485910312620001c5576200005c6200025e565b9382820151868111620001c557848362000079928601016200027f565b855260c0830151868111620001c557848362000098928601016200027f565b602086015260e083015160408601526101009283810151606087015261012080820151608088015261014090620000d1828401620002f3565b85890152620000f761016094620000ea86860162000308565b60c08b0152840162000308565b60e08901526200010b6101a084016200031d565b868901526200011e6101c084016200035d565b90880152620001316101e083016200035d565b90870152610200810151878111620001c5578386916200015393010162000372565b9085015260c051858111620001c55783620001709183016200027f565b9260e051958611620001c557620001ac956200018d92016200027f565b9051906200019a6200032d565b92620001a562000345565b9462000b76565b604051612cbb90816200123e8239608051816128e30152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b60a0601f91909101601f19168101906001600160401b038211908210176200020457604052565b620001c9565b60c081019081106001600160401b038211176200020457604052565b6001600160401b0381116200020457604052565b601f909101601f19168101906001600160401b038211908210176200020457604052565b6040519061018082016001600160401b038111838210176200020457604052565b919080601f84011215620001c55782516001600160401b038111620002045760209060405192620002ba83601f19601f85011601856200023a565b818452828287010111620001c5575f5b818110620002df5750825f9394955001015290565b8581018301518482018401528201620002ca565b51906001600160781b0382168203620001c557565b51906001600160401b0382168203620001c557565b519061ffff82168203620001c557565b61012051906001600160a01b0382168203620001c557565b61014051906001600160a01b0382168203620001c557565b51906001600160a01b0382168203620001c557565b81601f82011215620001c55780519060206001600160401b038311620002045760409360405194620003aa838660051b01876200023a565b848652828601918360c080970286010194818611620001c5578401925b858410620003d9575050505050505090565b8684830312620001c5578487918451620003f3816200020a565b8651815282870151838201526200040c868801620002f3565b8682015260606200041f81890162000308565b9082015260806200043281890162000308565b9082015260a08088015190820152815201930192620003c7565b60405190602082016001600160401b0381118382101762000204576040525f8252565b90600182811c921680156200049f575b60208310146200048b57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916200047f565b601f8111620004b7575050565b60025f5260205f20906020601f840160051c83019310620004f4575b601f0160051c01905b818110620004e8575050565b5f8155600101620004dc565b9091508190620004d3565b601f81116200050c575050565b60035f5260205f20906020601f840160051c8301931062000549575b601f0160051c01905b8181106200053d575050565b5f815560010162000531565b909150819062000528565b601f811162000561575050565b600b5f5260205f20906020601f840160051c830193106200059e575b601f0160051c01905b81811062000592575050565b5f815560010162000586565b90915081906200057d565b601f8111620005b6575050565b600c5f5260205f20906020601f840160051c83019310620005f3575b601f0160051c01905b818110620005e7575050565b5f8155600101620005db565b9091508190620005d2565b80519091906001600160401b03811162000204576200062a81620006246003546200046f565b620004ff565b602080601f83116001146200066f575081906200065e93945f9262000663575b50508160011b915f199060031b1c19161790565b600355565b015190505f806200064a565b60035f52601f198316949091907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b925f905b878210620006db575050836001959610620006c2575b505050811b01600355565b01515f1960f88460031b161c191690555f8080620006b7565b80600185968294968601518155019501930190620006a1565b80519091906001600160401b038111620002045762000720816200071a600b546200046f565b62000554565b602080601f831160011462000758575081906200075393945f92620006635750508160011b915f199060031b1c19161790565b600b55565b600b5f52601f198316949091907f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9925f905b878210620007c4575050836001959610620007ab575b505050811b01600b55565b01515f1960f88460031b161c191690555f8080620007a0565b806001859682949686015181550195019301906200078a565b80519091906001600160401b0381116200020457620008098162000803600c546200046f565b620005a9565b602080601f831160011462000841575081906200083c93945f92620006635750508160011b915f199060031b1c19161790565b600c55565b600c5f52601f198316949091907fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7925f905b878210620008ad57505083600195961062000894575b505050811b01600c55565b01515f1960f88460031b161c191690555f808062000889565b8060018596829496860151815501950193019062000873565b600281901b91906001600160fe1b03811603620008df57565b634e487b7160e01b5f52601160045260245ffd5b805190680100000000000000008211620002045760135482601355808310620009c1575b5060135f526020908101905f8051602062003ef98339815191525f925b84841062000943575050505050565b60048382620009b460019451869060a060039180518455602081015160018501556002840160018060781b03604083015116815490600160781b600160b81b03606085015160781b1690600160b81b600160f81b03608086015160b81b169260ff60f81b1617171790550151910155565b0192019301929062000934565b620009cc90620008c6565b620009d783620008c6565b60135f525f8051602062003ef983398151915291820191015b818110620009ff575062000917565b805f600492555f60018201555f60028201555f600382015501620009f0565b61016062000b5e9162000a328151620006f4565b62000a416020820151620007dd565b6040810151600d556060810151600e556080810151600f5560a08101516010805460c084015160e085015160789190911b600160781b600160b81b03166001600160781b039094167fff00000000000000000000000000000000000000000000000000000000000000909216919091179290921760b89290921b600160b81b600160f81b031691909117905562000af462000ae261010083015161ffff1690565b61ffff1661ffff196011541617601155565b61012081015162000b31906001600160a01b03166011805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b610140810151601280546001600160a01b0319166001600160a01b039092169190911790550151620008f3565b565b5f910312620001c557565b6040513d5f823e3d90fd5b92939162000b85918662000dae565b81516020815191012062000b986200044c565b6020815191012014801562000d8e575b801562000d80575b62000d6e576101408201516001600160a01b03168062000d5c575b5060805262000bda8162000a1e565b62000bea61016082015162000f9c565b734300000000000000000000000000000000000002803b15620001c55760405163388a0bbd60e11b81525f8160048183865af1801562000d285762000d45575b50803b15620001c5575f8091600460405180948193634e606c4760e01b83525af1801562000d285762000d2e575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd80090813b15620001c5576040516336b91f2b60e01b815273f8a82748e7df10d0684b758d02cf6c43ad83ad256004820152915f908390602490829084905af191821562000d285762000cf59262000d0a575b5061012081015162000cee9062000ce790610100906001600160a01b031693015161ffff1690565b61ffff1690565b90620010b1565b8062000cff575050565b62000b5e91620010f9565b8062000d1a62000d219262000226565b8062000b60565b5f62000cbf565b62000b6b565b8062000d1a62000d3e9262000226565b5f62000c58565b8062000d1a62000d559262000226565b5f62000c2a565b62000d679062000ee6565b5f62000bcb565b604051635435b28960e11b8152600490fd5b506040820151831162000bb0565b506107d061ffff62000da661010085015161ffff1690565b161162000ba8565b815191939290916001600160401b038111620002045762000ddc8162000dd66002546200046f565b620004aa565b602080601f831160011462000e545750908062000e159262000e1e9596975f92620006635750508160011b915f199060031b1c19161790565b600255620005fe565b5f80556001600160a01b0381161562000e3c5762000b5e90620011dc565b604051631e4fbdf760e01b81525f6004820152602490fd5b60025f52601f198316969091907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace925f905b89821062000ecd5750509083929160019462000e1e9798991062000eb4575b505050811b01600255620005fe565b01515f1960f88460031b161c191690555f808062000ea5565b8060018596829496860151815501950193019062000e86565b6001600160a01b0316734300000000000000000000000000000000000003811462000f705773b1a5700fa2358173fe465e6ea4ff52e36e88e2ad811462000f7057735ffd9ebd27f2fcab044c0f0a26a45cb62fa29c06811462000f705773d43d8adac6a4c7d9aeece7c3151fca8f23752cf81462000b5e57604051631eb3268560e31b8152600490fd5b50565b805182101562000f885760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b90600382511162001011575f805b8351821015620010ab5762000fc0828562000f73565b5151906020918262000fd3858862000f73565b510151109081156200108e575b811562001053575b50801562001023575b620010115760019062001005838662000f73565b51015191019062000faa565b60405163097191df60e41b8152600490fd5b5062001030828562000f73565b515115801562000ff157508062001048838662000f73565b510151151562000ff1565b905062001061838662000f73565b51511515908162001075575b505f62000fe8565b905062001083838662000f73565b515111155f6200106d565b9050816200109d848762000f73565b510151600e54109062000fe0565b50509050565b6001600160601b03909116906127108211620010ec5760601b8015620010df571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b905f54918115620011cd576001916200115060018060a01b038316926001831460e11b4260a01b17841762001136875f52600460205260405f2090565b556001600160a01b03165f90815260056020526040902090565b68010000000000000001820281540190558115620011c757830192916001815b6200117e575b505050505f55565b15620011b4575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a462001170565b8092019183830362001185578062001176565b6200122f565b63b562e8dd60e01b5f5260045ffd5b600a80546001600160a01b0319908116909155600980549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b622e076360e81b5f5260045ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146102f457806306fdde03146102ef578063081812fc146102ea57806309430a7e146102e5578063095ea7b3146102e057806318160ddd146102db5780631869ebda146102d657806323b872dd146102d157806326e2dca2146102cc5780632a55205a146102c75780632e1a7d4d146102c25780633add14c8146102bd5780633ccfd60b146102b857806340c10f19146102b357806342842e0e146102ae5780634fdf5d1d146102a957806353df5c7c146102a457806355f804b31461029f5780635e0cee0f1461029a5780636352211e146102955780636f8b44b014610290578063708b31f31461028b57806370a0823114610286578063715018a61461028157806375eedb451461027c57806379ba5097146102775780638503e714146102725780638da5cb5b1461026d578063938e3d7b1461026857806395d89b4114610263578063999927df1461025e5780639d0172f314610259578063a22cb46514610254578063acd9d3ea1461024f578063b88d4fde1461024a578063c4fe0fba14610245578063c87b56dd14610240578063d55829651461023b578063e1c2ffad14610236578063e30c397814610231578063e4be0c061461022c578063e8a3d48514610227578063e985e9c514610222578063f2fde38b1461021d578063f557ab03146102185763f8bd83e114610213575f80fd5b6121f9565b6121bd565b612151565b6120f5565b6120c6565b611e35565b611e0d565b611de4565b611d6f565b611cd3565b611c81565b611bef565b611b75565b611ae5565b611a91565b611a30565b61198b565b61185f565b611837565b61180c565b61178a565b611697565b6115cf565b611579565b61145b565b611226565b6111f7565b611127565b611005565b610f95565b610e2f565b610df7565b610c46565b610b29565b610af1565b6109db565b610953565b610870565b61082e565b610752565b610731565b610687565b610535565b6104e6565b610406565b61030f565b6001600160e01b031981160361030b57565b5f80fd5b3461030b57602036600319011261030b57602060043561032e816102f9565b6001600160e01b031981166301ffc9a760e01b811491908215610391575b8215610380575b508115610366575b506040519015158152f35b905060e01c6301ffc9a7632a55205a82149114175f61035b565b635b5e139f60e01b1491505f610353565b6380ac58cd60e01b8114925061034c565b5f91031261030b57565b5f5b8381106103bd5750505f910152565b81810151838201526020016103ae565b906020916103e6815180928185528580860191016103ac565b601f01601f1916010190565b9060206104039281815201906103cd565b90565b3461030b575f36600319011261030b576040515f6002546104268161128e565b808452906020906001908181169081156104bc5750600114610463575b61045f85610453818703826112ed565b604051918291826103f2565b0390f35b60025f90815293507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8385106104a9575050505081016020016104538261045f610443565b805486860184015293820193810161048d565b86955061045f9693506020925061045394915060ff191682840152151560051b8201019293610443565b3461030b57602036600319011261030b57600435610503816127d6565b15610526575f526006602052602060018060a01b0360405f205416604051908152f35b6333d1c03960e21b5f5260045ffd5b3461030b575f36600319011261030b576013546105518161225f565b60409161056160405192836112ed565b8082526020808301918260135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0905f915b83831061062257505050506040519281840190828552518091526040840192915f5b8281106105c25785850386f35b8351805186528083015186840152878101516001600160781b0316888701526060808201516001600160401b03908116918801919091526080808301519091169087015260a0908101519086015260c090940193928101926001016105b5565b600485600192610634859a989a612276565b815201920192019190959395610593565b600435906001600160a01b038216820361030b57565b604435906001600160a01b038216820361030b57565b602435906001600160a01b038216820361030b57565b604036600319011261030b5761069b610645565b602435906001600160a01b03806106b184612864565b1690813303610702575b835f52600660205260405f20921691826001600160601b0360a01b8254161790557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b5f82815260076020908152604080832033845290915290205460ff166106bb576367d9dca160e11b5f5260045ffd5b3461030b575f36600319011261030b5760205f546001549003604051908152f35b3461030b57604036600319011261030b576107b16020610770610645565b610778612850565b604051637cb8cb3160e11b81523060048201526001600160a01b0390911660248083019190915235604482015291829081906064820190565b03815f6002604360981b015af180156107f4576107ca57005b6107eb9060203d6020116107ed575b6107e381836112ed565b8101906122da565b005b503d6107d9565b6122e9565b606090600319011261030b576001600160a01b0390600435828116810361030b5791602435908116810361030b579060443590565b6107eb61083a366107f9565b916122f4565b9181601f8401121561030b578235916001600160401b03831161030b576020808501948460051b01011161030b57565b3461030b57606036600319011261030b57610889610645565b602435906001600160401b03821161030b576108ab6004923690600401610840565b9290916108b661065b565b936108bf612850565b6001600160a01b03909116905f5b8181106108d657005b6108e181838761248b565b3590833b1561030b57604080516323b872dd60e01b8152308782019081526001600160a01b038a166020820152918201939093525f9083908190606001038183885af19182156107f45760019261093a575b50016108cd565b8061094761094d926112da565b806103a2565b5f610933565b3461030b57604036600319011261030b576024356004355f5268aa4ec00224afccfdb7908160205260405f20548060601c9283156109c9575b5061045f908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b54606081901c9350905061045f61098c565b3461030b57602036600319011261030b575f6004356109f8612850565b806015548082118414610ada575050610a105f601555565b6012546001600160a01b031615158214610ab157601254602091610a7991610a4e90610a42906001600160a01b031681565b6001600160a01b031690565b60405163a9059cbb60e01b815233600482015260248101929092529093849283919082906044820190565b03925af180156107f457610a8957005b6107eb9060203d602011610aaa575b610aa281836112ed565b8101906124f5565b503d610a98565b81808092335af1610ac06124c6565b5015610ac857005b6040516327fcd9d160e01b8152600490fd5b610aec91610ae7916124b4565b601555565b610a10565b3461030b57602036600319011261030b576001600160a01b03610b12610645565b165f526017602052602060405f2054604051908152f35b3461030b575f36600319011261030b57610b41612850565b6012546001600160a01b031615610c1f57601254610b6990610a42906001600160a01b031681565b6040516370a0823160e01b8152306004820152602091908281602481855afa9081156107f4575f928492610bc9928591610c02575b5060405163a9059cbb60e01b8152336004820152602481019190915293849283919082906044820190565b03925af180156107f457610be4575b50505b6107eb5f601555565b81610bfa92903d10610aaa57610aa281836112ed565b505f80610bd8565b610c199150843d86116107ed576107e381836112ed565b5f610b9e565b5f80808047335af1610c2f6124c6565b50610bdb576040516327fcd9d160e01b8152600490fd5b60408060031936011261030b57610c5b610645565b60243590610c68826128e1565b600e5442108015610deb575b8015610ddf575b610dce576010546001600160401b03808260781c168411610dbd576001600160a01b0383165f908152601760205260409020610cba9085905b546128d4565b908260b81c1610610dac57826001600160781b03610cd8921661294a565b6012549093906001600160a01b031680610d425750833410610d325750610d2d610ae76107eb945b6001600160a01b0384165f9081526017602052604090205b610d238682546128d4565b90556015546128d4565b612b41565b5163356680b760e01b8152600490fd5b90516323b872dd60e01b81523360048201523060248201526044810185905290602090829060649082905f905af180156107f4576107eb94610d2d92610ae792610d8d575b50610d00565b610da59060203d602011610aaa57610aa281836112ed565b505f610d87565b8351634413775560e11b8152600490fd5b845163635a2d9b60e01b8152600490fd5b825163914edb0f60e01b8152600490fd5b5060185460ff16610c7b565b5042600f541115610c74565b610e00366107f9565b6040519160208301938385106001600160401b03861117610e2a576107eb946040525f84526126cd565b6112c6565b3461030b57604036600319011261030b57610e48610645565b610e50610671565b90610e59612850565b6001600160a01b03169081610eb1575f80806107eb9481944791610e87610a4260125460018060a01b031690565b14610e9d575b5af1610e976124c6565b5061250a565b90610eab90601554906124b4565b90610e8d565b6040516370a0823160e01b81523060048201526020928382602481845afa9081156107f457610f3a9385935f93610f76575b506012548390610efb906001600160a01b0316610a42565b8314610f60575b5060405163a9059cbb60e01b81526001600160a01b0390911660048201526024810192909252909283919082905f9082906044820190565b03925af180156107f457610f4a57005b816107eb92903d10610aaa57610aa281836112ed565b610f6f919350601554906124b4565b915f610f02565b610f8e919350843d86116107ed576107e381836112ed565b915f610ee3565b3461030b575f36600319011261030b57610fad612850565b6014805460ff19166001179055005b90602060031983011261030b576004356001600160401b039283821161030b578060238301121561030b57816004013593841161030b576024848301011161030b576024019190565b3461030b5761101336610fbc565b61101b612850565b60ff60145416611115576001600160401b038111610e2a5761104781611042600b5461128e565b61254f565b5f601f82116001146110a9578190611074935f9261109e575b50508160011b915f199060031b1c19161790565b600b555b7fa239f4bbfd90a175f9b529d5ee0788e561e3b14a3f60866421828226b31e883c5f80a1005b013590505f80611060565b600b5f52601f198216925f80516020612c66833981519152915f5b8581106110fd575083600195106110e4575b505050811b01600b55611078565b01355f19600384901b60f8161c191690555f80806110d6565b909260206001819286860135815501940191016110c4565b60405163696c636960e01b8152600490fd5b3461030b57604036600319011261030b57611140610645565b6024359061ffff82169182810361030b57611159612850565b60ff60145460101c166111e5576107d083116111d357601180546001600160b01b03191662010000600160b01b03601085901b161761ffff9092169190911790556111a4828261295d565b6001600160a01b03167ff1ae48f8f3e1bed700c52bee6fe28096c85db77867f9a18f35144c33ce6db2b45f80a3005b60405163a2a65b5360e01b8152600490fd5b604051635a214b2560e11b8152600490fd5b3461030b57602036600319011261030b5760206001600160a01b0361121d600435612864565b16604051908152f35b3461030b57602036600319011261030b57600435611242612850565b61124a6129a2565b5f54811061127c5780600d557f3f8118fc46e72ecde0c5e090803cad8c88e817b2f1e93e820aa9bfbf51f2468d5f80a2005b60405163066f305360e21b8152600490fd5b90600182811c921680156112bc575b60208310146112a857565b634e487b7160e01b5f52602260045260245ffd5b91607f169161129d565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111610e2a57604052565b90601f801991011681019081106001600160401b03821117610e2a57604052565b604051905f82600c54916113218361128e565b808352926020906001908181169081156113ad575060011461134e575b505061134c925003836112ed565b565b915092600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7935f925b828410611395575061134c9450505081016020015f8061133e565b8554888501830152948501948794509281019261137a565b9150506020925061134c94915060ff191682840152151560051b8201015f8061133e565b9997929b9a969394610140999561140f8c6001600160781b039561140161ffff9b966101608085528401906103cd565b9160208184039101526103cd565b60408d019e909e5260608c015260808b01521660a08901526001600160401b0391821660c08901521660e0870152166101008501526001600160a01b0391821661012085015216910152565b3461030b575f36600319011261030b576040515f600b5461147b8161128e565b8084529060209060019081811690811561154f5750600114611509575b61ffff856114a8818703826112ed565b61045f6114b361130e565b91600d5490600e5493600f54916010546001600160401b03916011549460018060a01b03988960125416976040519b8c9b8960101c169816966001600160781b03878760b81c16978760781c169616948c6113d1565b600b5f90815293505f80516020612c668339815191525b83851061153c575050505081016020016114a88261ffff611498565b8054868601840152938201938101611520565b86955061ffff969350602092506114a894915060ff191682840152151560051b8201019293611498565b3461030b57602036600319011261030b576001600160a01b0361159a610645565b1680156115c0575f52600560205260206001600160401b0360405f205416604051908152f35b6323d3ad8160e21b5f5260045ffd5b3461030b575f36600319011261030b576115e7612850565b600a80546001600160a01b03199081169091556009805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106116695750505050505090565b9091929394958480611687600193603f198682030187528a516103cd565b9801930193019194939290611659565b3461030b5760208060031936011261030b576004356001600160401b03811161030b576116c8903690600401610840565b916116d1612850565b6116da8361225f565b926040916116eb60405195866112ed565b818552601f196116fa8361225f565b015f5b81811061177b575050505f5b81811061171e576040518061045f8782611634565b5f8061172b838588612616565b9061173a875180938193612657565b0390305af46117476124c6565b901561176d579060019161175b82886126b9565b5261176681876126b9565b5001611709565b611775612664565b90612a13565b606087820184015282016116fd565b3461030b575f36600319011261030b57600a546001600160a01b0333818316036117f4576001600160601b0360a01b809216600a556009549133908316176009553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b3461030b575f36600319011261030b57611824612850565b6014805462ff0000191662010000179055005b3461030b575f36600319011261030b576009546040516001600160a01b039091168152602090f35b3461030b5761186d36610fbc565b611875612850565b60ff60145460081c16611979576001600160401b038111610e2a576118a48161189f600c5461128e565b6125a9565b5f601f82116001146118fa5781906118d0935f9261109e5750508160011b915f199060031b1c19161790565b600c555b7f801a056d1f533ad9d100de2039b5996850ae077400027351617645308a59cf2e5f80a1005b600c5f52601f198216927fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7915f5b85811061196157508360019510611948575b505050811b01600c556118d4565b01355f19600384901b60f8161c191690555f808061193a565b90926020600181928686013581550194019101611928565b604051631fd0326960e01b8152600490fd5b3461030b575f36600319011261030b576040515f6003546119ab8161128e565b808452906020906001908181169081156104bc57506001146119d75761045f85610453818703826112ed565b60035f90815293507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b838510611a1d575050505081016020016104538261045f610443565b8054868601840152938201938101611a01565b3461030b57602036600319011261030b57611a49610645565b611a51612850565b60405163430021db60e11b81523060048201526001600160a01b0390911660248201526020816044815f6002604360981b015af180156107f4576107ca57005b3461030b57602036600319011261030b576004356001600160781b03811680910361030b57611abe612850565b611ac66129a2565b6001600160781b031960105416176010555f80f35b8015150361030b57565b3461030b57604036600319011261030b57611afe610645565b60243590611b0b82611adb565b335f9081526007602090815260408083206001600160a01b038516845290915290209115159160ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b3461030b57604036600319011261030b576107b16020611b93610645565b611b9b612850565b604051630951888f60e01b81523060048201526001600160a01b0390911660248083019190915235604482015291829081906064820190565b6001600160401b038111610e2a57601f01601f191660200190565b608036600319011261030b57611c03610645565b611c0b610671565b606435916001600160401b03831161030b573660238401121561030b57826004013591611c3783611bd4565b92611c4560405194856112ed565b808452366024828701011161030b576020815f9260246107eb98018388013785010152604435916126cd565b6004359060ff8216820361030b57565b3461030b57604036600319011261030b576020611cca611c9f611c71565b60ff611ca9610671565b91165f526016835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461030b57602036600319011261030b57600435611cf0816127d6565b15611d5d5760405190608082019060a083016040525f8252905b5f190190600a906030828206018353049081611d0a57611d5161045361045f92856080601f19928381019203018152604051938491611d4b6020840161270e565b90612787565b039081018352826112ed565b60405163677510db60e11b8152600490fd5b3461030b575f36600319011261030b57611d87612850565b600160ff1960185416176018555f5480600d557fcbbaae1b89885aa88b0db407075a1f3e6df45931447d19c7da5f5b7471a729e55f80a17f3f8118fc46e72ecde0c5e090803cad8c88e817b2f1e93e820aa9bfbf51f2468d5f80a2005b3461030b575f36600319011261030b57611dfc612850565b6014805461ff001916610100179055005b3461030b575f36600319011261030b57600a546040516001600160a01b039091168152602090f35b608036600319011261030b57611e49611c71565b602435906001600160401b03821161030b57611e6a60049236908401610840565b91611e7361065b565b9160643593611e81856128e1565b611e93611e8d8461279e565b50612276565b918251421080156120b8575b6120a757611ec6611eba60608501516001600160401b031690565b6001600160401b031690565b861161209657611efe86610cb487611ee98860ff165f52601660205260405f2090565b9060018060a01b03165f5260205260405f2090565b611f15611eba60808601516001600160401b031690565b1061208557604080516001600160a01b03871660208083019182528252611f6c94611f689490939092611f559291611f4d90826112ed565b519020612b18565b602081519101209160a086015191612c1b565b1590565b6120745783611f97611f8b6040611f9c9401516001600160781b031690565b6001600160781b031690565b61294a565b6012549094906001600160a01b031680611feb5750843410611fdc5750610ae76107eb94610d1884611ee9610d2d9560ff165f52601660205260405f2090565b60405163356680b760e01b8152fd5b604080516323b872dd60e01b815233938101938452306020858101919091529184018890529396929091849182905f90829060600103925af19081156107f457610d1884611ee96107eb98610d2d96610ae796612055575b5060ff165f52601660205260405f2090565b61206d9060203d602011610aaa57610aa281836112ed565b505f612043565b60405163582f497d60e11b81528590fd5b60405163bdaa15c960e01b81528790fd5b6040516318e99c4960e21b81528790fd5b60405163cbe8d62360e01b81528790fd5b504260208401511115611e9f565b3461030b575f36600319011261030b5761045f6120e161130e565b6040519182916020835260208301906103cd565b3461030b57604036600319011261030b57602060ff612145612115610645565b61211d610671565b6001600160a01b039182165f9081526007865260408082209290931681526020919091522090565b54166040519015158152f35b3461030b57602036600319011261030b5761216a610645565b612172612850565b600a80546001600160a01b0319166001600160a01b039283169081179091556009549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b3461030b575f36600319011261030b57606060145460ff6040519181811615158352818160081c161515602084015260101c1615156040820152f35b3461030b57604036600319011261030b57612212611c71565b602435906001600160781b03821680920361030b57612242600291612235612850565b61223d6129a2565b61279e565b500180546effffffffffffffffffffffffffffff19169091179055005b6001600160401b038111610e2a5760051b60200190565b6040516001600160401b03929160c0820184811183821017610e2a5760a0916003916040528395815485526001820154602086015260028201546001600160781b0381166040870152818160781c16606087015260b81c1660808501520154910152565b9081602091031261030b575190565b6040513d5f823e3d90fd5b91909161230082612864565b6001600160a01b039182169390828116859003612472575f848152600660205260409020805461233f6001600160a01b03881633908114908314171590565b61243d575b612434575b506001600160a01b0385165f90815260056020526040902080545f190190556001600160a01b0382165f908152600560205260409020805460010190556001600160a01b0382164260a01b17600160e11b176123ad855f52600460205260405f2090565b55600160e11b8116156123ef575b501680927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4156123ea57565b612832565b60018401612405815f52600460205260405f2090565b5415612412575b506123bb565b5f54811461240c5761242c905f52600460205260405f2090565b555f8061240c565b5f90555f612349565b612468611f6861246133611ee98b60018060a01b03165f52600760205260405f2090565b5460ff1690565b1561234457612823565b612815565b634e487b7160e01b5f52603260045260245ffd5b919081101561249b5760051b0190565b612477565b634e487b7160e01b5f52601160045260245ffd5b919082039182116124c157565b6124a0565b3d156124f0573d906124d782611bd4565b916124e560405193846112ed565b82523d5f602084013e565b606090565b9081602091031261030b575161040381611adb565b1561251157565b60405162461bcd60e51b815260206004820152601660248201527513985d1a5d99481d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b601f811161255b575050565b600b5f525f80516020612c66833981519152906020601f840160051c8301931061259f575b601f0160051c01905b818110612594575050565b5f8155600101612589565b9091508190612580565b601f81116125b5575050565b600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7906020601f840160051c8301931061260c575b601f0160051c01905b818110612601575050565b5f81556001016125f6565b90915081906125ed565b919081101561249b5760051b81013590601e198136030182121561030b5701908135916001600160401b03831161030b57602001823603811361030b579190565b908092918237015f815290565b60405190606082018281106001600160401b03821117610e2a5760405260238252621b195960ea1b6040837f426c617a654d616e616765723a2077686974656c697374206d696e742066616960208201520152565b805182101561249b5760209160051b010190565b9291906126db8282866122f4565b803b6126e8575b50505050565b6126f193612a63565b156126ff575f8080806126e2565b6368d2bf6b60e11b5f5260045ffd5b600b545f929161271d8261128e565b91600190818116908115612774575060011461273857505050565b9091929350600b5f525f80516020612c66833981519152905f915b848310612761575050500190565b8181602092548587015201920191612753565b60ff191683525050811515909102019150565b9061279a602092828151948592016103ac565b0190565b60135481101561249b5760135f5260021b7f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001905f90565b905f915f5481106127e45750565b9091505b805f52600460205260405f205480612809575080156124c1575f19016127e8565b600160e01b1615919050565b62a1148160e81b5f5260045ffd5b632ce44b5f60e11b5f5260045ffd5b633a954ecd60e21b5f5260045ffd5b636f96cda160e11b5f5260045ffd5b6009546001600160a01b031633036117f457565b612876815f52600460205260405f2090565b5490811561288d5750600160e01b81166128415790565b90505f54811015612841575b5f19015f818152600460205260409020549081156128cd5750600160e01b81161561040357636f96cda160e11b5f5260045ffd5b9050612899565b919082018092116124c157565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612939575f549081018091116124c157600d541061292757565b60405163d05cb60960e01b8152600490fd5b6040516282b42960e81b8152600490fd5b818102929181159184041417156124c157565b906001600160601b03169061271082116129955760601b8015612988571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b600e54421180612a08575b6129e0576013545f5b8181106129c1575050565b6129ca8161279e565b50544211806129f2575b6129e0576001016129b6565b604051633f19d52960e21b8152600490fd5b5060016129fe8261279e565b50015442106129d4565b50600f5442106129ad565b805190919015612a265750805190602001fd5b60405162461bcd60e51b815260206004820152908190612a4a9060248301906103cd565b0390fd5b9081602091031261030b5751610403816102f9565b92602091612aab935f60018060a01b0360405180978196829584630a85bd0160e11b9c8d865233600487015216602485015260448401526080606484015260848301906103cd565b0393165af15f9181612ae7575b50612ad957612ac56124c6565b805115612ad457805190602001fd5b6126ff565b6001600160e01b0319161490565b612b0a91925060203d602011612b11575b612b0281836112ed565b810190612a4e565b905f612ab8565b503d612af8565b9060405191602083015260208252604082018281106001600160401b03821117610e2a57604052565b5f54918015612c0c576001916001600160a01b0381164260a01b83851460e11b1717612b75855f52600460205260405f2090565b556001600160a01b03165f8181526005602052604090208054680100000000000000018402019055908115612bfe57830192916001815b612bb9575b505050505f55565b15612bed575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4612bac565b80920191838303612bbf5780612bb1565b622e076360e81b5f5260045ffd5b63b562e8dd60e01b5f5260045ffd5b81939293612c2a575b50501490565b60059291831b8101915b8135808211851b91825260208092185260405f2091019282841015612c5a579290612c34565b509150505f80612c2456fe0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212208dd0488414d470d364d29901e2d3d5e1cf5d26d63da42d3741fd6f0df1c7837764736f6c6343000818003366de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0909016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220757472b7162687e5d295b2976bb94c21b989e650698a609161a50cd9dc7e805f64736f6c63430008180033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.