ETH Price: $2,939.59 (-0.61%)

Contract

0xAE11033B196002fCe0DfE1FE373172cF62235Da2

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Get Grinding364493052026-01-24 17:52:1913 hrs ago1769277139IN
0xAE11033B...F62235Da2
0 ETH0.000019440.04525
Get Grinding361293132026-01-22 17:48:482 days ago1769104128IN
0xAE11033B...F62235Da2
0 ETH0.000022480.04525
Get Grinding361230972026-01-22 16:41:562 days ago1769100116IN
0xAE11033B...F62235Da2
0 ETH0.00001070.04525
Get Grinding361222092026-01-22 16:34:062 days ago1769099646IN
0xAE11033B...F62235Da2
0 ETH0.000010320.04525
Get Grinding361179162026-01-22 15:59:592 days ago1769097599IN
0xAE11033B...F62235Da2
0 ETH0.000013580.04525
Get Grinding360253012026-01-22 1:47:253 days ago1769046445IN
0xAE11033B...F62235Da2
0 ETH0.000011820.04525
Get Grinding359761862026-01-21 16:42:403 days ago1769013760IN
0xAE11033B...F62235Da2
0 ETH0.00001270.04525
Get Grinding359653812026-01-21 15:06:053 days ago1769007965IN
0xAE11033B...F62235Da2
0 ETH0.000010310.04525
Get Grinding359647462026-01-21 15:01:293 days ago1769007689IN
0xAE11033B...F62235Da2
0 ETH0.000010230.04525
Get Grinding358489012026-01-20 21:31:534 days ago1768944713IN
0xAE11033B...F62235Da2
0 ETH0.000017520.04525
Get Grinding358368832026-01-20 19:16:064 days ago1768936566IN
0xAE11033B...F62235Da2
0 ETH0.000018150.04525
Get Grinding358218392026-01-20 17:04:044 days ago1768928644IN
0xAE11033B...F62235Da2
0 ETH0.000012690.04525
Get Grinding358170922026-01-20 16:23:394 days ago1768926219IN
0xAE11033B...F62235Da2
0 ETH0.000015260.04525
Get Grinding358132352026-01-20 15:48:184 days ago1768924098IN
0xAE11033B...F62235Da2
0 ETH0.000024620.04525
Get Grinding356466062026-01-19 15:09:565 days ago1768835396IN
0xAE11033B...F62235Da2
0 ETH0.000012240.04525
Get Grinding355666552026-01-19 3:57:186 days ago1768795038IN
0xAE11033B...F62235Da2
0 ETH0.000009340.04525
Get Grinding355167792026-01-18 18:24:166 days ago1768760656IN
0xAE11033B...F62235Da2
0 ETH0.0000110.04525
Get Grinding354751972026-01-18 11:05:046 days ago1768734304IN
0xAE11033B...F62235Da2
0 ETH0.000018110.04525
Get Grinding354395182026-01-18 4:33:117 days ago1768710791IN
0xAE11033B...F62235Da2
0 ETH0.000013480.04525
Get Grinding353440142026-01-17 10:51:237 days ago1768647083IN
0xAE11033B...F62235Da2
0 ETH0.000017280.04525
Get Grinding352604102026-01-16 22:22:518 days ago1768602171IN
0xAE11033B...F62235Da2
0 ETH0.000018110.04525
Get Grinding352497222026-01-16 20:31:598 days ago1768595519IN
0xAE11033B...F62235Da2
0 ETH0.0000110.04525
Get Grinding352300902026-01-16 17:38:198 days ago1768585099IN
0xAE11033B...F62235Da2
0 ETH0.000013120.04525
Get Grinding352086002026-01-16 14:37:458 days ago1768574265IN
0xAE11033B...F62235Da2
0 ETH0.000023010.04525
Get Grinding352080302026-01-16 14:33:088 days ago1768573988IN
0xAE11033B...F62235Da2
0 ETH0.000008250.04525
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
131292632025-06-30 15:13:55208 days ago1751296435  Contract Creation0 ETH
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GrindClaim

Compiler Version
v0.8.28+commit.7893614a

ZkSolc Version
v1.5.12

Optimization Enabled:
Yes with Mode 3

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {IERC721} from "forge-std/interfaces/IERC721.sol";
import {Ownable} from "solady-0.1.19/src/auth/Ownable.sol";
import {EIP712} from "solady-0.1.19/src/utils/EIP712.sol";
import {SignatureCheckerLib} from "solady-0.1.19/src/utils/SignatureCheckerLib.sol";
import {SafeTransferLib} from "solady-0.1.19/src/utils/ext/zksync/SafeTransferLib.sol";
import {Claim, ClaimDetail, ClaimHistory} from "./Structs.sol";

contract GrindClaim is Ownable, EIP712 {
    using SafeTransferLib for address;
    using SafeTransferLib for address payable;

    bytes32 public constant CLAIM_TYPEHASH = keccak256(
        "Claim(address to,uint256 deadline,ClaimDetail[] details)ClaimDetail(bytes32 data,uint128 amount,uint128 bonusAmount)"
    );
    bytes32 public constant CLAIM_DETAIL_TYPEHASH =
        keccak256("ClaimDetail(bytes32 data,uint128 amount,uint128 bonusAmount)");

    address public immutable GRIND;

    address public signer;
    bool public claimEnabled;

    mapping(bytes32 => ClaimHistory) private _amountsClaimed;

    error ClaimNotActive();
    error InvalidSignature();
    error SignatureExpired();

    event Claimed(bytes32 indexed key, address indexed to, uint256 claimedAmount, uint256 totalClaimed);
    event BonusClaimed(bytes32 indexed key, address indexed bonusWallet, uint256 bonusAmount);

    constructor(address owner, address grind, address _signer) {
        _initializeOwner(owner);
        GRIND = grind;
        signer = _signer;
    }

    function setSigner(address _signer) external onlyOwner {
        signer = _signer;
    }

    function setClaimEnabled(bool _claimEnabled) external onlyOwner {
        claimEnabled = _claimEnabled;
    }

    function withdrawERC20(address token, uint256 amount) external onlyOwner {
        token.safeTransfer(msg.sender, amount);
    }

    function rescueETH(uint256 amount) external onlyOwner {
        payable(msg.sender).safeTransferETH(amount);
    }

    function rescueERC721(address token, uint256 tokenId) external onlyOwner {
        IERC721(token).transferFrom(address(this), msg.sender, tokenId);
    }

    function getGrinding(Claim calldata claim, bytes calldata signature) external {
        require(claimEnabled, ClaimNotActive());
        require(block.timestamp <= claim.deadline, SignatureExpired());

        bytes32 digest = _hashTypedData(_hashClaim(claim));
        require(SignatureCheckerLib.isValidSignatureNowCalldata(signer, digest, signature), InvalidSignature());

        uint256 totalAmount;

        uint256 claimDetailCount = claim.details.length;
        if (claimDetailCount > 0) {
            for (uint256 i; i < claimDetailCount; ++i) {
                ClaimDetail calldata claimDetail = claim.details[i];
                ClaimHistory memory alreadyClaimed = _amountsClaimed[claimDetail.data];
                if (claimDetail.amount > alreadyClaimed.amount) {
                    _amountsClaimed[claimDetail.data].amount = claimDetail.amount;
                    uint256 amountToClaim = claimDetail.amount - alreadyClaimed.amount;
                    totalAmount += amountToClaim;
                    emit Claimed(claimDetail.data, claim.to, amountToClaim, claimDetail.amount);
                }
                // bonus can only be claimed once per claim
                if (claimDetail.bonusAmount > 0 && alreadyClaimed.bonusAmount == 0) {
                    _amountsClaimed[claimDetail.data].bonusAmount = claimDetail.bonusAmount;
                    totalAmount += claimDetail.bonusAmount;
                    emit BonusClaimed(claimDetail.data, claim.to, claimDetail.bonusAmount);
                }
            }
        }

        if (totalAmount > 0) {
            GRIND.safeTransfer(claim.to, totalAmount);
        }
    }

    function nftClaimStatus(address nftContract, uint96 tokenId) external view returns (uint256 amount) {
        return _amountsClaimed[_packNft(nftContract, tokenId)].amount;
    }

    function getClaimStatus(bytes32 data) external view returns (uint256 amountClaimed) {
        return _amountsClaimed[data].amount;
    }

    function getClaimBonus(bytes32 data) external view returns (uint256 amount) {
        return _amountsClaimed[data].bonusAmount;
    }

    function _domainNameAndVersion() internal pure override returns (string memory, string memory) {
        return ("GrindClaim", "1");
    }

    function _packNft(address nftContract, uint96 tokenId) internal pure returns (bytes32) {
        return bytes32((uint256(uint160(nftContract)) << 96) | tokenId);
    }

    function _hashClaimDetail(ClaimDetail calldata claimDetail) internal pure returns (bytes32) {
        return
            keccak256(abi.encode(CLAIM_DETAIL_TYPEHASH, claimDetail.data, claimDetail.amount, claimDetail.bonusAmount));
    }

    function _hashClaim(Claim calldata claim) internal pure returns (bytes32) {
        uint256 claimDetailCount = claim.details.length;
        bytes32[] memory claimDetailHashes = new bytes32[](claimDetailCount);
        for (uint256 i; i < claimDetailCount; ++i) {
            claimDetailHashes[i] = _hashClaimDetail(claim.details[i]);
        }

        return keccak256(
            abi.encode(CLAIM_TYPEHASH, claim.to, claim.deadline, keccak256(abi.encodePacked(claimDetailHashes)))
        );
    }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
    /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
    /// is the new allowance.
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /// @notice Returns the amount of tokens in existence.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the amount of tokens owned by `account`.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Moves `amount` tokens from the caller's account to `to`.
    function transfer(address to, uint256 amount) external returns (bool);

    /// @notice Returns the remaining number of tokens that `spender` is allowed
    /// to spend on behalf of `owner`
    function allowance(address owner, address spender) external view returns (uint256);

    /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
    /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    function approve(address spender, uint256 amount) external returns (bool);

    /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
    /// `amount` is then deducted from the caller's allowance.
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    /// @notice Returns the name of the token.
    function name() external view returns (string memory);

    /// @notice Returns the symbol of the token.
    function symbol() external view returns (string memory);

    /// @notice Returns the decimals places of the token.
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

import {IERC165} from "./IERC165.sol";

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 is IERC165 {
    /// @dev This emits when ownership of any NFT changes by any mechanism.
    /// This event emits when NFTs are created (`from` == 0) and destroyed
    /// (`to` == 0). Exception: during contract creation, any number of NFTs
    /// may be created and assigned without emitting Transfer. At the time of
    /// any transfer, the approved address for that NFT (if any) is reset to none.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

    /// @dev This emits when the approved address for an NFT is changed or
    /// reaffirmed. The zero address indicates there is no approved address.
    /// When a Transfer event emits, this also indicates that the approved
    /// address for that NFT (if any) is reset to none.
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

    /// @dev This emits when an operator is enabled or disabled for an owner.
    /// The operator can manage all NFTs of the owner.
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    /// @notice Count all NFTs assigned to an owner
    /// @dev NFTs assigned to the zero address are considered invalid, and this
    /// function throws for queries about the zero address.
    /// @param _owner An address for whom to query the balance
    /// @return The number of NFTs owned by `_owner`, possibly zero
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Find the owner of an NFT
    /// @dev NFTs assigned to zero address are considered invalid, and queries
    /// about them do throw.
    /// @param _tokenId The identifier for an NFT
    /// @return The address of the owner of the NFT
    function ownerOf(uint256 _tokenId) external view returns (address);

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    /// operator, or the approved address for this NFT. Throws if `_from` is
    /// not the current owner. Throws if `_to` is the zero address. Throws if
    /// `_tokenId` is not a valid NFT. When transfer is complete, this function
    /// checks if `_to` is a smart contract (code size > 0). If so, it calls
    /// `onERC721Received` on `_to` and throws if the return value is not
    /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    /// @param data Additional data with no specified format, sent in call to `_to`
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev This works identically to the other function with an extra data parameter,
    /// except this function just sets data to "".
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
    /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
    /// THEY MAY BE PERMANENTLY LOST
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    /// operator, or the approved address for this NFT. Throws if `_from` is
    /// not the current owner. Throws if `_to` is the zero address. Throws if
    /// `_tokenId` is not a valid NFT.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Change or reaffirm the approved address for an NFT
    /// @dev The zero address indicates there is no approved address.
    /// Throws unless `msg.sender` is the current NFT owner, or an authorized
    /// operator of the current owner.
    /// @param _approved The new approved NFT controller
    /// @param _tokenId The NFT to approve
    function approve(address _approved, uint256 _tokenId) external payable;

    /// @notice Enable or disable approval for a third party ("operator") to manage
    /// all of `msg.sender`'s assets
    /// @dev Emits the ApprovalForAll event. The contract MUST allow
    /// multiple operators per owner.
    /// @param _operator Address to add to the set of authorized operators
    /// @param _approved True if the operator is approved, false to revoke approval
    function setApprovalForAll(address _operator, bool _approved) external;

    /// @notice Get the approved address for a single NFT
    /// @dev Throws if `_tokenId` is not a valid NFT.
    /// @param _tokenId The NFT to find the approved address for
    /// @return The approved address for this NFT, or the zero address if there is none
    function getApproved(uint256 _tokenId) external view returns (address);

    /// @notice Query if an address is an authorized operator for another address
    /// @param _owner The address that owns the NFTs
    /// @param _operator The address that acts on behalf of the owner
    /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721TokenReceiver {
    /// @notice Handle the receipt of an NFT
    /// @dev The ERC721 smart contract calls this function on the recipient
    /// after a `transfer`. This function MAY throw to revert and reject the
    /// transfer. Return of other than the magic value MUST result in the
    /// transaction being reverted.
    /// Note: the contract address is always the message sender.
    /// @param _operator The address which called `safeTransferFrom` function
    /// @param _from The address which previously owned the token
    /// @param _tokenId The NFT identifier which is being transferred
    /// @param _data Additional data with no specified format
    /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    ///  unless throwing
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data)
        external
        returns (bytes4);
}

/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface IERC721Metadata is IERC721 {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns (string memory _name);

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns (string memory _symbol);

    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    /// 3986. The URI may point to a JSON file that conforms to the "ERC721
    /// Metadata JSON Schema".
    function tokenURI(uint256 _tokenId) external view returns (string memory);
}

/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x780e9d63.
interface IERC721Enumerable is IERC721 {
    /// @notice Count NFTs tracked by this contract
    /// @return A count of valid NFTs tracked by this contract, where each one of
    /// them has an assigned and queryable owner not equal to the zero address
    function totalSupply() external view returns (uint256);

    /// @notice Enumerate valid NFTs
    /// @dev Throws if `_index` >= `totalSupply()`.
    /// @param _index A counter less than `totalSupply()`
    /// @return The token identifier for the `_index`th NFT,
    /// (sort order not specified)
    function tokenByIndex(uint256 _index) external view returns (uint256);

    /// @notice Enumerate NFTs assigned to an owner
    /// @dev Throws if `_index` >= `balanceOf(_owner)` or if
    /// `_owner` is the zero address, representing invalid NFTs.
    /// @param _owner An address where we are interested in NFTs owned by them
    /// @param _index A counter less than `balanceOf(_owner)`
    /// @return The token identifier for the `_index`th NFT assigned to `_owner`,
    /// (sort order not specified)
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

// 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 Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CONSTANTS AND IMMUTABLES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256("EIP712Domain(string name,string version,address verifyingContract)")`.
    /// This is only used in `_hashTypedDataSansChainId`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID =
        0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766;

    /// @dev `keccak256("EIP712Domain(string name,string version)")`.
    /// This is only used in `_hashTypedDataSansChainIdAndVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT =
        0xb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3;

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId)")`.
    /// This is only used in `_hashTypedDataSansVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT =
        0xc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e;

    uint256 private immutable _cachedThis;
    uint256 private immutable _cachedChainId;
    bytes32 private immutable _cachedNameHash;
    bytes32 private immutable _cachedVersionHash;
    bytes32 private immutable _cachedDomainSeparator;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CONSTRUCTOR                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Cache the hashes for cheaper runtime gas costs.
    /// In the case of upgradeable contracts (i.e. proxies),
    /// or if the chain id changes due to a hard fork,
    /// the domain separator will be seamlessly calculated on-the-fly.
    constructor() {
        _cachedThis = uint256(uint160(address(this)));
        _cachedChainId = block.chainid;

        string memory name;
        string memory version;
        if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
        bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
        bytes32 versionHash =
            _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
        _cachedNameHash = nameHash;
        _cachedVersionHash = versionHash;

        bytes32 separator;
        if (!_domainNameAndVersionMayChange()) {
            /// @solidity memory-safe-assembly
            assembly {
                let m := mload(0x40) // Load the free memory pointer.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), versionHash)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                separator := keccak256(m, 0xa0)
            }
        }
        _cachedDomainSeparator = separator;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   FUNCTIONS TO OVERRIDE                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Please override this function to return the domain name and version.
    /// ```
    ///     function _domainNameAndVersion()
    ///         internal
    ///         pure
    ///         virtual
    ///         returns (string memory name, string memory version)
    ///     {
    ///         name = "Solady";
    ///         version = "1";
    ///     }
    /// ```
    ///
    /// Note: If the returned result may change after the contract has been deployed,
    /// you must override `_domainNameAndVersionMayChange()` to return true.
    function _domainNameAndVersion()
        internal
        view
        virtual
        returns (string memory name, string memory version);

    /// @dev Returns if `_domainNameAndVersion()` may change
    /// after the contract has been deployed (i.e. after the constructor).
    /// Default: false.
    function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _domainSeparator() internal view virtual returns (bytes32 separator) {
        if (_domainNameAndVersionMayChange()) {
            separator = _buildDomainSeparator();
        } else {
            separator = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
        }
    }

    /// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
    /// given `structHash`, as defined in
    /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    ///
    /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
    /// ```
    ///     bytes32 digest = _hashTypedData(keccak256(abi.encode(
    ///         keccak256("Mail(address to,string contents)"),
    ///         mailTo,
    ///         keccak256(bytes(mailContents))
    ///     )));
    ///     address signer = ECDSA.recover(digest, signature);
    /// ```
    function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
        // We will use `digest` to store the domain separator to save a bit of gas.
        if (_domainNameAndVersionMayChange()) {
            digest = _buildDomainSeparator();
        } else {
            digest = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the digest.
            mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
            mstore(0x1a, digest) // Store the domain separator.
            mstore(0x3a, structHash) // Store the struct hash.
            digest := keccak256(0x18, 0x42)
            // Restore the part of the free memory slot that was overwritten.
            mstore(0x3a, 0)
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID.
    /// Included for the niche use case of cross-chain workflows.
    function _hashTypedDataSansChainId(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, address())
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of cross-chain and multi-verifier workflows.
    function _hashTypedDataSansChainIdAndVerifyingContract(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x60)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of multi-verifier workflows.
    function _hashTypedDataSansVerifyingContract(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, chainid())
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    EIP-5267 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev See: https://eips.ethereum.org/EIPS/eip-5267
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        fields = hex"0f"; // `0b01111`.
        (name, version) = _domainNameAndVersion();
        chainId = block.chainid;
        verifyingContract = address(this);
        salt = salt; // `bytes32(0)`.
        extensions = extensions; // `new uint256[](0)`.
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _buildDomainSeparator() private view returns (bytes32 separator) {
        // We will use `separator` to store the name hash to save a bit of gas.
        bytes32 versionHash;
        if (_domainNameAndVersionMayChange()) {
            (string memory name, string memory version) = _domainNameAndVersion();
            separator = keccak256(bytes(name));
            versionHash = keccak256(bytes(version));
        } else {
            separator = _cachedNameHash;
            versionHash = _cachedVersionHash;
        }
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), separator) // Name hash.
            mstore(add(m, 0x40), versionHash)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            separator := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns if the cached domain separator has been invalidated.
    function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
        uint256 cachedChainId = _cachedChainId;
        uint256 cachedThis = _cachedThis;
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - The `bytes memory signature` variants use the identity precompile (0x4)
///   to copy memory internally.
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library SignatureCheckerLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               SIGNATURE CHECKING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    switch mload(signature)
                    case 64 {
                        let vs := mload(add(signature, 0x40))
                        mstore(0x20, add(shr(255, vs), 27)) // `v`.
                        mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    }
                    case 65 {
                        mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                        mstore(0x60, mload(add(signature, 0x40))) // `s`.
                    }
                    default { break }
                    mstore(0x00, hash)
                    mstore(0x40, mload(add(signature, 0x20))) // `r`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                // Copy the `signature` over.
                let n := add(0x20, mload(signature))
                let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
                isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
                isValid := and(eq(mload(d), f), and(isValid, copied))
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    switch signature.length
                    case 64 {
                        let vs := calldataload(add(signature.offset, 0x20))
                        mstore(0x20, add(shr(255, vs), 27)) // `v`.
                        mstore(0x40, calldataload(signature.offset)) // `r`.
                        mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    }
                    case 65 {
                        mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                        calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
                    }
                    default { break }
                    mstore(0x00, hash)
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), signature.length)
                // Copy the `signature` over.
                calldatacopy(add(m, 0x64), signature.offset, signature.length)
                isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    mstore(0x00, hash)
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, r) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
                mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
                isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    mstore(0x00, hash)
                    mstore(0x20, and(v, 0xff)) // `v`.
                    mstore(0x40, r) // `r`.
                    mstore(0x60, s) // `s`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), s) // `s`.
                mstore8(add(m, 0xa4), v) // `v`.
                isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     ERC1271 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: These ERC1271 operations do NOT have an ECDSA fallback.

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            // Copy the `signature` over.
            let n := add(0x20, mload(signature))
            let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
            isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
            isValid := and(eq(mload(d), f), and(isValid, copied))
        }
    }

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNowCalldata(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), signature.length)
            // Copy the `signature` over.
            calldatacopy(add(m, 0x64), signature.offset, signature.length)
            isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
            mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
            isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), s) // `s`.
            mstore8(add(m, 0xa4), v) // `v`.
            isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     ERC6492 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: These ERC6492 operations now include an ECDSA fallback at the very end.
    // The calldata variants are excluded for brevity.

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt to
    /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check.
    /// Note: This function is NOT reentrancy safe.
    /// The verifier must be deployed.
    /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
    /// See: https://gist.github.com/Vectorized/011d6becff6e0a73e42fe100f8d7ef04
    /// With a dedicated verifier, this function is safe to use in contracts
    /// that have been granted special permissions.
    function isValidERC6492SignatureNowAllowSideEffects(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
                _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                _isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
            }
            let noCode := iszero(extcodesize(signer))
            let n := mload(signature)
            for {} 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
                    break
                }
                if iszero(noCode) {
                    let o := add(signature, 0x20) // Signature bytes.
                    isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
                    if isValid { break }
                }
                let m := mload(0x40)
                mstore(m, signer)
                mstore(add(m, 0x20), hash)
                pop(
                    call(
                        gas(), // Remaining gas.
                        0x0000bc370E4DC924F427d84e2f4B9Ec81626ba7E, // Non-reverting verifier.
                        0, // Send zero ETH.
                        m, // Start of memory.
                        add(returndatasize(), 0x40), // Length of calldata in memory.
                        staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
                        0x00 // Length of returndata to write.
                    )
                )
                isValid := returndatasize()
                break
            }
            // Do `ecrecover` fallback if `noCode && !isValid`.
            for {} gt(noCode, isValid) {} {
                switch n
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt
    /// to use a reverting verifier to deploy / prepare the `signer` smart account
    /// and do a `isValidSignature` check via the reverting verifier.
    /// Note: This function is reentrancy safe.
    /// The reverting verifier must be deployed.
    /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
    /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad
    function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
                _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                _isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
            }
            let noCode := iszero(extcodesize(signer))
            let n := mload(signature)
            for {} 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
                    break
                }
                if iszero(noCode) {
                    let o := add(signature, 0x20) // Signature bytes.
                    isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
                    if isValid { break }
                }
                let m := mload(0x40)
                mstore(m, signer)
                mstore(add(m, 0x20), hash)
                let willBeZeroIfRevertingVerifierExists :=
                    call(
                        gas(), // Remaining gas.
                        0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier.
                        0, // Send zero ETH.
                        m, // Start of memory.
                        add(returndatasize(), 0x40), // Length of calldata in memory.
                        staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
                        0x00 // Length of returndata to write.
                    )
                isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists)
                break
            }
            // Do `ecrecover` fallback if `noCode && !isValid`.
            for {} gt(noCode, isValid) {} {
                switch n
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {SingleUseETHVault} from "./SingleUseETHVault.sol";

/// @notice Library for force safe transferring ETH and ERC20s in ZKsync.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SafeTransferLib.sol)
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev A single use ETH vault has been created for `to`, with `amount`.
    event SingleUseETHVaultCreated(address indexed to, uint256 amount, address vault);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The ERC20 `totalSupply` query has failed.
    error TotalSupplyQueryFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 1000000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), 0x00, 0x00, 0x00, 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// If force transfer is used, returns the vault. Else returns `address(0)`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (address vault)
    {
        if (amount == uint256(0)) return address(0); // Early return if `amount` is zero.
        uint256 selfBalanceBefore = address(this).balance;
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfBalanceBefore, amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            pop(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00))
        }
        if (address(this).balance == selfBalanceBefore) {
            vault = address(new SingleUseETHVault());
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x00, shr(96, shl(96, to)))
                if iszero(call(gas(), vault, amount, 0x00, 0x20, 0x00, 0x00)) { revert(0x00, 0x00) }
            }
            emit SingleUseETHVaultCreated(to, amount, vault);
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    /// If force transfer is used, returns the vault. Else returns `address(0)`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (address vault)
    {
        vault = forceSafeTransferETH(to, address(this).balance, gasStipend);
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    /// If force transfer is used, returns the vault. Else returns `address(0)`.
    function forceSafeTransferETH(address to, uint256 amount) internal returns (address vault) {
        vault = forceSafeTransferETH(to, amount, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    /// If force transfer is used, returns the vault. Else returns `address(0)`.
    function forceSafeTransferAllETH(address to) internal returns (address vault) {
        vault = forceSafeTransferETH(to, address(this).balance, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), 0x00, 0x00, 0x00, 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x34, 0) // Store 0 for the `amount`.
                    mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                    pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval.
                    mstore(0x34, amount) // Store back the original `amount`.
                    // Retry the approval, reverting upon failure.
                    success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    if iszero(and(eq(mload(0x00), 1), success)) {
                        // Check the `extcodesize` again just in case the token selfdestructs lol.
                        if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                            mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                            revert(0x1c, 0x04)
                        }
                    }
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Returns the total supply of the `token`.
    /// Reverts if the token does not exist or does not implement `totalSupply()`.
    function totalSupply(address token) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x18160ddd) // `totalSupply()`.
            if iszero(
                and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
            ) {
                mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
                revert(0x1c, 0x04)
            }
            result := mload(0x00)
        }
    }
}

File 8 of 10 : Structs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

struct Claim {
    address to;
    uint256 deadline;
    ClaimDetail[] details;
}

struct ClaimDetail {
    bytes32 data;
    uint128 amount;
    uint128 bonusAmount;
}

struct ClaimHistory {
    uint128 amount;
    uint128 bonusAmount;
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    /// uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    /// `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

File 10 of 10 : SingleUseETHVault.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice A single-use vault that allows a designated caller to withdraw all ETH in it.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SingleUseETHVault.sol)
contract SingleUseETHVault {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to withdraw all.
    error WithdrawAllFailed();

    /// @dev Not authorized.
    error Unauthorized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        WITHDRAW ALL                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    fallback() external payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x40, 0) // Optimization trick to remove free memory pointer initialization.
            let owner := sload(0)
            // Initialization.
            if iszero(owner) {
                sstore(0, calldataload(0x00)) // Store the owner.
                return(0x00, 0x00) // Early return.
            }
            // Authorization check.
            if iszero(eq(caller(), owner)) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
            let to := calldataload(0x00)
            // If the calldata is less than 32 bytes, zero-left-pad it to 32 bytes.
            // Then use the rightmost 20 bytes of the word as the `to` address.
            // This allows for the calldata to be `abi.encode(to)` or `abi.encodePacked(to)`.
            to := shr(mul(lt(calldatasize(), 0x20), shl(3, sub(0x20, calldatasize()))), to)
            // If `to` is `address(0)`, set it to `msg.sender`.
            to := xor(mul(xor(to, caller()), iszero(to)), to)
            // Transfers the whole balance to `to`.
            if iszero(call(gas(), to, selfbalance(), 0x00, 0x00, 0x00, 0x00)) {
                mstore(0x00, 0x651aee10) // `WithdrawAllFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

Settings
{
  "viaIR": false,
  "codegen": "yul",
  "remappings": [
    "forge-std-1.9.7/=dependencies/forge-std-1.9.7/",
    "solady-0.1.19/=dependencies/solady-0.1.19/",
    "forge-std/=lib/forge-std/src/",
    "forge-zksync-std/=lib/forge-zksync-std/src/"
  ],
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "abi"
      ]
    }
  },
  "optimizer": {
    "enabled": true,
    "mode": "3",
    "size_fallback": false,
    "disable_system_request_memoization": true
  },
  "metadata": {},
  "libraries": {},
  "enableEraVMExtensions": false,
  "forceEVMLA": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"grind","type":"address"},{"internalType":"address","name":"_signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ClaimNotActive","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"address","name":"bonusWallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"bonusAmount","type":"uint256"}],"name":"BonusClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalClaimed","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"CLAIM_DETAIL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CLAIM_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GRIND","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"data","type":"bytes32"}],"name":"getClaimBonus","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"data","type":"bytes32"}],"name":"getClaimStatus","outputs":[{"internalType":"uint256","name":"amountClaimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"components":[{"internalType":"bytes32","name":"data","type":"bytes32"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"bonusAmount","type":"uint128"}],"internalType":"struct ClaimDetail[]","name":"details","type":"tuple[]"}],"internalType":"struct Claim","name":"claim","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"getGrinding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint96","name":"tokenId","type":"uint96"}],"name":"nftClaimStatus","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_claimEnabled","type":"bool"}],"name":"setClaimEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]

9c4d535b000000000000000000000000000000000000000000000000000000000000000001000273620de76580922d11f3b829e090ce11a7f02ce9dd6e3ac11d7caa82a900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000340f19e6a630b58f892abdd742f3ce04ef4ad77a0000000000000000000000001c26da604221466976beeb509698152ba8a3a13f0000000000000000000000003d1efc86eefc8310c0ab0c9248711fd2c22e0d06

Deployed Bytecode

0x0002000000000002000f000000000002000100000001035500000060031002700000020d0030019d0000020d0330019700000001002001900000002f0000c13d0000008002000039000000400020043f000000040030008c000003a90000413d000000000201043b000000e0022002700000021d0020009c0000007d0000213d0000022c0020009c000000b40000a13d0000022d0020009c000000ee0000213d000002310020009c000002160000613d000002320020009c000001ac0000613d000002330020009c000003a90000c13d0000021901000041000000000501041a0000000001000411000000000051004b0000029e0000c13d00000000010004140000020d0010009c0000020d01008041000000c00110021000000216011001c70000800d0200003900000003030000390000021a040000410000000006000019082f08250000040f0000000100200190000003a90000613d0000021901000041000000000001041b0000000001000019000008300001042e0000014004000039000000400040043f0000000002000416000000000002004b000003a90000c13d0000001f023000390000020e022001970000014002200039000000400020043f0000001f0530018f0000020f063001980000014002600039000000410000613d000000000701034f000000007807043c0000000004840436000000000024004b0000003d0000c13d000000000005004b0000004e0000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000600030008c000003a90000413d000001400200043d000002100020009c000003a90000213d000001600100043d000d00000001001d000002100010009c000003a90000213d000001800100043d000c00000001001d000002100010009c000003a90000213d000b00000002001d0000000001000410000000800010043f0000021101000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d000000000401043b000000a00040043f000000400100043d000002130010009c000000770000213d0000004002100039000000400020043f0000000a02000039000000000221043600000214030000410000000000320435000000400500043d000002130050009c000002a20000a13d0000025201000041000000000010043f0000004101000039000000040010043f000002530100004100000831000104300000021e0020009c000000d40000a13d0000021f0020009c000001060000213d000002230020009c0000021d0000613d000002240020009c000001bd0000613d000002250020009c000003a90000c13d000000440030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000402100370000000000202043b000c00000002001d000002410020009c000003a90000213d0000000c0230006a000002420020009c000003a90000213d000000640020008c000003a90000413d0000002402100370000000000202043b000600000002001d000002410020009c000003a90000213d00000006020000290000002302200039000000000032004b000003a90000813d00000006020000290000000402200039000000000221034f000000000202043b000500000002001d000002410020009c000003a90000213d00000006020000290000002404200039000400000004001d0000000502400029000000000032004b000003a90000213d000000000200041a000300000002001d0000024300200198000003640000c13d0000025f01000041000000000010043f0000025d010000410000083100010430000002340020009c0000011f0000a13d000002350020009c000001830000613d000002360020009c000001690000613d000002370020009c000003a90000c13d0000023a010000410000000c0010043f0000000001000411000000000010043f00000000010004140000020d0010009c0000020d01008041000000c0011002100000023e011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b000000000001041b00000000010004140000020d0010009c0000020d01008041000000c00110021000000216011001c70000800d0200003900000002030000390000026b04000041000001490000013d000002260020009c0000014e0000a13d000002270020009c0000018d0000613d000002280020009c000001700000613d000002290020009c000003a90000c13d000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000000000010043f0000000101000039000000200010043f00000040020000390000000001000019082f07f20000040f000000000101041a0000008001100270000000800010043f0000023b01000041000008300001042e0000022e0020009c0000025f0000613d0000022f0020009c000001ce0000613d000002300020009c000003a90000c13d000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000000000010043f0000000101000039000000200010043f00000040020000390000000001000019082f07f20000040f000000000101041a0000024601100197000000800010043f0000023b01000041000008300001042e000002200020009c0000026f0000613d000002210020009c000002050000613d000002220020009c000003a90000c13d000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000002100010009c000003a90000213d0000023a020000410000000c0020043f000000000010043f0000000c010000390000002002000039082f07f20000040f000000000101041a000000800010043f0000023b01000041000008300001042e000002380020009c000001a10000613d000002390020009c000003a90000c13d0000023a010000410000000c0010043f0000000001000411000000000010043f0000023f01000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d000000000101043b000d00000001001d00000000010004140000020d0010009c0000020d01008041000000c0011002100000023e011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b0000000d020000290000026c0220009a000000000021041b00000000010004140000020d0010009c0000020d01008041000000c00110021000000216011001c70000800d0200003900000002030000390000026d040000410000000005000411082f08250000040f0000000100200190000003290000c13d000003a90000013d0000022a0020009c000001a60000613d0000022b0020009c000003a90000c13d000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000201043b000000000002004b0000000001000039000000010100c039000d00000002001d000000000012004b000003a90000c13d082f07820000040f0000000d0000006b0000000001000019000002630100c041000000000200041a0000026402200197000000000112019f000000000010041b0000000001000019000008300001042e0000000001000416000000000001004b000003a90000c13d0000024701000041000000800010043f0000023b01000041000008300001042e000000440030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000d00000001001d000002100010009c000003a90000213d082f07820000040f00000024010000390000000101100367000000000301043b00000000020004110000000d01000029082f07a20000040f0000000001000019000008300001042e0000000001000416000000000001004b000003a90000c13d000000000100041a00000243001001980000000001000039000000010100c039000000800010043f0000023b01000041000008300001042e000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000021902000041000000000402041a0000000002000411000000000042004b0000029e0000c13d0000000401100370000000000301043b00000000010004140000020d0010009c0000020d01008041000000c001100210000000000003004b000003230000c13d0000000002040019000003260000013d0000000001000416000000000001004b000003a90000c13d000000000100041a000001ca0000013d0000000001000416000000000001004b000003a90000c13d0000021901000041000000000101041a000001ca0000013d000000240030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000d00000001001d000002100010009c000003a90000213d082f07820000040f000000000100041a0000021b011001970000000d011001af000000000010041b0000000001000019000008300001042e0000000001000416000000000001004b000003a90000c13d0000000001000412000f00000001001d000e00a00000003d0000800501000039000000440300003900000000040004150000000f0440008a00000005044002100000024a02000041082f08070000040f0000021001100197000000800010043f0000023b01000041000008300001042e0000000001000416000000000001004b000003a90000c13d0000000a01000039000000800010043f0000021402000041000000a00020043f0000010002000039000000400020043f0000000102000039000000c00020043f0000021503000041000000e00030043f0000026503000041000001000030043f000000e003000039000001200030043f000001e00010043f000002000100043d000002660110019700000214011001c7000002000010043f0000020a0000043f0000012001000039000001400010043f000002200020043f000002400100043d000002670110019700000215011001c7000002400010043f000002410000043f0000021101000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d000000000101043b000001600010043f0000000001000410000001800010043f000001a00000043f0000016001000039000001c00010043f000000600100043d000002600010043f000000000001004b0000032f0000c13d0000018001000039000003390000013d000000240030008c000003a90000413d0000000401100370000000000101043b000002100010009c000003a90000213d0000021902000041000000000202041a0000000003000411000000000023004b0000029e0000c13d000000000001004b000003410000c13d0000023c01000041000000000010043f0000023d0100004100000831000104300000000001000416000000000001004b000003a90000c13d0000024901000041000000800010043f0000023b01000041000008300001042e000000440030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000401100370000000000101043b000d00000001001d000002100010009c000003a90000213d0000021901000041000000000201041a0000000001000411000000000021004b0000029e0000c13d000c00000002001d0000024e0100004100000000001004430000000d01000029000000040010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024f011001c70000800202000039082f082a0000040f0000000100200190000007650000613d000000000101043b000000000001004b000003a90000613d000000400300043d00000024013000390000000c0200002900000000002104350000026001000041000000000013043500000004013000390000000002000410000000000021043500000024010000390000000101100367000000000101043b000000440230003900000000001204350000020d0030009c000c00000003001d0000020d010000410000000001034019000000400110021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000261011001c70000000d02000029082f08250000040f0000000100200190000003440000613d0000000c010000290000000002000019082f07700000040f0000000001000019000008300001042e000000440030008c000003a90000413d0000000002000416000000000002004b000003a90000c13d0000000402100370000000000202043b000002100020009c000003a90000213d0000002401100370000000000101043b000002690010009c000003a90000213d0000006002200210000000000121019f000000fb0000013d000000240030008c000003a90000413d0000000401100370000000000101043b000d00000001001d000002100010009c000003a90000213d0000021901000041000000000101041a0000000002000411000000000012004b0000029e0000c13d0000023a010000410000000c0010043f0000000d01000029000000000010043f00000000010004140000020d0010009c0000020d01008041000000c0011002100000023e011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b000b00000001001d000000000101041a000c00000001001d0000023f01000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d000000000101043b0000000c0010006c0000033e0000a13d0000024001000041000000000010043f0000023d0100004100000831000104300000026a01000041000000000010043f0000023d010000410000083100010430000800000004001d0000004003500039000000400030043f0000000103000039000a00000005001d00000000043504360000021503000041000900000004001d00000000003404350000020d0020009c0000020d02008041000000400220021000000000010104330000020d0010009c0000020d010080410000006001100210000000000121019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000216011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d00000009020000290000020d0020009c0000020d0200804100000040022002100000000a0300002900000000030304330000020d0030009c0000020d030080410000006003300210000000000223019f000000000101043b000a00000001001d00000000010004140000020d0010009c0000020d01008041000000c001100210000000000121019f00000216011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b0000000a05000029000000c00050043f000000e00010043f000000400200043d0000008003200039000000000400041000000000004304350000006003200039000000080400002900000000004304350000004003200039000000000013043500000020012000390000000000510435000002170100004100000000001204350000020d0020009c0000020d02008041000000400120021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000121019f00000218011001c70000801002000039082f082a0000040f0000000b060000290000000100200190000003a90000613d000000000101043b000001000010043f0000021901000041000000000061041b00000000010004140000020d0010009c0000020d01008041000000c00110021000000216011001c70000800d0200003900000003030000390000021a040000410000000005000019082f08250000040f0000000100200190000003a90000613d0000000d04000029000001200040043f000000000100041a0000021b011001970000000c011001af000000000010041b000000800100043d000001400000044300000160001004430000002001000039000000a00200043d0000018000100443000001a0002004430000004002000039000000c00300043d000001c000200443000001e0003004430000006002000039000000e00300043d000002000020044300000220003004430000008002000039000001000300043d00000240002004430000026000300443000000a0020000390000028000200443000002a0004004430000010000100443000000060100003900000120001004430000021c01000041000008300001042e00000216011001c700008009020000390000000005000019082f08250000040f00000001002001900000032b0000613d0000000001000019000008300001042e0000026201000041000000000010043f0000023d0100004100000831000104300000028003000039000000000200001900000080050000390000000004030019000000005305043400000000033404360000000102200039000000000012004b000003320000413d000000e00140008a0000020d0010009c0000020d01008041000000600110021000000268011001c7000008300001042e0000000b01000029000000000001041b0000000d01000029082f078c0000040f0000000001000019000008300001042e00000060061002700000001f0460018f0000020f05600198000000400200043d0000000003520019000003500000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b0000034c0000c13d0000020d06600197000000000004004b0000035e0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000060016002100000020d0020009c0000020d020080410000004002200210000000000112019f00000831000104300000000c02000029000d00240020003d0000000d01100360000000000101043b000200000001001d0000023f01000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d000000000101043b000000020010006c0000037b0000a13d0000025e01000041000000000010043f0000025d0100004100000831000104300000000d01000029000100200010003d00000001010003670000000102100360000000000302043b00000000020000310000000c0420006a000000230440008a00000244054001970000024406300197000000000756013f000000000056004b00000000050000190000024405004041000000000043004b00000000040000190000024404008041000002440070009c000000000504c019000000000005004b000003a90000c13d0000000c04000029000a00040040003d0000000a03300029000000000431034f000000000404043b000b00000004001d000002410040009c000003a90000213d000000600400008a0000000b044000b900000000042400190000002003300039000000000043004b0000000005000019000002440500204100000244044001970000024403300197000000000643013f000000000043004b00000000030000190000024403004041000002440060009c000000000305c019000000000003004b000003ab0000613d000000000100001900000831000104300000000b0300002900000005033002100000003f043000390000024504400197000000400500043d0000000004450019000900000005001d000000000054004b00000000050000390000000105004039000002410040009c000000770000213d0000000100500190000000770000c13d000000400040043f0000000b0400002900000009050000290000000004450436000800000004001d0000001f0430018f000000000003004b000003c80000613d000000000221034f00000008050000290000000003350019000000002602043c0000000005650436000000000035004b000003c40000c13d000000000004004b0000000c02000029000700440020003d0000000b0000006b000004890000c13d0000000102000029000000400220008a000000000121034f000000000101043b000d00000001001d000002100010009c000003a90000213d000000400100043d000000200210003900000009030000290000000003030433000000000003004b00000000040200190000000807000029000003e30000613d00000000050000190000000004020019000000007607043400000000046404360000000105500039000000000035004b000003de0000413d0000000003140049000000200430008a00000000004104350000001f033000390000026e043001970000000003140019000000000043004b00000000040000390000000104004039000002410030009c000000770000213d0000000100400190000000770000c13d000000400030043f0000020d0020009c0000020d02008041000000400220021000000000010104330000020d0010009c0000020d010080410000006001100210000000000121019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000216011001c70000801002000039082f082a0000040f00000001002001900000008004000039000003a90000613d000000000201043b000000400100043d000000800310003900000000002304350000006002100039000000020300002900000000003204350000000d020000290000021002200197000000400310003900000000002304350000002002100039000002490300004100000000003204350000000000410435000002480010009c000000770000213d000000a003100039000000400030043f0000020d0020009c0000020d02008041000000400220021000000000010104330000020d0010009c0000020d010080410000006001100210000000000121019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000216011001c70000801002000039082f082a0000040f00000001002001900000008002000039000003a90000613d000000000101043b000d00000001001d0000024a01000041000000000010044300000000010004120000000400100443000000240020044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000101043b000b00000001001d0000024a01000041000000000010044300000000010004120000000400100443000000240000044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000101043b000900000001001d0000024a010000410000000000100443000000000100041200000004001004430000002001000039000000240010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000101043b000800000001001d0000021101000041000000000010044300000000010004140000020d0010009c0000020d01008041000000c00110021000000212011001c70000800b02000039082f082a0000040f0000000100200190000007650000613d0000000002000410000000000101043b000200000001001d000000090020006c000004f40000c13d0000000802000029000000020020006b000004f40000c13d0000024c01000041000000000010043f0000000b010000290000001a0010043f0000000d010000290000003a0010043f00000000010004140000020d0010009c0000020d01008041000000c0011002100000024d011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b000b00000001001d0000003a0000043f0000000301000029000d02100010019c000005340000c13d0000025c01000041000000000010043f0000025d0100004100000831000104300000000008000019000000800700003900000000010000310000000c0210006a000000230320008a00000007020000290000000102200367000000000202043b00000244043001970000024405200197000000000645013f000000000045004b00000000040000190000024404004041000000000032004b00000000030000190000024403008041000002440060009c000000000403c019000000000004004b000003a90000c13d0000000a032000290000000102300367000000000202043b000002410020009c000003a90000213d0000026f042000d10000000004140019000000200130003900000244034001970000024405100197000000000635013f000000000035004b00000000030000190000024403004041000000000041004b00000000040000190000024404002041000002440060009c000000000304c019000000000003004b000003a90000c13d000000000028004b000006fe0000813d00000060028000c9000000000421001900000020014000390000000102100367000000000202043b000002460020009c000003a90000213d00000020011000390000000101100367000000000501043b000002460050009c000003a90000213d000d00000008001d000000400100043d0000002003100039000002470600004100000000006304350000000104400367000000000404043b0000008006100039000000000056043500000060051000390000000000250435000000400210003900000000004204350000000000710435000002480010009c000000770000213d000000a002100039000000400020043f0000020d0030009c0000020d03008041000000400230021000000000010104330000020d0010009c0000020d010080410000006001100210000000000121019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000216011001c70000801002000039082f082a0000040f000000010020019000000080070000390000000d08000029000003a90000613d00000009020000290000000002020433000000000028004b000006fe0000813d00000005028002100000000802200029000000000101043b000000000012043500000001088000390000000b0080006c0000048b0000413d0000000101000367000003cd0000013d000000400200043d0000021701000041000900000002001d0000000001120436000b00000001001d0000024a010000410000000000100443000000000100041200000004001004430000004001000039000000240010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000101043b0000000b0200002900000000001204350000024a010000410000000000100443000000000100041200000004001004430000006001000039000000240010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000101043b0000000904000029000000800240003900000000030004100000000000320435000000600240003900000002030000290000000000320435000000400240003900000000001204350000020d0040009c0000020d04008041000000400140021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000121019f00000218011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b000b00000001001d000004700000013d000000400100043d000900000001001d0000024e0100004100000000001004430000000d01000029000000040010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024f011001c70000800202000039082f082a0000040f0000000100200190000007650000613d000000000101043b000000000001004b0000055a0000c13d0000000501000029000000400010008c000005b50000613d0000000501000029000000410010008c000004850000c13d000000060100002900000064011000390000000101100367000000000101043b000000f801100270000000200010043f000000040100002900000001011003670000004002000039000000001301043c0000000002320436000000800020008c000005550000c13d000005c20000013d00000009050000290000006402500039000000440150003900000024065000390000000403500039000002500400004100000000004504350000000b0400002900000000004304350000004003000039000b00000006001d0000000000360435000000050400002900000000004104350000026e034001980000001f0440018f000000000132001900000004050000290000000105500367000005730000613d000000000605034f000000006706043c0000000002720436000000000012004b0000056f0000c13d000000000004004b000005800000613d000000000235034f0000000303400210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f000000000021043500000009010000290000020d0010009c0000020d010080410000004001100210000000050200002900000064022000390000020d0020009c0000020d020080410000006002200210000000000121019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f0000000d02000029082f082a0000040f00000060031002700000020d03300197000000200030008c00000020030080390000001f0430018f00000020053001900000000b035000290000059f0000613d000000000601034f0000000b07000029000000006806043c0000000007870436000000000037004b0000059b0000c13d000000000004004b000005ac0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000b010000290000000001010433000002500010009c00000000010000390000000101006039000000000112016f0000000100100190000004850000613d000005f20000013d000000060100002900000044011000390000000101100367000000000101043b000000ff031002700000001b03300039000000200030043f00000004030000290000000102300367000000000202043b000000400020043f0000024201100197000000600010043f0000000b01000029000000000010043f00000000010004140000020d0010009c0000020d01008041000000c00110021000000251011001c70000000102000039000d00000002001d082f082a0000040f00000060031002700000020d03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf000005dc0000613d000000000701034f000000007807043c0000000d090000290000000009890436000d00000009001d000000000049004b000005d60000c13d000000010220018f000000000005004b000005ea0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000000001020433000000600000043f0000000902000029000000400020043f000000030110014f0000006001100210000000000013004b000004850000a13d00000001010003670000000702100360000000000302043b00000000020000310000000c0420006a000000230440008a00000244054001970000024406300197000000000756013f000000000056004b00000000050000190000024405004041000000000043004b00000000040000190000024404008041000002440070009c000000000504c019000000000005004b000003a90000c13d0000000a03300029000000000431034f000000000404043b000300000004001d000002410040009c000003a90000213d000000600400008a00000003044000b900000000022400190000002003300039000000000023004b0000000004000019000002440400204100000244022001970000024403300197000000000523013f000000000023004b00000000020000190000024402004041000002440050009c000000000204c019000000000002004b000003a90000c13d000000030000006b000003290000613d00000007020000290002004000200092000d00000000001d000500000000001d000006280000013d0000000d030000290000000103300039000d00000003001d000000030030006c000007040000813d0000000702100360000000000302043b00000000020000310000000c0420006a000000230440008a00000244054001970000024406300197000000000756013f000000000056004b00000000050000190000024405004041000000000043004b00000000040000190000024404008041000002440070009c000000000504c019000000000005004b000003a90000c13d0000000a04300029000000000341034f000000000303043b000002410030009c000003a90000213d0000026f053000d10000000005250019000000200240003900000244045001970000024406200197000000000746013f000000000046004b00000000040000190000024404004041000000000052004b00000000050000190000024405002041000002440070009c000000000405c019000000000004004b000003a90000c13d0000000d0030006b000006fe0000813d0000000d0300002900000060033000c9000900000032001d0000000901100360000000000101043b000600000001001d000000000010043f0000000101000039000000200010043f00000000010004140000020d0010009c0000020d01008041000000c00110021000000254011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000400200043d000b00000002001d000002130020009c000000770000213d000000000101043b0000000b040000290000004002400039000000400020043f000000000101041a00000020034000390000008002100270000400000003001d0000000000230435000002460210019700000000002404350000000901000029000800200010003d00000001010003670000000803100360000000000303043b000900000003001d000002460030009c000003a90000213d000000090020006b000006b90000a13d0000000601000029000000000010043f0000000101000039000000200010043f00000000010004140000020d0010009c0000020d01008041000000c00110021000000254011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d000000000101043b000000000201041a000002550220019700000009022001af000000000021041b00000001020003670000000801200360000000000101043b000002460010009c000003a90000213d0000000b03000029000000000303043300000246033001970000000003310049000b00000003001d000002460030009c000007660000213d0000000b04000029000000050040002a000007660000413d0000000202200360000000000602043b000002100060009c000003a90000213d000000400200043d000000200320003900000000001304350000000b0100002900000000001204350000020d0020009c0000020d02008041000000400120021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000254011001c70000800d02000039000000030300003900000256040000410000000605000029082f08250000040f0000000100200190000003a90000613d0000000b02000029000500050020002d00000001010003670000000802000029000900200020003d0000000902100360000000000202043b000b00000002001d000002460020009c000003a90000213d0000000b0000006b000006230000613d000000040200002900000000020204330000024600200198000006230000c13d0000000601000029000000000010043f0000000101000039000000200010043f00000000010004140000020d0010009c0000020d01008041000000c00110021000000254011001c70000801002000039082f082a0000040f0000000100200190000003a90000613d0000000b020000290000008002200210000000000101043b000000000301041a0000024603300197000000000223019f000000000021041b00000001010003670000000902100360000000000202043b000b00000002001d000002460020009c000003a90000213d0000000b03000029000000050030002a000007660000413d0000000a01100360000000000601043b000002100060009c000003a90000213d000000400100043d0000000b0200002900000000002104350000020d0010009c0000020d01008041000000400110021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000257011001c70000800d02000039000000030300003900000258040000410000000605000029082f08250000040f0000000100200190000003a90000613d0000000b02000029000500050020002d0000000101000367000006230000013d0000025201000041000000000010043f0000003201000039000000040010043f00000253010000410000083100010430000000050000006b000003290000613d0000000a01100360000000000101043b000d00000001001d000002100010009c000003a90000213d0000024a01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024b011001c70000800502000039082f082a0000040f0000000100200190000007650000613d000000000201043b0000000d01000029000000140010043f0000000501000029000000340010043f0000025901000041000000000010043f00000000010004140000020d0010009c0000020d01008041000000c0011002100000025a011001c7000b00000002001d082f08250000040f000d00000002001d00000060021002700000020d02200197000000200020008c000c00000002001d00000020020080390000001f0320018f0000002002200190000007370000613d000000000401034f0000000005000019000000004604043c0000000005650436000000000025004b000007330000c13d000000000003004b000007440000613d000000000121034f0000000303300210000000000402043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000000000100043d000000010010008c000000000100003900000001010060390000000d0110017f0000000100100190000007620000c13d0000024e0100004100000000001004430000000b01000029000000040010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024f011001c70000800202000039082f082a0000040f0000000100200190000007650000613d000000000101043b000000000001004b000000000100003900000001010060390000000c001001b0000000000100003900000001010060390000000d0110017f00000001001001900000076c0000613d000000340000043f0000000001000019000008300001042e000000000001042f0000025201000041000000000010043f0000001101000039000000040010043f000002530100004100000831000104300000025b01000041000000000010043f0000023d0100004100000831000104300000001f022000390000026e022001970000000001120019000000000021004b00000000020000390000000102004039000002410010009c0000077c0000213d00000001002001900000077c0000c13d000000400010043f000000000001042d0000025201000041000000000010043f0000004101000039000000040010043f000002530100004100000831000104300000021901000041000000000101041a0000000002000411000000000012004b000007880000c13d000000000001042d0000026a01000041000000000010043f0000023d01000041000008310001043000010000000000020000021902000041000000000502041a000000000200041400000210061001970000020d0020009c0000020d02008041000000c00120021000000216011001c70000800d0200003900000003030000390000021a04000041000100000006001d082f08250000040f0000000100200190000007a00000613d00000219010000410000000102000029000000000021041b000000000001042d000000000100001900000831000104300003000000000002000300000001001d000000140020043f000000340030043f0000025901000041000000000010043f00000000010004140000020d0010009c0000020d01008041000000c0011002100000025a011001c70000000302000029082f08250000040f00000060031002700000020d07300197000000200070008c000000200400003900000000040740190000001f0340018f0000002008400190000007bd0000613d000000000401034f0000000005000019000000004604043c0000000005650436000000000085004b000007b90000c13d000000000003004b000007ca0000613d000000000181034f0000000303300210000000000408043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000180435000000000100043d000000010010008c00000000010000390000000101006039000000000112016f0000000100100190000007ea0000c13d000100000002001d000200000007001d0000024e0100004100000000001004430000000301000029000000040010044300000000010004140000020d0010009c0000020d01008041000000c0011002100000024f011001c70000800202000039082f082a0000040f0000000100200190000007ec0000613d000000010200008a000000010220014f000000000101043b000000000001004b0000000001000039000000010100603900000002001001b0000000010220c1bf0000000100200190000007ed0000c13d000000340000043f000000000001042d000000000001042f0000025b01000041000000000010043f0000023d010000410000083100010430000000000001042f0000020d0010009c0000020d0100804100000040011002100000020d0020009c0000020d020080410000006002200210000000000112019f00000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000216011001c70000801002000039082f082a0000040f0000000100200190000008050000613d000000000101043b000000000001042d0000000001000019000008310001043000000000050100190000000000200443000000050030008c000008150000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b0000080d0000413d0000020d0030009c0000020d03008041000000600130021000000000020004140000020d0020009c0000020d02008041000000c002200210000000000112019f00000270011001c70000000002050019082f082a0000040f0000000100200190000008240000613d000000000101043b000000000001042d000000000001042f00000828002104210000000102000039000000000001042d0000000002000019000000000001042d0000082d002104230000000102000039000000000001042d0000000002000019000000000001042d0000082f00000432000008300001042e00000831000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf4772696e64436c61696d00000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f02000000000000000000000000000000000000a0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ffffffffffffffffffffffff000000000000000000000000000000000000000000000002000000000000000000000000000001c0000001000000000000000000000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000d798183300000000000000000000000000000000000000000000000000000000f04e283d00000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000d798183400000000000000000000000000000000000000000000000000000000e03b142e00000000000000000000000000000000000000000000000000000000e85c7d66000000000000000000000000000000000000000000000000000000009e252eff000000000000000000000000000000000000000000000000000000009e252f0000000000000000000000000000000000000000000000000000000000a1db978200000000000000000000000000000000000000000000000000000000c56cd75a000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000092929a09000000000000000000000000000000000000000000000000000000006b0509b00000000000000000000000000000000000000000000000000000000083782df90000000000000000000000000000000000000000000000000000000083782dfa0000000000000000000000000000000000000000000000000000000084b0196e00000000000000000000000000000000000000000000000000000000896a6715000000000000000000000000000000000000000000000000000000006b0509b1000000000000000000000000000000000000000000000000000000006c19e78300000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000002866ed20000000000000000000000000000000000000000000000000000000002866ed2100000000000000000000000000000000000000000000000000000000286c11310000000000000000000000000000000000000000000000000000000054d1f13d00000000000000000000000000000000000000000000000000000000238ac933000000000000000000000000000000000000000000000000000000002569296200000000000000000000000000000000000000000000000000000000389a75e10000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c000000000000000002000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132000000000000000000000000000000000000000000000000000000006f5e8818000000000000000000000000000000000000000000000000ffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000ff000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000fffffffffffffffffffffffffffffffff55fe0ef9f358856b02b37b358f1a53c005c7cf185ed8ee7a0c12b7009b67f6e000000000000000000000000000000000000000000000000ffffffffffffff5f6fd89efe05b5144175efc9d1dd8dc36b20ec07b7084630f79b26a4425c7f17d0310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e0200000200000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000000000000190100000000000002000000000000000000000000000000000000420000001800000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000200000000000000000000000000000000000040000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000000000002500ada8ba581126c805692756f230258621bbe372c90d928a7284fab4a9c1ea020000000000000000000000000000000000002000000000000000000000000096f716c4697b77fc4841e9d28b7fdc9950d2c3f86a436449e0b6fe28977eb8cf00000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000000000440000001000000000000000000000000000000000000000000000000000000000000000000000000090b8ec188baa579f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000819bdcd0000000000000000000000000000000000000000000000000000000024fbaa900000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000b12d13eb0000000000000000000000010000000000000000000000000000000000000000ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff0f0000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000082b42900fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576aa792c370f9c78cfc1c5a13325e141cc1e2c4385ef60ebfd701dcaa215df7

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000340f19e6a630b58f892abdd742f3ce04ef4ad77a0000000000000000000000001c26da604221466976beeb509698152ba8a3a13f0000000000000000000000003d1efc86eefc8310c0ab0c9248711fd2c22e0d06

-----Decoded View---------------
Arg [0] : owner (address): 0x340f19E6A630B58F892aBdd742f3cE04Ef4aD77a
Arg [1] : grind (address): 0x1C26DA604221466976bEeB509698152bA8A3A13F
Arg [2] : _signer (address): 0x3d1eFc86Eefc8310c0ab0C9248711FD2C22E0d06

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000340f19e6a630b58f892abdd742f3ce04ef4ad77a
Arg [1] : 0000000000000000000000001c26da604221466976beeb509698152ba8a3a13f
Arg [2] : 0000000000000000000000003d1efc86eefc8310c0ab0c9248711fd2c22e0d06


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.