ETH Price: $2,296.61 (-4.97%)

Contract

0x00000000000099DE0BF6fA90dEB851E2A2df7d83

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
392314222026-02-01 21:03:0118 mins ago1769979781
0x00000000...2A2df7d83
0 ETH
392314222026-02-01 21:03:0118 mins ago1769979781
0x00000000...2A2df7d83
0 ETH
392314222026-02-01 21:03:0118 mins ago1769979781
0x00000000...2A2df7d83
0 ETH
392314222026-02-01 21:03:0118 mins ago1769979781
0x00000000...2A2df7d83
0 ETH
392313392026-02-01 21:01:3819 mins ago1769979698
0x00000000...2A2df7d83
0 ETH
392313392026-02-01 21:01:3819 mins ago1769979698
0x00000000...2A2df7d83
0 ETH
392313392026-02-01 21:01:3819 mins ago1769979698
0x00000000...2A2df7d83
0 ETH
392313392026-02-01 21:01:3819 mins ago1769979698
0x00000000...2A2df7d83
0 ETH
392276962026-02-01 20:00:551 hr ago1769976055
0x00000000...2A2df7d83
0 ETH
392276962026-02-01 20:00:551 hr ago1769976055
0x00000000...2A2df7d83
0 ETH
392276962026-02-01 20:00:551 hr ago1769976055
0x00000000...2A2df7d83
0 ETH
392276962026-02-01 20:00:551 hr ago1769976055
0x00000000...2A2df7d83
0 ETH
392276742026-02-01 20:00:331 hr ago1769976033
0x00000000...2A2df7d83
0 ETH
392276742026-02-01 20:00:331 hr ago1769976033
0x00000000...2A2df7d83
0 ETH
392276742026-02-01 20:00:331 hr ago1769976033
0x00000000...2A2df7d83
0 ETH
392276742026-02-01 20:00:331 hr ago1769976033
0x00000000...2A2df7d83
0 ETH
392241812026-02-01 19:02:202 hrs ago1769972540
0x00000000...2A2df7d83
0 ETH
392241812026-02-01 19:02:202 hrs ago1769972540
0x00000000...2A2df7d83
0 ETH
392241812026-02-01 19:02:202 hrs ago1769972540
0x00000000...2A2df7d83
0 ETH
392241812026-02-01 19:02:202 hrs ago1769972540
0x00000000...2A2df7d83
0 ETH
392241452026-02-01 19:01:442 hrs ago1769972504
0x00000000...2A2df7d83
0 ETH
392241452026-02-01 19:01:442 hrs ago1769972504
0x00000000...2A2df7d83
0 ETH
392241452026-02-01 19:01:442 hrs ago1769972504
0x00000000...2A2df7d83
0 ETH
392241452026-02-01 19:01:442 hrs ago1769972504
0x00000000...2A2df7d83
0 ETH
392205912026-02-01 18:02:303 hrs ago1769968950
0x00000000...2A2df7d83
0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SingleSignerValidationModule

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol";
import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol";
import {ReplaySafeWrapper} from "@erc6900/reference-implementation/modules/ReplaySafeWrapper.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

import {SignatureType} from "../../helpers/SignatureType.sol";
import {ModuleBase} from "../ModuleBase.sol";

/// @title Single Signer Validation Module
/// @author Alchemy
/// @notice This validation enables any ECDSA (secp256k1 curve) signature validation or Contract Owner signature
/// validation. It handles installation by each entity (entityId).
/// NOTE:
/// - The first byte of the to be checked Signature is the SignatureType, indicating EOA or Contract Owner.
/// - Uninstallation will NOT disable all installed entity IDs of an account. It only uninstalls the
///   entity ID that is passed in. Account must remove access for each entity ID if want to disable all.
/// - None of the functions are installed on the account. Account states are to be retrieved from this global
///   singleton directly.
/// - This validation supports ERC-1271. The signature is valid if it is signed by the owner's private key.
/// - This validation supports composition that other validation can relay on entities in this validation to
///   validate partially or fully.
contract SingleSignerValidationModule is IValidationModule, ReplaySafeWrapper, ModuleBase {
    using MessageHashUtils for bytes32;

    uint256 internal constant _SIG_VALIDATION_PASSED = 0;
    uint256 internal constant _SIG_VALIDATION_FAILED = 1;

    // bytes4(keccak256("isValidSignature(bytes32,bytes)"))
    bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e;
    bytes4 internal constant _1271_INVALID = 0xffffffff;

    mapping(uint32 entityId => mapping(address account => address)) public signers;

    /// @notice This event is emitted when Signer of the account's validation changes.
    /// @param account The account whose validation Signer changed.
    /// @param entityId The entityId for the account and the signer.
    /// @param newSigner The address of the new signer.
    /// @param previousSigner The address of the previous signer.
    event SignerTransferred(
        address indexed account, uint32 indexed entityId, address indexed newSigner, address previousSigner
    ) anonymous;

    error InvalidSignatureType();
    error NotAuthorized();

    /// @notice Transfer Signer of the account's validation to `newSigner`.
    /// @param entityId The entityId for the account and the signer.
    /// @param newSigner The address of the new signer.
    function transferSigner(uint32 entityId, address newSigner) external {
        _transferSigner(entityId, newSigner);
    }

    /// @inheritdoc IModule
    function onInstall(bytes calldata data) external override {
        (uint32 entityId, address newSigner) = abi.decode(data, (uint32, address));
        _transferSigner(entityId, newSigner);
    }

    /// @inheritdoc IModule
    function onUninstall(bytes calldata data) external override {
        uint32 entityId = abi.decode(data, (uint32));
        _transferSigner(entityId, address(0));
    }

    /// @inheritdoc IValidationModule
    function validateUserOp(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        view
        override
        returns (uint256)
    {
        // Validate the user op signature against the owner.
        if (_checkSig(signers[entityId][userOp.sender], userOpHash.toEthSignedMessageHash(), userOp.signature)) {
            return _SIG_VALIDATION_PASSED;
        }
        return _SIG_VALIDATION_FAILED;
    }

    /// @inheritdoc IValidationModule
    function validateRuntime(
        address account,
        uint32 entityId,
        address sender,
        uint256,
        bytes calldata,
        bytes calldata
    ) external view override {
        // Validate that the sender is the owner of the account or self.
        if (sender != signers[entityId][account]) {
            revert NotAuthorized();
        }
        return;
    }

    /// @inheritdoc IValidationModule
    /// @dev The signature is valid if it is signed by the owner's private key
    /// (if the owner is an EOA) or if it is a valid ERC-1271 signature from the
    /// owner (if the owner is a contract).
    /// Note that the digest is wrapped in an EIP-712 struct to prevent cross-account replay attacks. The
    /// replay-safe hash may be retrieved by calling the public function `replaySafeHash`.
    function validateSignature(address account, uint32 entityId, address, bytes32 digest, bytes calldata signature)
        external
        view
        override
        returns (bytes4)
    {
        bytes32 _replaySafeHash = replaySafeHash(account, digest);
        if (_checkSig(signers[entityId][account], _replaySafeHash, signature)) {
            return _1271_MAGIC_VALUE;
        }
        return _1271_INVALID;
    }

    // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    // ┃    Module interface functions    ┃
    // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

    /// @inheritdoc IModule
    function moduleId() external pure returns (string memory) {
        return "alchemy.single-signer-validation-module.1.0.0";
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ModuleBase, IERC165)
        returns (bool)
    {
        return (interfaceId == type(IValidationModule).interfaceId || super.supportsInterface(interfaceId));
    }

    // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    // ┃    Internal / Private functions    ┃
    // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

    function _transferSigner(uint32 entityId, address newSigner) internal {
        address previousSigner = signers[entityId][msg.sender];
        signers[entityId][msg.sender] = newSigner;
        emit SignerTransferred(msg.sender, entityId, newSigner, previousSigner);
    }

    function _checkSig(address owner, bytes32 digest, bytes calldata sig) internal view returns (bool) {
        if (sig.length < 1) {
            revert InvalidSignatureType();
        }
        SignatureType sigType = SignatureType(uint8(bytes1(sig)));
        if (sigType == SignatureType.EOA) {
            (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(digest, sig[1:]);
            if (err == ECDSA.RecoverError.NoError && recovered == owner) {
                return true;
            }
            return false;
        } else if (sigType == SignatureType.CONTRACT_OWNER) {
            return SignatureChecker.isValidERC1271SignatureNow(owner, digest, sig[1:]);
        }
        revert InvalidSignatureType();
    }
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

interface IModule is IERC165 {
    /// @notice Initialize module data for the modular account.
    /// @dev Called by the modular account during `installExecution`.
    /// @param data Optional bytes array to be decoded and used by the module to setup initial module data for the
    /// modular account.
    function onInstall(bytes calldata data) external;

    /// @notice Clear module data for the modular account.
    /// @dev Called by the modular account during `uninstallExecution`.
    /// @param data Optional bytes array to be decoded and used by the module to clear module data for the modular
    /// account.
    function onUninstall(bytes calldata data) external;

    /// @notice Return a unique identifier for the module.
    /// @dev This function MUST return a string in the format "vendor.module.semver". The vendor and module
    /// names MUST NOT contain a period character.
    /// @return The module ID.
    function moduleId() external view returns (string memory);
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

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

interface IValidationModule is IModule {
    /// @notice Run the user operation validation function specified by the `entityId`.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param userOp The user operation.
    /// @param userOpHash The user operation hash.
    /// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
    function validateUserOp(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        returns (uint256);

    /// @notice Run the runtime validation function specified by the `entityId`.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param account the account to validate for.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender The caller address.
    /// @param value The call value.
    /// @param data The calldata sent.
    /// @param authorization Additional data for the validation function to use.
    function validateRuntime(
        address account,
        uint32 entityId,
        address sender,
        uint256 value,
        bytes calldata data,
        bytes calldata authorization
    ) external;

    /// @notice Validates a signature using ERC-1271.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param account the account to validate for.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender the address that sent the ERC-1271 request to the smart account
    /// @param hash the hash of the ERC-1271 request
    /// @param signature the signature of the ERC-1271 request
    /// @return The ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid.
    function validateSignature(
        address account,
        uint32 entityId,
        address sender,
        bytes32 hash,
        bytes calldata signature
    ) external view returns (bytes4);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

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

import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

// A contract mixin for modules that wish to use EIP-712 to wrap the hashes sent to the EIP-1271 function
// `isValidSignature`.
// This makes signatures generated by owners of contract accounts non-replayable across multiple accounts owned by
// the same owner.
abstract contract ReplaySafeWrapper is ModuleEIP712 {
    // keccak256("ReplaySafeHash(bytes32 hash)")
    bytes32 private constant _REPLAY_SAFE_HASH_TYPEHASH =
        0x294a8735843d4afb4f017c76faf3b7731def145ed0025fc9b1d5ce30adf113ff;

    /// @notice Wraps a hash in an EIP-712 envelope to prevent cross-account replay attacks.
    /// Uses the ModuleEIP712 domain separator, which includes the chainId, module address, and account address.
    /// @param account The account that will validate the message hash.
    /// @param hash The hash to wrap.
    /// @return The the replay-safe hash, computed by wrapping the input hash in an EIP-712 struct.
    function replaySafeHash(address account, bytes32 hash) public view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash({
            domainSeparator: _domainSeparator(account),
            structHash: _hashStruct(hash)
        });
    }

    function _hashStruct(bytes32 hash) internal pure virtual returns (bytes32) {
        bytes32 res;
        assembly ("memory-safe") {
            mstore(0x00, _REPLAY_SAFE_HASH_TYPEHASH)
            mstore(0x20, hash)
            res := keccak256(0x00, 0x40)
        }
        return res;
    }
}

File 5 of 19 : PackedUserOperation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

/**
 * User Operation struct
 * @param sender                - The sender account of this request.
 * @param nonce                 - Unique value the sender uses to verify it is not a replay.
 * @param initCode              - If set, the account contract will be created by this constructor/
 * @param callData              - The method call to execute on this account.
 * @param accountGasLimits      - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
 * @param preVerificationGas    - Gas not calculated by the handleOps method, but added to the gas paid.
 *                                Covers batch overhead.
 * @param gasFees               - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.
 * @param paymasterAndData      - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data
 *                                The paymaster will pay for the transaction instead of the sender.
 * @param signature             - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.
 */
struct PackedUserOperation {
    address sender;
    uint256 nonce;
    bytes initCode;
    bytes callData;
    bytes32 accountGasLimits;
    uint256 preVerificationGas;
    bytes32 gasFees;
    bytes paymasterAndData;
    bytes signature;
}

File 6 of 19 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.20;

import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Safe Wallet (previously Gnosis Safe).
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
        return
            (error == ECDSA.RecoverError.NoError && recovered == signer) ||
            isValidERC1271SignatureNow(signer, hash, signature);
    }

    /**
     * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
     * against the signer smart contract using ERC1271.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidERC1271SignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
        );
        return (success &&
            result.length >= 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

File 10 of 19 : SignatureType.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

/// @notice An enum that is prepended to signatures to differentiate between EOA and contract owner signatures.
enum SignatureType {
    EOA,
    CONTRACT_OWNER
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol";

/// @title Module Base
/// @author Alchemy
/// @dev Implements ERC-165 to support IModule's interface, which is a requirement for module installation.
abstract contract ModuleBase is ERC165, IModule {
    error NotImplemented();
    error UnexpectedDataPassed();

    modifier assertNoData(bytes calldata data) {
        if (data.length > 0) {
            revert UnexpectedDataPassed();
        }
        _;
    }

    /// @dev Returns true if this contract implements the interface defined by
    /// `interfaceId`. See the corresponding
    /// https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
    /// to learn more about how these ids are created.
    ///
    /// This function call must use less than 30 000 gas.
    ///
    /// Supporting the IModule interface is a requirement for module installation. This is also used
    /// by the modular account to prevent standard execution functions `execute` and `executeBatch` from
    /// making calls to modules.
    /// @param interfaceId The interface ID to check for support.
    /// @return True if the contract supports `interfaceId`.
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IModule).interfaceId || super.supportsInterface(interfaceId);
    }

    /// @dev help method that returns extracted selector and calldata. If selector is executeUserOp, return the
    /// selector and calldata of the inner call.
    function _getSelectorAndCalldata(bytes calldata data) internal pure returns (bytes4, bytes memory) {
        bytes4 selector = bytes4(data[:4]);
        if (selector == IAccountExecute.executeUserOp.selector) {
            (PackedUserOperation memory uo,) = abi.decode(data[4:], (PackedUserOperation, bytes32));
            bytes memory finalCalldata = uo.callData;
            // Bytes arr representation: [bytes32(len), bytes4(executeUserOp.selector), bytes4(actualSelector),
            // bytes(actualCallData)]
            assembly ("memory-safe") {
                // Copy actualSelector into a new var
                selector := shl(224, mload(add(finalCalldata, 8)))

                let len := mload(finalCalldata)

                // Move the finalCalldata pointer by 8
                finalCalldata := add(finalCalldata, 8)

                // Shorten bytes arry by 8 by: store length - 8 into the new pointer location
                mstore(finalCalldata, sub(len, 8))
            }
            return (selector, finalCalldata);
        }
        return (selector, data[4:]);
    }
}

File 12 of 19 : ModuleEIP712.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

// A base for modules that use EIP-712 structured data signing.
//
// Unlike other EIP712 libraries, this mixin uses the salt field to hold the account address.
//
// It omits the name and version from the EIP-712 domain, as modules are intended to be deployed as
// immutable singletons, thus a different versions and instances would have a different module address.
//
// Due to depending on the account address to calculate the domain separator, this abstract contract does not
// implement EIP-5267, as the domain retrieval function does not provide a parameter to use for the account address
// (internally the verifyingContract), and the computed `msg.sender` for an `eth_call` without an override is
// address(0).
abstract contract ModuleEIP712 {
    // keccak256(
    //     "EIP712Domain(uint256 chainId,address verifyingContract,bytes32 salt)"
    // )
    bytes32 private constant _DOMAIN_SEPARATOR_TYPEHASH =
        0x71062c282d40422f744945d587dbf4ecfd4f9cfad1d35d62c944373009d96162;

    function _domainSeparator(address account) internal view returns (bytes32) {
        return keccak256(
            abi.encode(
                _DOMAIN_SEPARATOR_TYPEHASH, block.chainid, address(this), bytes32(uint256(uint160(account)))
            )
        );
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 16 of 19 : IAccountExecute.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

import "./PackedUserOperation.sol";

interface IAccountExecute {
    /**
     * Account may implement this execute method.
     * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash)
     * to the account.
     * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields)
     *
     * @param userOp              - The operation that was just validated.
     * @param userOpHash          - Hash of the user's request data.
     */
    function executeUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash
    ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

Settings
{
  "viaIR": true,
  "metadata": {
    "bytecodeHash": "none"
  },
  "optimizer": {
    "runs": 10000000,
    "enabled": true
  },
  "evmVersion": "paris",
  "remappings": [
    ":@alchemy/light-account/=lib/light-account/",
    ":@erc6900/reference-implementation/=node_modules/@erc6900/reference-implementation/src/",
    ":@eth-infinitism/account-abstraction/=node_modules/account-abstraction/contracts/",
    ":@openzeppelin/=lib/openzeppelin-contracts/",
    ":FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/",
    ":account-abstraction/=node_modules/account-abstraction/contracts/",
    ":ds-test/=lib/forge-std/lib/ds-test/src/",
    ":forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
    ":forge-std/=lib/forge-std/src/",
    ":openzeppelin-contracts/=lib/webauthn-sol/lib/openzeppelin-contracts/",
    ":solady/=node_modules/solady/src/",
    ":webauthn-sol/=lib/webauthn-sol/"
  ],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"InvalidSignatureType","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotImplemented","type":"error"},{"inputs":[],"name":"UnexpectedDataPassed","type":"error"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint32","name":"entityId","type":"uint32"},{"indexed":true,"internalType":"address","name":"newSigner","type":"address"},{"indexed":false,"internalType":"address","name":"previousSigner","type":"address"}],"name":"SignerTransferred","type":"event"},{"inputs":[],"name":"moduleId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onInstall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onUninstall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"replaySafeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"address","name":"account","type":"address"}],"name":"signers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"address","name":"newSigner","type":"address"}],"name":"transferSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"validateRuntime","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"entityId","type":"uint32"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"validateSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"entityId","type":"uint32"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60808060405234601557610f88908161001b8239f35b600080fdfe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a714610646575080630ab8785f146105bb578063217178fb14610525578063219336d6146104d8578063465d33e0146103ca5780634aeb3b03146103825780636d61fe70146102ee5780638a91b0e3146101e0578063a1308f27146101385763e7db7f7e1461008d57600080fd5b346101335760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576100c461078f565b6100cc610748565b906100d56107b2565b506084359067ffffffffffffffff8211610133576020926100fd6101099336906004016107d5565b92909160643591610ad9565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b600080fd5b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576101dc604051610178606082610a2f565b602d81527f616c6368656d792e73696e676c652d7369676e65722d76616c69646174696f6e60208201527f2d6d6f64756c652e312e302e30000000000000000000000000000000000000006040820152604051918291602083526020830190610803565b0390f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335760043567ffffffffffffffff81116101335761023160209136906004016107d5565b90809291810103126101335763ffffffff61024d60009261075b565b16808252816020526040822073ffffffffffffffffffffffffffffffffffffffff3316835260205273ffffffffffffffffffffffffffffffffffffffff604083205416818352826020526040832073ffffffffffffffffffffffffffffffffffffffff33168452602052604083207fffffffffffffffffffffffff0000000000000000000000000000000000000000815416905560405190815260203391a3005b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335760043567ffffffffffffffff81116101335761033f60409136906004016107d5565b90809291810103126101335760206103568261075b565b91013573ffffffffffffffffffffffffffffffffffffffff81168091036101335761038091610e2f565b005b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576103806103bc610735565b6103c461076c565b90610e2f565b346101335760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761040161078f565b610409610748565b906104126107b2565b9160843567ffffffffffffffff8111610133576104339036906004016107d5565b505060a4359067ffffffffffffffff82116101335761045b63ffffffff9236906004016107d5565b505016600052600060205273ffffffffffffffffffffffffffffffffffffffff6040600020911660005260205273ffffffffffffffffffffffffffffffffffffffff80604060002054169116036104ae57005b7fea8e4eb50000000000000000000000000000000000000000000000000000000060005260046000fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602061051d61051461078f565b60243590610965565b604051908152f35b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761055c610735565b63ffffffff61056961076c565b9116600052600060205273ffffffffffffffffffffffffffffffffffffffff60406000209116600052602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b346101335760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576105f2610735565b6024359067ffffffffffffffff8211610133576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83360301126101335760209161051d916044359160040190610862565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361013357817fab3e34c100000000000000000000000000000000000000000000000000000000602093149081156106d8575b5015158152f35b7f46c0c1b40000000000000000000000000000000000000000000000000000000081149150811561070b575b50836106d1565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610704565b6004359063ffffffff8216820361013357565b6024359063ffffffff8216820361013357565b359063ffffffff8216820361013357565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b9181601f840112156101335782359167ffffffffffffffff8311610133576020838186019501011161013357565b919082519283825260005b84811061084d5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b8060208092840101518282860101520161080e565b63ffffffff1660005260006020526040600020813573ffffffffffffffffffffffffffffffffffffffff811681036101335773ffffffffffffffffffffffffffffffffffffffff1660005260205273ffffffffffffffffffffffffffffffffffffffff60406000205416917f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c60002090610100810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020019082360382136101335761095793610bbd565b61096057600190565b600090565b9060429160405173ffffffffffffffffffffffffffffffffffffffff60208201927f71062c282d40422f744945d587dbf4ecfd4f9cfad1d35d62c944373009d961628452466040840152306060840152166080820152608081526109ca60a082610a2f565b519020907f294a8735843d4afb4f017c76faf3b7731def145ed0025fc9b1d5ce30adf113ff6000526020526040600020604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a7057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111610a7057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b63ffffffff610aed610b3a96959483610965565b9216600052600060205273ffffffffffffffffffffffffffffffffffffffff6040600020911660005260205273ffffffffffffffffffffffffffffffffffffffff60406000205416610bbd565b610b62577fffffffff0000000000000000000000000000000000000000000000000000000090565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b929192610b9282610a9f565b91610ba06040519384610a2f565b829481845281830111610133578281602093846000960137010152565b929160018310610e0557803560f81c6002811015610c645780610c9357508260011161013357610c1e92610c189160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3693019101610b86565b90610e9d565b506004811015610c6457159182610c40575b5050610c3b57600090565b600190565b73ffffffffffffffffffffffffffffffffffffffff91925081169116143880610c30565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90939190600114610cc8577f60cd402d0000000000000000000000000000000000000000000000000000000060005260046000fd5b8260011161013357610d50610d7c610d0c60009695879660017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3693019101610b86565b60405192839160208301957f1626ba7e0000000000000000000000000000000000000000000000000000000087526024840152604060448401526064830190610803565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610a2f565b51915afa3d15610dfe573d610d9081610a9f565b90610d9e6040519283610a2f565b81523d6000602083013e5b81610df0575b81610db8575090565b905060208180518101031261013357602001517f1626ba7e000000000000000000000000000000000000000000000000000000001490565b905060208151101590610daf565b6060610da9565b7f60cd402d0000000000000000000000000000000000000000000000000000000060005260046000fd5b63ffffffff166000818152602081815260408083203380855290835292819020805473ffffffffffffffffffffffffffffffffffffffff9687167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117909255915195909116855293a3565b8151919060418303610ece57610ec792506020820151906060604084015193015160001a90610ed9565b9192909190565b505060009160029190565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411610f6f579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa15610f635760005173ffffffffffffffffffffffffffffffffffffffff811615610f575790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea164736f6c634300081a000a

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a714610646575080630ab8785f146105bb578063217178fb14610525578063219336d6146104d8578063465d33e0146103ca5780634aeb3b03146103825780636d61fe70146102ee5780638a91b0e3146101e0578063a1308f27146101385763e7db7f7e1461008d57600080fd5b346101335760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576100c461078f565b6100cc610748565b906100d56107b2565b506084359067ffffffffffffffff8211610133576020926100fd6101099336906004016107d5565b92909160643591610ad9565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b600080fd5b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576101dc604051610178606082610a2f565b602d81527f616c6368656d792e73696e676c652d7369676e65722d76616c69646174696f6e60208201527f2d6d6f64756c652e312e302e30000000000000000000000000000000000000006040820152604051918291602083526020830190610803565b0390f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335760043567ffffffffffffffff81116101335761023160209136906004016107d5565b90809291810103126101335763ffffffff61024d60009261075b565b16808252816020526040822073ffffffffffffffffffffffffffffffffffffffff3316835260205273ffffffffffffffffffffffffffffffffffffffff604083205416818352826020526040832073ffffffffffffffffffffffffffffffffffffffff33168452602052604083207fffffffffffffffffffffffff0000000000000000000000000000000000000000815416905560405190815260203391a3005b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335760043567ffffffffffffffff81116101335761033f60409136906004016107d5565b90809291810103126101335760206103568261075b565b91013573ffffffffffffffffffffffffffffffffffffffff81168091036101335761038091610e2f565b005b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576103806103bc610735565b6103c461076c565b90610e2f565b346101335760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761040161078f565b610409610748565b906104126107b2565b9160843567ffffffffffffffff8111610133576104339036906004016107d5565b505060a4359067ffffffffffffffff82116101335761045b63ffffffff9236906004016107d5565b505016600052600060205273ffffffffffffffffffffffffffffffffffffffff6040600020911660005260205273ffffffffffffffffffffffffffffffffffffffff80604060002054169116036104ae57005b7fea8e4eb50000000000000000000000000000000000000000000000000000000060005260046000fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602061051d61051461078f565b60243590610965565b604051908152f35b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761055c610735565b63ffffffff61056961076c565b9116600052600060205273ffffffffffffffffffffffffffffffffffffffff60406000209116600052602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b346101335760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576105f2610735565b6024359067ffffffffffffffff8211610133576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83360301126101335760209161051d916044359160040190610862565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361013357817fab3e34c100000000000000000000000000000000000000000000000000000000602093149081156106d8575b5015158152f35b7f46c0c1b40000000000000000000000000000000000000000000000000000000081149150811561070b575b50836106d1565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610704565b6004359063ffffffff8216820361013357565b6024359063ffffffff8216820361013357565b359063ffffffff8216820361013357565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b9181601f840112156101335782359167ffffffffffffffff8311610133576020838186019501011161013357565b919082519283825260005b84811061084d5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b8060208092840101518282860101520161080e565b63ffffffff1660005260006020526040600020813573ffffffffffffffffffffffffffffffffffffffff811681036101335773ffffffffffffffffffffffffffffffffffffffff1660005260205273ffffffffffffffffffffffffffffffffffffffff60406000205416917f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c60002090610100810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020019082360382136101335761095793610bbd565b61096057600190565b600090565b9060429160405173ffffffffffffffffffffffffffffffffffffffff60208201927f71062c282d40422f744945d587dbf4ecfd4f9cfad1d35d62c944373009d961628452466040840152306060840152166080820152608081526109ca60a082610a2f565b519020907f294a8735843d4afb4f017c76faf3b7731def145ed0025fc9b1d5ce30adf113ff6000526020526040600020604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a7057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111610a7057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b63ffffffff610aed610b3a96959483610965565b9216600052600060205273ffffffffffffffffffffffffffffffffffffffff6040600020911660005260205273ffffffffffffffffffffffffffffffffffffffff60406000205416610bbd565b610b62577fffffffff0000000000000000000000000000000000000000000000000000000090565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b929192610b9282610a9f565b91610ba06040519384610a2f565b829481845281830111610133578281602093846000960137010152565b929160018310610e0557803560f81c6002811015610c645780610c9357508260011161013357610c1e92610c189160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3693019101610b86565b90610e9d565b506004811015610c6457159182610c40575b5050610c3b57600090565b600190565b73ffffffffffffffffffffffffffffffffffffffff91925081169116143880610c30565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90939190600114610cc8577f60cd402d0000000000000000000000000000000000000000000000000000000060005260046000fd5b8260011161013357610d50610d7c610d0c60009695879660017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3693019101610b86565b60405192839160208301957f1626ba7e0000000000000000000000000000000000000000000000000000000087526024840152604060448401526064830190610803565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610a2f565b51915afa3d15610dfe573d610d9081610a9f565b90610d9e6040519283610a2f565b81523d6000602083013e5b81610df0575b81610db8575090565b905060208180518101031261013357602001517f1626ba7e000000000000000000000000000000000000000000000000000000001490565b905060208151101590610daf565b6060610da9565b7f60cd402d0000000000000000000000000000000000000000000000000000000060005260046000fd5b63ffffffff166000818152602081815260408083203380855290835292819020805473ffffffffffffffffffffffffffffffffffffffff9687167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117909255915195909116855293a3565b8151919060418303610ece57610ec792506020820151906060604084015193015160001a90610ed9565b9192909190565b505060009160029190565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411610f6f579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa15610f635760005173ffffffffffffffffffffffffffffffffffffffff811615610f575790600090600090565b50600090600190600090565b6040513d6000823e3d90fd5b5050506000916003919056fea164736f6c634300081a000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.