Abstract Testnet

Contract

0xfEeEAbcC276c859bEf17c07563334668F883d769

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

6 Internal Transactions found.

Latest 6 internal transactions

Parent Transaction Hash Block From To
67802622025-02-20 9:15:3547 days ago1740042935
0xfEeEAbcC...8F883d769
0 ETH
67802622025-02-20 9:15:3547 days ago1740042935
0xfEeEAbcC...8F883d769
0 ETH
67802622025-02-20 9:15:3547 days ago1740042935
0xfEeEAbcC...8F883d769
0 ETH
67802622025-02-20 9:15:3547 days ago1740042935
0xfEeEAbcC...8F883d769
0 ETH
67802622025-02-20 9:15:3547 days ago1740042935
0xfEeEAbcC...8F883d769
0 ETH
67802622025-02-20 9:15:3547 days ago1740042935  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
KhugaBash

Compiler Version
v0.8.28+commit.7893614a

ZkSolc Version
v1.5.11

Optimization Enabled:
Yes with Mode 3

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : KhugaBash.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "solady/utils/Initializable.sol";
import "solady/auth/Ownable.sol";
import "solady/utils/ReentrancyGuard.sol";
import "solady/utils/UUPSUpgradeable.sol";
import "solady/utils/SignatureCheckerLib.sol";
import "solady/utils/EIP712.sol";

/**
 * @title KhugaBash
 * @dev Main contract for the Khuga Bash game, implementing score system, stat upgrades, and leaderboard
 * @notice This is the zkSync version of the contract, optimized for L2 execution and upgradeable
 */
contract KhugaBash is
    Initializable,
    Ownable,
    ReentrancyGuard,
    UUPSUpgradeable,
    EIP712
{
    // Structs
    struct Player {
        uint256 score;
        bool isRegistered;
    }

    struct LeaderboardEntry {
        address player;
        uint256 score;
    }

    // State variables
    mapping(address => Player) private players;
    mapping(address => uint256) private playerNonce;
    address public backendSigner;
    address[] private playerAddresses;
    uint256 private constant MAX_LEADERBOARD_SIZE = 100;
    uint256 private constant SCORE_PER_GAME = 10;
    bytes32 private constant SCORE_UPDATED_TYPE_HASH =
        keccak256("ScoreUpdated(uint256 score,uint256 nonce)");

    // Events
    event PlayerRegistered(address indexed player, uint256 nonce);
    event ScoreEarned(address indexed player, uint256 score);
    event ScoreUpdated(uint256 score, uint256 nonce);
    event LeaderboardUpdated(address indexed player, uint256 score);
    event Debug(bytes32 messageHash, address signer, bytes signature);

    error PlayerAlreadyRegistered();
    error InvalidSignature();
    error InvalidNonce();
    error PlayerNotRegistered();

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize() public initializer {
        _initializeOwner(msg.sender);
    }

    // Player Registration
    function registerPlayer(uint256 nonce) external {
        require(!players[msg.sender].isRegistered, PlayerAlreadyRegistered());

        players[msg.sender] = Player({score: 0, isRegistered: true});

        playerNonce[msg.sender] = nonce;
        playerAddresses.push(msg.sender);
        emit PlayerRegistered(msg.sender, nonce);
    }

    // Game score System
    function awardScore(address player, uint256 multiplier) external onlyOwner {
        require(players[player].isRegistered, PlayerNotRegistered());

        uint256 scoreToAward = SCORE_PER_GAME * multiplier;
        players[player].score += scoreToAward;

        emit ScoreEarned(player, scoreToAward);
        emit LeaderboardUpdated(player, players[player].score);
    }

    function updateScore(
        uint256 score,
        uint256 nonce,
        bytes calldata signature
    ) external {
        require(nonce == playerNonce[msg.sender] + 1, InvalidNonce());

        bytes32 messageHash = _hashTypedData(
            keccak256(abi.encode(SCORE_UPDATED_TYPE_HASH, score, nonce))
        );

        if (
            !SignatureCheckerLib.isValidSignatureNowCalldata(
                backendSigner,
                messageHash,
                signature
            )
        ) {
            revert InvalidSignature();
        }

        players[msg.sender].score += score;
        playerNonce[msg.sender]++;

        emit ScoreUpdated(score, nonce);
    }

    // Leaderboard Functions
    function getTopPlayers(
        uint256 limit
    ) external view returns (LeaderboardEntry[] memory) {
        uint256 size = playerAddresses.length;
        uint256 resultSize = size < limit ? size : limit;
        resultSize = resultSize < MAX_LEADERBOARD_SIZE
            ? resultSize
            : MAX_LEADERBOARD_SIZE;

        LeaderboardEntry[] memory topPlayers = new LeaderboardEntry[](
            resultSize
        );

        // Create initial array
        for (uint256 i = 0; i < resultSize; i++) {
            topPlayers[i] = LeaderboardEntry({
                player: playerAddresses[i],
                score: players[playerAddresses[i]].score
            });
        }

        // Simple bubble sort (can be optimized for production)
        for (uint256 i = 0; i < resultSize - 1; i++) {
            for (uint256 j = 0; j < resultSize - i - 1; j++) {
                if (topPlayers[j].score < topPlayers[j + 1].score) {
                    LeaderboardEntry memory temp = topPlayers[j];
                    topPlayers[j] = topPlayers[j + 1];
                    topPlayers[j + 1] = temp;
                }
            }
        }

        return topPlayers;
    }

    // Player Stats
    function getPlayerStats(
        address player
    ) external view returns (Player memory) {
        require(players[player].isRegistered, PlayerNotRegistered());
        return players[player];
    }

    // Admin Functions
    function setBackendSigner(address _backendSigner) external onlyOwner {
        backendSigner = _backendSigner;
    }

    function setPlayerNonce(address player, uint256 nonce) external onlyOwner {
        playerNonce[player] = nonce;
    }

    // Required override for UUPS proxy pattern
    function _authorizeUpgrade(
        address newImplementation
    ) internal override onlyOwner {}

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

File 2 of 8 : Initializable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Initializable mixin for the upgradeable contracts.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol)
abstract contract Initializable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The contract is already initialized.
    error InvalidInitialization();

    /// @dev The contract is not initializing.
    error NotInitializing();

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

    /// @dev Triggered when the contract has been initialized.
    event Initialized(uint64 version);

    /// @dev `keccak256(bytes("Initialized(uint64)"))`.
    bytes32 private constant _INTIALIZED_EVENT_SIGNATURE =
        0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2;

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

    /// @dev The default initializable slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_INITIALIZABLE_SLOT")))))`.
    ///
    /// Bits Layout:
    /// - [0]     `initializing`
    /// - [1..64] `initializedVersion`
    bytes32 private constant _INITIALIZABLE_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132;

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

    constructor() {
        // Construction time check to ensure that `_initializableSlot()` is not
        // overridden to zero. Will be optimized away if there is no revert.
        require(_initializableSlot() != bytes32(0));
    }

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

    /// @dev Override to return a non-zero custom storage slot if required.
    function _initializableSlot() internal pure virtual returns (bytes32) {
        return _INITIALIZABLE_SLOT;
    }

    /// @dev Guards an initializer function so that it can be invoked at most once.
    ///
    /// You can guard a function with `onlyInitializing` such that it can be called
    /// through a function guarded with `initializer`.
    ///
    /// This is similar to `reinitializer(1)`, except that in the context of a constructor,
    /// an `initializer` guarded function can be invoked multiple times.
    /// This can be useful during testing and is not expected to be used in production.
    ///
    /// Emits an {Initialized} event.
    modifier initializer() virtual {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            let i := sload(s)
            // Set `initializing` to 1, `initializedVersion` to 1.
            sstore(s, 3)
            // If `!(initializing == 0 && initializedVersion == 0)`.
            if i {
                // If `!(address(this).code.length == 0 && initializedVersion == 1)`.
                if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) {
                    mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
                    revert(0x1c, 0x04)
                }
                s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`.
            }
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            if s {
                // Set `initializing` to 0, `initializedVersion` to 1.
                sstore(s, 2)
                // Emit the {Initialized} event.
                mstore(0x20, 1)
                log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
            }
        }
    }

    /// @dev Guards an reinitialzer function so that it can be invoked at most once.
    ///
    /// You can guard a function with `onlyInitializing` such that it can be called
    /// through a function guarded with `reinitializer`.
    ///
    /// Emits an {Initialized} event.
    modifier reinitializer(uint64 version) virtual {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            // Clean upper bits, and shift left by 1 to make space for the initializing bit.
            version := shl(1, and(version, 0xffffffffffffffff))
            let i := sload(s)
            // If `initializing == 1 || initializedVersion >= version`.
            if iszero(lt(and(i, 1), lt(i, version))) {
                mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
                revert(0x1c, 0x04)
            }
            // Set `initializing` to 1, `initializedVersion` to `version`.
            sstore(s, or(1, version))
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            // Set `initializing` to 0, `initializedVersion` to `version`.
            sstore(s, version)
            // Emit the {Initialized} event.
            mstore(0x20, shr(1, version))
            log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
        }
    }

    /// @dev Guards a function such that it can only be called in the scope
    /// of a function guarded with `initializer` or `reinitializer`.
    modifier onlyInitializing() virtual {
        _checkInitializing();
        _;
    }

    /// @dev Reverts if the contract is not initializing.
    function _checkInitializing() internal view virtual {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(and(1, sload(s))) {
                mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`.
    ///
    /// Calling this in the constructor will prevent the contract from being initialized
    /// or reinitialized. It is recommended to use this to lock implementation contracts
    /// that are designed to be called through proxies.
    ///
    /// Emits an {Initialized} event the first time it is successfully called.
    function _disableInitializers() internal virtual {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            let i := sload(s)
            if and(i, 1) {
                mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.
                revert(0x1c, 0x04)
            }
            let uint64max := 0xffffffffffffffff
            if iszero(eq(shr(1, i), uint64max)) {
                // Set `initializing` to 0, `initializedVersion` to `2**64 - 1`.
                sstore(s, shl(1, uint64max))
                // Emit the {Initialized} event.
                mstore(0x20, uint64max)
                log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)
            }
        }
    }

    /// @dev Returns the highest version that has been initialized.
    function _getInitializedVersion() internal view virtual returns (uint64 version) {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            version := shr(1, sload(s))
        }
    }

    /// @dev Returns whether the contract is currently initializing.
    function _isInitializing() internal view virtual returns (bool result) {
        bytes32 s = _initializableSlot();
        /// @solidity memory-safe-assembly
        assembly {
            result := and(1, sload(s))
        }
    }
}

File 3 of 8 : Ownable.sol
// 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();
        _;
    }
}

File 4 of 8 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

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

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions with lower slots,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      REENTRANCY GUARD                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            sstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            sstore(_REENTRANCY_GUARD_SLOT, codesize())
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

File 5 of 8 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

/// @notice UUPS proxy mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol)
/// @author Modified from OpenZeppelin
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol)
///
/// @dev Note:
/// - This implementation is intended to be used with ERC1967 proxies.
/// See: `LibClone.deployERC1967` and related functions.
/// - This implementation is NOT compatible with legacy OpenZeppelin proxies
/// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`.
abstract contract UUPSUpgradeable is CallContextChecker {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The upgrade failed.
    error UpgradeFailed();

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

    /// @dev Emitted when the proxy's implementation is upgraded.
    event Upgraded(address indexed implementation);

    /// @dev `keccak256(bytes("Upgraded(address)"))`.
    uint256 private constant _UPGRADED_EVENT_SIGNATURE =
        0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b;

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

    /// @dev The ERC-1967 storage slot for the implementation in the proxy.
    /// `uint256(keccak256("eip1967.proxy.implementation")) - 1`.
    bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

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

    /// @dev Please override this function to check if `msg.sender` is authorized
    /// to upgrade the proxy to `newImplementation`, reverting if not.
    /// ```
    ///     function _authorizeUpgrade(address) internal override onlyOwner {}
    /// ```
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /// @dev Returns the storage slot used by the implementation,
    /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822).
    ///
    /// Note: The `notDelegated` modifier prevents accidental upgrades to
    /// an implementation that is a proxy contract.
    function proxiableUUID() public view virtual notDelegated returns (bytes32) {
        // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967.
        return _ERC1967_IMPLEMENTATION_SLOT;
    }

    /// @dev Upgrades the proxy's implementation to `newImplementation`.
    /// Emits a {Upgraded} event.
    ///
    /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`.
    function upgradeToAndCall(address newImplementation, bytes calldata data)
        public
        payable
        virtual
        onlyProxy
    {
        _authorizeUpgrade(newImplementation);
        /// @solidity memory-safe-assembly
        assembly {
            newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits.
            mstore(0x00, returndatasize())
            mstore(0x01, 0x52d1902d) // `proxiableUUID()`.
            let s := _ERC1967_IMPLEMENTATION_SLOT
            // Check if `newImplementation` implements `proxiableUUID` correctly.
            if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) {
                mstore(0x01, 0x55299b49) // `UpgradeFailed()`.
                revert(0x1d, 0x04)
            }
            // Emit the {Upgraded} event.
            log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation)
            sstore(s, newImplementation) // Updates the implementation.

            // Perform a delegatecall to `newImplementation` if `data` is non-empty.
            if data.length {
                // Forwards the `data` to `newImplementation` via delegatecall.
                let m := mload(0x40)
                calldatacopy(m, data.offset, data.length)
                if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00))
                {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
        }
    }
}

File 6 of 8 : SignatureCheckerLib.sol
// 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
        }
    }
}

File 7 of 8 : EIP712.sol
// 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;

    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.
    /// We expect that most contracts will use `_hashTypedData` as the main hash,
    /// and `_hashTypedDataSansChainId` only occasionally for cross-chain workflows.
    /// Thus this is optimized for smaller bytecode size over runtime gas.
    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.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    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)))
        }
    }
}

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

/// @notice Call context checker mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/CallContextChecker.sol)
contract CallContextChecker {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The call is from an unauthorized call context.
    error UnauthorizedCallContext();

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

    /// @dev For checking if the context is a delegate call.
    ///
    /// Note: To enable use cases with an immutable default implementation in the bytecode,
    /// (see: ERC6551Proxy), we don't require that the proxy address must match the
    /// value stored in the implementation slot, which may not be initialized.
    uint256 private immutable __self = uint256(uint160(address(this)));

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    CALL CONTEXT CHECKS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // A proxy call can be either via a `delegatecall` to an implementation,
    // or a 7702 call on an authority that points to a delegation.

    /// @dev Returns whether the current call context is on a EIP7702 authority
    /// (i.e. externally owned account).
    function _onEIP7702Authority() internal view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(address(), 0x00, 0x00, 0x20)
            result :=
                and(eq(0xef0100, shr(232, mload(0x00))), lt(sub(extcodesize(address()), 1), 23))
        }
    }

    /// @dev Returns whether the current call context is on the implementation itself.
    function _onImplementation() internal view virtual returns (bool) {
        return __self == uint160(address(this));
    }

    /// @dev Requires that the current call context is performed via a EIP7702 authority.
    function _checkOnlyEIP7702Authority() internal view virtual {
        if (!_onEIP7702Authority()) _revertUnauthorizedCallContext();
    }

    /// @dev Requires that the current call context is performed via a proxy.
    function _checkOnlyProxy() internal view virtual {
        if (_onImplementation()) _revertUnauthorizedCallContext();
    }

    /// @dev Requires that the current call context is NOT performed via a proxy.
    /// This is the opposite of `checkOnlyProxy`.
    function _checkNotDelegated() internal view virtual {
        if (!_onImplementation()) _revertUnauthorizedCallContext();
    }

    /// @dev Requires that the current call context is performed via a EIP7702 authority.
    modifier onlyEIP7702Authority() virtual {
        _checkOnlyEIP7702Authority();
        _;
    }

    /// @dev Requires that the current call context is performed via a proxy.
    modifier onlyProxy() virtual {
        _checkOnlyProxy();
        _;
    }

    /// @dev Requires that the current call context is NOT performed via a proxy.
    /// This is the opposite of `onlyProxy`.
    modifier notDelegated() virtual {
        _checkNotDelegated();
        _;
    }

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

    function _revertUnauthorizedCallContext() private pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.
            revert(0x1c, 0x04)
        }
    }
}

Settings
{
  "viaIR": false,
  "codegen": "yul",
  "remappings": [
    "solady/=lib/solady/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/"
  ],
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "abi"
      ]
    }
  },
  "optimizer": {
    "enabled": true,
    "mode": "3",
    "fallback_to_optimizing_for_size": false,
    "disable_system_request_memoization": true
  },
  "metadata": {},
  "libraries": {},
  "enableEraVMExtensions": false,
  "forceEVMLA": false
}

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PlayerAlreadyRegistered","type":"error"},{"inputs":[],"name":"PlayerNotRegistered","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"Debug","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"score","type":"uint256"}],"name":"LeaderboardUpdated","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"PlayerRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"score","type":"uint256"}],"name":"ScoreEarned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"score","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"ScoreUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"awardScore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"backendSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","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":"address","name":"player","type":"address"}],"name":"getPlayerStats","outputs":[{"components":[{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"bool","name":"isRegistered","type":"bool"}],"internalType":"struct KhugaBash.Player","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getTopPlayers","outputs":[{"components":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"score","type":"uint256"}],"internalType":"struct KhugaBash.LeaderboardEntry[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"registerPlayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_backendSigner","type":"address"}],"name":"setBackendSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"setPlayerNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"updateScore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]

9c4d535b00000000000000000000000000000000000000000000000000000000000000000100023d41834b12ae7dd726d485d28f3b0f05c02a010ef4e3baea79742c7d3900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x0002000000000002000b00000000000200010000000103550000000100200190000000500000c13d0000006002100270000001d7022001970000008003000039000000400030043f000000040020008c0000042e0000413d000000000301043b000000e003300270000001e70030009c000000770000a13d000001e80030009c000000860000213d000001ef0030009c000001520000a13d000001f00030009c0000028e0000613d000001f10030009c000002ce0000613d000001f20030009c0000042e0000c13d0000000001000416000000000001004b0000042e0000c13d0000000901000039000000800010043f000001db02000041000000a00020043f0000010002000039000000400020043f0000000102000039000000c00020043f000001dd03000041000000e00030043f0000020e03000041000001000030043f000000e003000039000001200030043f000001e00010043f000002000100043d0000020f01100197000001db011001c7000002000010043f000002090000043f0000012001000039000001400010043f000002200020043f000002400100043d0000021001100197000001dd011001c7000002400010043f000002410000043f000001d80100004100000000001004430000000001000414000001d70010009c000001d701008041000000c001100210000001d9011001c70000800b020000390757074d0000040f0000000100200190000006360000613d000000000101043b000001600010043f0000000001000410000001800010043f000001a00000043f0000016001000039000001c00010043f000000600100043d000002600010043f000000000001004b000004990000c13d0000018001000039000004a30000013d0000014001000039000000400010043f0000000001000416000000000001004b0000042e0000c13d0000000001000410000000800010043f000000a00010043f000001d80100004100000000001004430000000001000414000001d70010009c000001d701008041000000c001100210000001d9011001c70000800b020000390757074d0000040f0000000100200190000006360000613d000000000401043b000000c00040043f000000400100043d000001da0010009c000000710000813d0000004002100039000000400020043f00000009020000390000000002210436000001db030000410000000000320435000000400500043d000001dc0050009c000000ce0000a13d0000020c01000041000000000010043f0000004101000039000000040010043f0000020d010000410000075900010430000001f50030009c000000a10000a13d000001f60030009c000001700000a13d000001f70030009c000003370000613d000001f80030009c000003540000613d000001f90030009c0000042e0000c13d0000000001000416000000000001004b0000042e0000c13d00000002010000390000041f0000013d000001e90030009c000001b30000a13d000001ea0030009c000003710000613d000001eb0030009c000003a00000613d000001ec0030009c0000042e0000c13d000000240020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000401100370000000000101043b000002010010009c0000042e0000213d00000202020000410000000c0020043f000000000010043f0000000c010000390000002002000039075707330000040f000000000101041a000000800010043f0000020301000041000007580001042e000001fc0030009c000001d20000213d000001ff0030009c000003b10000613d000002000030009c0000042e0000c13d00000202010000410000000c0010043f0000000001000411000000000010043f000002080100004100000000001004430000000001000414000001d70010009c000001d701008041000000c001100210000001d9011001c70000800b020000390757074d0000040f0000000100200190000006360000613d000000000101043b000b00000001001d0000000001000414000001d70010009c000001d701008041000000c00110021000000207011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000b02000029000002320220009a000000000021041b0000000001000414000001d70010009c000001d701008041000000c001100210000001de011001c70000800d02000039000000020300003900000233040000410000036b0000013d000900000004001d0000004003500039000000400030043f0000000103000039000b00000005001d0000000004350436000001dd03000041000a00000004001d0000000000340435000001d70020009c000001d70200804100000040022002100000000001010433000001d70010009c000001d7010080410000006001100210000000000121019f0000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f000001de011001c700008010020000390757074d0000040f00000001002001900000042e0000613d0000000a02000029000001d70020009c000001d70200804100000040022002100000000b030000290000000003030433000001d70030009c000001d7030080410000006003300210000000000223019f000000000101043b000b00000001001d0000000001000414000001d70010009c000001d701008041000000c001100210000000000121019f000001de011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000b05000029000000e00050043f000001000010043f000000400200043d0000008003200039000000000400041000000000004304350000006003200039000000090400002900000000004304350000004003200039000000000013043500000020012000390000000000510435000001df010000410000000000120435000001d70020009c000001d70200804100000040012002100000000002000414000001d70020009c000001d702008041000000c002200210000000000121019f000001e0011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000001200010043f000001e102000041000000000202041a0000000100200190000004470000c13d0000023802200197000001e20020009c000001370000613d000001e201000041000001e102000041000000000012041b000001e301000041000000200010043f0000000001000414000001d70010009c000001d701008041000000c001100210000001e4011001c70000800d020000390000000103000039000001e504000041075707480000040f00000001002001900000042e0000613d000001200100043d000000800200043d00000140000004430000016000200443000000a00200043d00000020030000390000018000300443000001a000200443000000c00200043d0000004004000039000001c000400443000001e0002004430000006002000039000000e00400043d000002000020044300000220004004430000008002000039000001000400043d00000240002004430000026000400443000000a0020000390000028000200443000002a000100443000001000030044300000006010000390000012000100443000001e601000041000007580001042e000001f30030009c000003d80000613d000001f40030009c0000042e0000c13d000000440020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000401100370000000000101043b000b00000001001d000002010010009c0000042e0000213d075707120000040f0000000b01000029000000000010043f0000000101000039000000200010043f00000024010000390000000101100367000000000101043b000b00000001001d00000040020000390000000001000019075707330000040f0000000b02000029000000000021041b0000000001000019000007580001042e000001fa0030009c000003ed0000613d000001fb0030009c0000042e0000c13d000000240020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000401100370000000000101043b000b00000001001d000002010010009c0000042e0000213d000000c001000039000000400010043f000000800000043f000000a00000043f0000000b01000029000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000101100039000000000101041a000000ff00100190000003d40000613d0000000b01000029000000000010043f000000200000043f00000040020000390000000001000019075707330000040f000b00000001001d000000400100043d000a00000001001d075707070000040f0000000b03000029000000000103041a0000000a0200002900000000021204360000000103300039000000000303041a000000ff003001900000000003000039000000010300c0390000000000320435000000400300043d00000000011304360000000002020433000000000002004b0000000002000039000000010200c0390000000000210435000001d70030009c000001d703008041000000400130021000000220011001c7000007580001042e000001ed0030009c0000041b0000613d000001ee0030009c0000042e0000c13d000000240020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000302000039000000000d02041a0000000401100370000000000101043b00000000001d004b000000000d0180190000006400d0008c000000640d0080390000000501d002100000003f0210003900001fe00220018f0000008002200039000000400020043f0000008000d0043f00000000000d004b000004300000c13d0000020c01000041000000000010043f0000001101000039000000040010043f0000020d010000410000075900010430000001fd0030009c000004240000613d000001fe0030009c0000042e0000c13d000000640020008c0000042e0000413d0000000003000416000000000003004b0000042e0000c13d0000002403100370000000000303043b000a00000003001d0000000403100370000000000303043b000900000003001d0000004403100370000000000303043b000b00000003001d000001e30030009c0000042e0000213d0000000b030000290000002303300039000000000023004b0000042e0000813d0000000b03000029000700040030003d0000000701100360000000000101043b000800000001001d000001e30010009c0000042e0000213d0000000b010000290000002403100039000600000003001d0000000801300029000000000021004b0000042e0000213d0000000001000411000000000010043f0000000101000039000000200010043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000101041a000000010110003a000001cc0000613d0000000a03000029000000000013004b000005290000c13d000000400100043d000000600210003900000000003204350000004002100039000000090300002900000000003204350000006002000039000000000221043600000227030000410000000000320435000002280010009c000000710000213d0000008003100039000000400030043f000001d70020009c000001d70200804100000040022002100000000001010433000001d70010009c000001d7010080410000006001100210000000000121019f0000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f000001de011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000500000001001d0000021c01000041000000000010044300000000010004120000000400100443000000a00100003900000024001004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b000400000001001d0000021c01000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b000300000001001d0000021c01000041000000000010044300000000010004120000000400100443000000400100003900000024001004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b000200000001001d000001d80100004100000000001004430000000001000414000001d70010009c000001d701008041000000c001100210000001d9011001c70000800b020000390757074d0000040f0000000100200190000006360000613d0000000002000410000000000101043b000100000001001d000000030020006c000005d00000c13d0000000202000029000000010020006b000005d00000c13d0000022901000041000000000010043f00000004010000290000001a0010043f00000005010000290000003a0010043f0000000001000414000001d70010009c000001d701008041000000c0011002100000022a011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000400000001001d0000003a0000043f0000000201000039000000000101041a000300000001001d000502010010019c000006100000c13d0000023101000041000000000010043f000002130100004100000759000104300000000001000416000000000001004b0000042e0000c13d000001e102000041000000000302041a0000000301000039000000000012041b000000000003004b000002af0000613d000b00000003001d00000217010000410000000000100443000000000100041000000004001004430000000001000414000001d70010009c000001d701008041000000c00110021000000218011001c700008002020000390757074d0000040f0000000100200190000006360000613d0000000b030000290000023802300197000000000101043b000000020020008c000004470000c13d000000000001004b000004470000c13d00000001003001900000000002000019000001e102006041000b00000002001d00000000060004110000020401000041000000000061041b0000000001000414000001d70010009c000001d701008041000000c001100210000001de011001c70000800d0200003900000003030000390000021a040000410000000005000019075707480000040f00000001002001900000042e0000613d0000000b0000006b0000036f0000613d00000002010000390000000b02000029000000000012041b0000000103000039000000200030043f0000000001000414000001d70010009c000001d701008041000000c001100210000001e4011001c70000800d02000039000001e5040000410000036c0000013d000000240020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000401100370000000000101043b000b00000001001d0000000001000411000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000101100039000000000101041a000000ff00100190000004a80000c13d000000400200043d000001dc0020009c000000710000213d0000004001200039000000400010043f00000020032000390000000101000039000900000003001d0000000000130435000a00000002001d00000000000204350000000001000411000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d0000000a020000290000000002020433000000000101043b000000000021041b0000000101100039000000000201041a000002390220019700000009030000290000000003030433000000000003004b000000010220c1bf000000000021041b0000000001000411000000000010043f0000000101000039000000200010043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000b02000029000000000021041b0000000302000039000000000102041a000001e30010009c000000710000213d0000000103100039000000000032041b000000000020043f0000020a0110009a000000000201041a00000214022001970000000005000411000000000252019f000000000021041b000000400100043d0000000b020000290000000000210435000001d70010009c000001d70100804100000040011002100000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f00000215011001c70000800d02000039000000020300003900000216040000410000036c0000013d0000000001000416000000000001004b0000042e0000c13d0000021c0100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b0000000002000410000000000021004b000004170000c13d000000400100043d0000021e020000410000000000210435000001d70010009c000001d70100804100000040011002100000021f011001c7000007580001042e00000202010000410000000c0010043f0000000001000411000000000010043f0000000001000414000001d70010009c000001d701008041000000c00110021000000207011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000001041b0000000001000414000001d70010009c000001d701008041000000c001100210000001de011001c70000800d0200003900000002030000390000021b040000410000000005000411075707480000040f00000001002001900000042e0000613d0000000001000019000007580001042e000000240020008c0000042e0000413d0000000401100370000000000101043b000b00000001001d000002010010009c0000042e0000213d0000020401000041000000000101041a0000000002000411000000000012004b000005c80000c13d00000202010000410000000c0010043f0000000b01000029000000000010043f0000000001000414000001d70010009c000001d701008041000000c00110021000000207011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000900000001001d000000000101041a000a00000001001d000002080100004100000000001004430000000001000414000001d70010009c000001d701008041000000c001100210000001d9011001c70000800b020000390757074d0000040f0000000100200190000006360000613d000000000101043b0000000a0010006c000004f50000a13d0000020901000041000000000010043f00000206010000410000075900010430000000240020008c0000042e0000413d0000000401100370000000000101043b000002010010009c0000042e0000213d0000020402000041000000000202041a0000000003000411000000000023004b000005c80000c13d000000000001004b000004f80000c13d0000020501000041000000000010043f00000206010000410000075900010430000000440020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000402100370000000000202043b000b00000002001d000002010020009c0000042e0000213d0000002401100370000000000301043b0000020401000041000000000101041a0000000002000411000000000012004b000005c80000c13d000a00000003001d0000000b01000029000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b0000000101100039000000000101041a000000ff00100190000004ac0000c13d0000023701000041000000000010043f000002130100004100000759000104300000020401000041000000000501041a0000000001000411000000000051004b000005c80000c13d0000000001000414000001d70010009c000001d701008041000000c001100210000001de011001c70000800d0200003900000003030000390000021a040000410000000006000019075707480000040f00000001002001900000042e0000613d0000020401000041000000000001041b0000000001000019000007580001042e000000440020008c0000042e0000413d0000000403100370000000000303043b000b00000003001d000002010030009c0000042e0000213d0000002403100370000000000303043b000001e30030009c0000042e0000213d0000002304300039000000000024004b0000042e0000813d000900040030003d0000000901100360000000000101043b000a00000001001d000001e30010009c0000042e0000213d0000000a013000290000002401100039000000000021004b0000042e0000213d0000021c0100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b0000000002000410000000000021004b0000052d0000c13d0000022501000041000000000010043f000002060100004100000759000104300000000001000416000000000001004b0000042e0000c13d0000020401000041000000000101041a0000020101100197000000800010043f0000020301000041000007580001042e000000240020008c0000042e0000413d0000000002000416000000000002004b0000042e0000c13d0000000401100370000000000101043b000b00000001001d000002010010009c0000043f0000a13d0000000001000019000007590001043000000000030000190000004004200039000000400040043f000000200420003900000000000404350000000000020435000000a00430003900000000002404350000002003300039000000000013004b0000044b0000813d000000400200043d000001dc0020009c000004310000a13d000000710000013d075707120000040f0000000201000039000000000201041a00000214022001970000000b022001af000000000021041b0000000001000019000007580001042e0000021901000041000000000010043f00000206010000410000075900010430000000000300001900090000000d001d0000000301000039000000000101041a000000000031004b000005230000a13d000b00000003001d0000020a0130009a000000000101041a0000020101100197000a00000001001d000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000400200043d000001dc0020009c000000090d000029000000710000213d000000000101043b000000000101041a0000004003200039000000400030043f000000200320003900000000001304350000000a010000290000000000120435000000800100043d0000000b03000029000000000031004b000005230000a13d0000000501300210000000a0011000390000000000210435000000800100043d000000000031004b000005230000a13d00000001033000390000000000d3004b0000044d0000413d0000000102d0008c000004fb0000c13d000000400100043d00000020020000390000000002210436000000800300043d00000000003204350000004002100039000000000003004b000004900000613d000000a004000039000000000500001900000000460404340000000076060434000002010660019700000000066204360000000007070433000000000076043500000040022000390000000105500039000000000035004b000004860000413d0000000002120049000001d70020009c000001d7020080410000006002200210000001d70010009c000001d7010080410000004001100210000000000112019f000007580001042e0000028003000039000000000200001900000080050000390000000004030019000000005305043400000000033404360000000102200039000000000012004b0000049c0000413d000000e00140008a000001d70010009c000001d701008041000000600110021000000211011001c7000007580001042e0000021201000041000000000010043f000002130100004100000759000104300000000a020000290000000a032000c90000000a0130011a000000000012004b000001cc0000c13d000a00000003001d0000000b01000029000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000201041a0000000a03000029000000000032001a000001cc0000413d0000000002320019000000000021041b000000400100043d0000000000310435000001d70010009c000001d70100804100000040011002100000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f00000215011001c70000800d02000039000000020300003900000235040000410000000b05000029075707480000040f00000001002001900000042e0000613d0000000b01000029000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000101041a000000400200043d0000000000120435000001d70020009c000001d70200804100000040012002100000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f00000215011001c70000800d02000039000000020300003900000236040000410000000b050000290000036c0000013d0000000901000029000000000001041b0000000b010000290757071c0000040f0000000001000019000007580001042e0000000004000019000005000000013d0000000104400039000000000024004b0000047c0000813d0000000000d4004b000001cc0000213d0000023a0540016700000000055d001a000004fd0000613d00000000070000190000050a0000013d000000000056004b0000000007060019000004fd0000813d000000000071004b000005230000a13d0000000106700039000000000061004b000005230000a13d0000000507700210000000a00970003900000000070904330000000508600210000000200a700039000000000b0a0433000000a008800039000000000a080433000000200ca00039000000000c0c04330000000000cb004b000005070000813d0000000000a90435000000800100043d000000000061004b000005230000a13d0000000000780435000000800100043d000000000061004b000005070000213d0000020c01000041000000000010043f0000003201000039000000040010043f0000020d0100004100000759000104300000022601000041000000000010043f000002130100004100000759000104300000020401000041000000000101041a0000000002000411000000000012004b000005c80000c13d0000000001000031000000000010043f000001f701000041000000010010043f0000000001000414000001d70010009c000001d701008041000000c00110021000000221011001c70000000b020000290757074d0000040f0000006003100270000001d703300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf0000054c0000613d0000000107000039000000000801034f000000008908043c0000000007970436000000000047004b000005480000c13d000000010220018f000000000005004b0000055a0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f00000000010204330000021e0010009c000005cc0000c13d0000000001000414000001d70010009c000001d701008041000000c001100210000001de011001c70000800d02000039000000020300003900000223040000410000000b05000029075707480000040f00000001002001900000042e0000613d0000021e010000410000000b02000029000000000021041b0000000a0000006b0000036f0000613d0000000a030000290000023b023001980000001f0330018f000000400100043d000800000001001d00000000012100190000000904000029000000200440003900000001044003670000057f0000613d000000000504034f0000000806000029000000005705043c0000000006760436000000000016004b0000057b0000c13d000000000003004b0000058c0000613d000000000224034f0000000303300210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f000000000021043500000217010000410000000000100443000000000100041200000004001004430000000001000414000001d70010009c000001d701008041000000c00110021000000218011001c700008002020000390757074d0000040f0000000100200190000006360000613d0000000a01000029000001d70010009c000001d70100804100000060011002100000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f0000000802000029000001d70020009c000001d702008041000a0040002002180000000a011001af0000000b02000029075707520000040f0000006003100270000001d70030019d00000001002001900000036f0000c13d000001d7023001970000001f0420018f000002240520019800000008080000290000000003580019000005b80000613d000000000601034f000000006706043c0000000008780436000000000038004b000005b40000c13d000000000004004b000005c50000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000060012002100000000a011001af00000759000104300000023401000041000000000010043f000002060100004100000759000104300000022201000041000000010010043f00000221010000410000075900010430000000400200043d000001df01000041000300000002001d0000000001120436000400000001001d0000021c01000041000000000010044300000000010004120000000400100443000000600100003900000024001004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b000000040200002900000000001204350000021c01000041000000000010044300000000010004120000000400100443000000800100003900000024001004430000000001000414000001d70010009c000001d701008041000000c0011002100000021d011001c700008005020000390757074d0000040f0000000100200190000006360000613d000000000101043b000000030400002900000080024000390000000003000410000000000032043500000060024000390000000103000029000000000032043500000040024000390000000000120435000001d70040009c000001d70400804100000040014002100000000002000414000001d70020009c000001d702008041000000c002200210000000000121019f000001e0011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000400000001001d000002730000013d000000400100043d000200000001001d00000217010000410000000000100443000000050100002900000004001004430000000001000414000001d70010009c000001d701008041000000c00110021000000218011001c700008002020000390757074d0000040f0000000100200190000006360000613d000000000101043b000000000001004b000006370000c13d0000000801000029000000400010008c000006940000613d0000000801000029000000410010008c0000028a0000c13d0000000b0100002900000064011000390000000101100367000000000101043b000000f801100270000000200010043f000000060100002900000001011003670000004003000039000000001201043c0000000003230436000000800030008c000006310000c13d000006a10000013d000000000001042f000000020500002900000064025000390000004401500039000000240650003900000004035000390000022b040000410000000000450435000000040400002900000000004304350000004003000039000b00000006001d0000000000360435000000080400002900000000004104350000023b034001980000001f0440018f000000000132001900000006050000290000000105500367000006500000613d000000000605034f000000006706043c0000000002720436000000000012004b0000064c0000c13d000000000004004b0000065d0000613d000000000235034f0000000303400210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f00000000002104350000000201000029000001d70010009c000001d701008041000000400110021000000008020000290000022c0020009c0000022c020080410000006002200210000000000112019f0000000002000414000001d70020009c000001d702008041000000c002200210000000000121019f0000022d0110009a00000005020000290757074d0000040f0000006003100270000001d703300197000000200030008c000000200400003900000000040340190000001f0540018f00000020064001900000000b046000290000067d0000613d000000000701034f0000000b08000029000000007907043c0000000008980436000000000048004b000006790000c13d000000000005004b0000068a0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000b0100002900000000010104330000022b0010009c00000000010000390000000101006039000000000112016f00000001001001900000028a0000613d000006d00000013d000000070400002900000040014000390000000101100367000000000101043b000000ff031002700000001b03300039000000200030043f00000020034000390000000102300367000000000202043b000000400020043f0000022e01100197000000600010043f0000000401000029000000000010043f0000000001000414000001d70010009c000001d701008041000000c0011002100000022f011001c700000001020000390757074d0000040f00000001090000390000006003100270000001d703300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf000006b90000613d000000000701034f000000007807043c0000000009890436000000000049004b000006b50000c13d000000010220018f000000000005004b000006c70000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000202000029000000400020043f000000030110014f0000006001100210000000000013004b0000028a0000a13d0000000001000411000000000010043f000000200000043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000201041a000000090020002a000001cc0000413d0000000902200029000000000021041b0000000001000411000000000010043f0000000101000039000000200010043f0000000001000414000001d70010009c000001d701008041000000c0011002100000020b011001c700008010020000390757074d0000040f00000001002001900000042e0000613d000000000101043b000000000201041a000000010220003a000001cc0000613d000000000021041b000000400100043d00000020021000390000000a03000029000000000032043500000009020000290000000000210435000001d70010009c000001d70100804100000040011002100000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f0000020b011001c70000800d02000039000000010300003900000230040000410000036c0000013d000001da0010009c0000070c0000813d0000004001100039000000400010043f000000000001042d0000020c01000041000000000010043f0000004101000039000000040010043f0000020d0100004100000759000104300000020401000041000000000101041a0000000002000411000000000012004b000007180000c13d000000000001042d0000023401000041000000000010043f0000020601000041000007590001043000010000000000020000020402000041000000000502041a00000000020004140000020106100197000001d70020009c000001d702008041000000c001200210000001de011001c70000800d0200003900000003030000390000021a04000041000100000006001d075707480000040f0000000100200190000007300000613d00000204010000410000000102000029000000000021041b000000000001042d00000000010000190000075900010430000000000001042f000001d70010009c000001d7010080410000004001100210000001d70020009c000001d7020080410000006002200210000000000112019f0000000002000414000001d70020009c000001d702008041000000c002200210000000000112019f000001de011001c700008010020000390757074d0000040f0000000100200190000007460000613d000000000101043b000000000001042d000000000100001900000759000104300000074b002104210000000102000039000000000001042d0000000002000019000000000001042d00000750002104230000000102000039000000000001042d0000000002000019000000000001042d00000755002104250000000102000039000000000001042d0000000002000019000000000001042d0000075700000432000007580001042e00000759000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffc04b68756761426173680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf310000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f02000000000000000000000000000000000000a0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132000000000000000000000000000000000000000000000001fffffffffffffffe000000000000000000000000000000000000000000000000ffffffffffffffff0200000000000000000000000000000000000020000000200000000000000000c7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d200000002000000000000000000000000000001c000000100000000000000000000000000000000000000000000000000000000000000000000000000715018a5000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000f04e283d00000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000fee81cf4000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000ba3c0067000000000000000000000000000000000000000000000000000000008129fc1b000000000000000000000000000000000000000000000000000000008129fc1c00000000000000000000000000000000000000000000000000000000821644e60000000000000000000000000000000000000000000000000000000084b0196e00000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000007271bd7a000000000000000000000000000000000000000000000000000000004f1ef2850000000000000000000000000000000000000000000000000000000052d1902c0000000000000000000000000000000000000000000000000000000052d1902d0000000000000000000000000000000000000000000000000000000054d1f13d0000000000000000000000000000000000000000000000000000000065d65e86000000000000000000000000000000000000000000000000000000004f1ef286000000000000000000000000000000000000000000000000000000004fd66eae0000000000000000000000000000000000000000000000000000000036f9566f0000000000000000000000000000000000000000000000000000000036f9567000000000000000000000000000000000000000000000000000000000385aa0d70000000000000000000000000000000000000000000000000000000019d29beb0000000000000000000000000000000000000000000000000000000025692962000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000389a75e10000000000000000000000000000000000000020000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c000000000000000002000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132000000000000000000000000000000000000000000000000000000006f5e88183da8a5f161a6c3ff06a60736d0ed24d7963cc6a5c4fafd2fa1dae9bb908e07a502000000000000000000000000000000000000400000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000001000000000000000000ab5ac72b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000200000000000000000000000000000000000020000000000000000000000000324cb0062138d65997c86cd3012489ceb351d602f2f55c7408306e8040c79f3f1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000000000000000000000f92ee8a98be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e0200000200000000000000000000000000000044000000000000000000000000360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc0000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000001d00000000000000000000000000000000000000000000000000000000000000000000000055299b49bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b00000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000000000000000000000000000000000009f03a026756688fe000000000000000000000000000000000000000000000000000000002490220cb91f83014ac0d727e13dce8b176302e0fd4bd96c9f4c381942269f0e000000000000000000000000000000000000000000000000ffffffffffffff7f000000000000000000000000000000000000000000000000190100000000000002000000000000000000000000000000000000420000001800000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff9bffffffffffffffffffffffffffffffffffffff9c0000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000080000000000000000000000000efd5a7f141ae02cd40bc84ffe6ebb58811cb61dfd017746842a005c78bfed8528baa579f00000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d0000000000000000000000000000000000000000000000000000000082b42900869fbbabf77b40949a507fa060ce28ba380b0f168fc23838320938f6910926a624e225604268d6416871b32db1be8e49f497caf8360393b31d71a34a4ce2669337ae9e4c00000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0d53de5f6d84c9f92a6ed229cb46a010b85b6d6bc6417f1db910a011322424d62

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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