OP Sepolia Testnet

Contract

0x065B633c83848Cd4D21D8827c6B6aDF807D258a8

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
213556562024-12-18 9:24:1290 days ago1734513852  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WebAuthnValidator

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 18 : WebAuthnValidator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {WebAuthn} from "./webauthn/WebAuthn.sol";
import {AbstractValidator} from "./AbstractValidator.sol";

/**
 * @title WebAuthnValidator
 * @notice This validator validates WebAuthn signatures.
 */
contract WebAuthnValidator is AbstractValidator {
    /**
     * @notice Verify a signature.
     */
    function _verifySignature(bytes memory /*context*/, bytes32 hash, bytes memory signature) override internal view returns (bool valid) {
        // decode the signature
        (bytes memory authenticatorData, string memory clientDataJSON, uint256 responseTypeLocation, uint256 r, uint256 s, bool usePrecompiled) = abi
            .decode(signature, (bytes, string, uint256, uint256, uint256, bool));

        // get the public key from storage
        (uint256 pubKeyX, uint256 pubKeyY) = abi.decode(validatorStorage[msg.sender], (uint256, uint256));

        // The location of the challenge in the clientDataJSON
        uint256 CHALLENGE_LOCATION = 23;

        // verify the signature using the signature and the public key
        valid = WebAuthn.verifySignature(
            abi.encodePacked(hash),
            authenticatorData,
            true,
            clientDataJSON,
            CHALLENGE_LOCATION,
            responseTypeLocation,
            r,
            s,
            pubKeyX,
            pubKeyY,
            usePrecompiled
        );
    }
}

File 2 of 18 : Base64.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 0x20)
            let dataPtr := data
            let endPtr := add(data, mload(data))

            // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
            // set it to zero to make sure no dirty bytes are read in that section.
            let afterPtr := add(endPtr, 0x20)
            let afterCache := mload(afterPtr)
            mstore(afterPtr, 0x00)

            // Run over the input, 3 bytes at a time
            for {

            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 byte (24 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F to bitmask the least significant 6 bits.
                // Use this as an index into the lookup table, mload an entire word
                // so the desired character is in the least significant byte, and
                // mstore8 this least significant byte into the result and continue.

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // Reset the value that was cached
            mstore(afterPtr, afterCache)

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

File 3 of 18 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.20;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 4 of 18 : MessageHashUtils.sol
// 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)
        }
    }
}

File 5 of 18 : Math.sol
// 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;
    }
}

File 6 of 18 : SignedMath.sol
// 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);
        }
    }
}

File 7 of 18 : Strings.sol
// 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));
    }
}

File 8 of 18 : AuthAccountLib.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

enum SigType {
    OneOp,
    MultiChainSource,
    MultiChainTarget,
    MultiChainMerkle
}

library AuthAccountLib {
    /**
     * @notice Parse an account signature into its type and data.
     */
    function parseAccountSig(bytes calldata accountSig) internal pure returns (SigType sigType, bytes calldata sigData) {
        sigType = SigType(uint8(bytes1(accountSig[:1])));
        sigData = accountSig[1:];
    }

    /**
     * @notice Parse a multi-chain signature into rootSig and opHash.
     */
    function parseMultiChainSig(bytes calldata sig) internal pure returns (bytes calldata rootSig, bytes32 opHash) {
        uint256 opHashOffset = sig.length - 32;
        uint256 finalOffset = opHashOffset + 32;

        rootSig = sig[:opHashOffset];
        opHash = bytes32(sig[opHashOffset:finalOffset]);
    }

    function parseMerkleTreeSig(bytes calldata sig) internal pure returns (bytes memory rootSig, bytes32 merkleRoot, bytes32[] memory merkleProof) {
        return abi.decode(sig, (bytes, bytes32, bytes32[]));
    }
}

File 9 of 18 : AuthPaymasterLib.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

library AuthPaymasterLib {
    /**
     * Parses `sig` into `accountSig` and `paymasterSigData`.
     * 
     * `sig` format:
     * |AccountSigLength:uint16|
     * |AccountSig:{AccountSigLength}bytes|
     * |PaymasterSigData:bytes|
     */
    function parseUserOpSignature(bytes calldata sig) internal pure returns (bytes calldata accountSig, bytes calldata paymasterSigData) {
        // Parse accountSig length.
        uint256 uint16Length = 2;
        uint16 accountSigLength = (uint16(uint8(sig[0])) << 8) | uint16(uint8(sig[1]));

        // Compute data field offsets.
        uint256 accountSigOffset = uint16Length;
        uint256 paymasterDataOffset = accountSigOffset + accountSigLength;

        accountSig = sig[accountSigOffset:paymasterDataOffset];
        paymasterSigData = sig[paymasterDataOffset:];
    }

    /**
     * Parses `paymasterSigData` into `paymasterSig` and `guarantorSig`.
     *
     * `paymasterSigData` format:
     * optional {
     *     |PaymasterSig:{65}bytes|
     *     optional{ |GuarantorSig:{65}bytes| }
     * }
     */
    function parsePaymasterSigData(bytes calldata paymasterSigData) internal pure returns (bytes calldata paymasterSig, bytes calldata guarantorSig) {
        // Parse paymasterSig.
        paymasterSig = paymasterSigData[0:65];

        // Parse guarantorSig.
        if (paymasterSigData.length > 65) {
            guarantorSig = paymasterSigData[65:130];
        } else {
            guarantorSig = paymasterSigData[0:0];
        }
    }
}

File 10 of 18 : AbstractValidator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {IValidator, IHook} from "./interfaces/IERC7579Modules.sol";
import {MODULE_TYPE_VALIDATOR, MODULE_TYPE_HOOK} from "./types/Constants.sol";
import {SIG_VALIDATION_FAILED_UINT, SIG_VALIDATION_SUCCESS_UINT, ERC1271_MAGICVALUE, ERC1271_INVALID} from "./types/Constants.sol";
import {PackedUserOperation} from "./interfaces/PackedUserOperation.sol";
import {WebAuthn} from "./webauthn/WebAuthn.sol";
import {ExtSigVerifier} from "./ExtSigVerifier.sol";

/**
 * @title AbstractValidator
 * @notice This is an abstract validator supporting multi-chain signatures. It
 *   can be instantiated using a signature scheme of choice.
 */
abstract contract AbstractValidator is IValidator, ExtSigVerifier {
    // Emitted when a validator is registered.
    event ValidatorRegistered(address indexed kernel);

    // The validator data of a kernel.
    mapping(address kernel => bytes validatorData) public validatorStorage;

    function onInstall(bytes calldata _data) external payable override {
        // Check if the validator is already initialized.
        if (_isInitialized(msg.sender)) revert AlreadyInitialized(msg.sender);
        // Update the validator data.
        validatorStorage[msg.sender] = _data;
        // Emit event.
        emit ValidatorRegistered(msg.sender);
    }

    function onUninstall(bytes calldata) external payable override {
        if (!_isInitialized(msg.sender)) revert NotInitialized(msg.sender);
        delete validatorStorage[msg.sender];
    }

    function isModuleType(uint256 typeID) external pure override returns (bool) {
        return typeID == MODULE_TYPE_VALIDATOR;
    }

    function isInitialized(address smartAccount) external view override returns (bool) {
        return _isInitialized(smartAccount);
    }

    function _isInitialized(address smartAccount) internal view returns (bool) {
        return validatorStorage[smartAccount].length > 0;
    }

    /**
     * @notice Validate a user operation.
     */
    function validateUserOp(PackedUserOperation calldata _userOp, bytes32 _userOpHash) external payable override returns (uint256) {
        bool valid = _validateUserOp(bytes(""), _userOp.signature, _userOpHash);
        return valid ? SIG_VALIDATION_SUCCESS_UINT : SIG_VALIDATION_FAILED_UINT;
    }

    /**
     * @notice Verify a signature with sender for ERC-1271 validation.
     */
    function isValidSignatureWithSender(address /*sender*/, bytes32 hash, bytes calldata sig) external view returns (bytes4) {
        bool valid = _validateUserOp(bytes(""), sig, hash);
        return valid ? ERC1271_MAGICVALUE : ERC1271_INVALID;
    }
}

File 11 of 18 : ExtSigVerifier.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {AuthPaymasterLib} from "../auth/AuthPaymasterLib.sol";
import {AuthAccountLib, SigType} from "../auth/AuthAccountLib.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

abstract contract ExtSigVerifier {
    function _validateUserOp(bytes memory context, bytes calldata _signature, bytes32 _userOpHash) internal view returns (bool) {
        (bytes calldata accountSig,) = AuthPaymasterLib.parseUserOpSignature(_signature);
        (SigType sigType, bytes calldata sigData) = AuthAccountLib.parseAccountSig(accountSig);

        if (sigType == SigType.OneOp) {
            // Verify standard user op signature.
            bytes32 msgHash = MessageHashUtils.toEthSignedMessageHash(_userOpHash);
            return _verifySignature(context, msgHash, sigData);

        } else if (sigType == SigType.MultiChainSource || sigType == SigType.MultiChainTarget) {
            // Verify two user op signature.

            // Parse sigData.
            (bytes calldata rootSig, bytes32 otherOpHash) = AuthAccountLib.parseMultiChainSig(sigData);

            // Compute root hash.
            bool isSourceOp = sigType == SigType.MultiChainSource;
            (bytes32 sourceOpHash, bytes32 targetOpHash) = isSourceOp ? (_userOpHash, otherOpHash) : (otherOpHash, _userOpHash);
            bytes32 rootHash = keccak256(abi.encode(sourceOpHash, targetOpHash));

            // Verify signature on root hash.
            bytes32 msgHash = MessageHashUtils.toEthSignedMessageHash(rootHash);
            return _verifySignature(context, msgHash, rootSig);

        } else if (sigType == SigType.MultiChainMerkle) {
            (bytes memory rootSig, bytes32 merkleRoot, bytes32[] memory merkleProof) = AuthAccountLib.parseMerkleTreeSig(sigData);

            bytes32 leaf = _userOpHash;

            bool success = MerkleProof.verify(merkleProof, merkleRoot, leaf);

            if (!success) {
                revert("Invalid Merkle proof");
            }

            bytes32 msgHash = MessageHashUtils.toEthSignedMessageHash(merkleRoot);
            return _verifySignature(context, msgHash, rootSig);
        }

        revert("Invalid signature type");
    }

    function _verifySignature(bytes memory context, bytes32 hash, bytes memory signature) virtual internal view returns (bool valid);
}

File 12 of 18 : IERC7579Modules.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

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

interface IModule {
    error AlreadyInitialized(address smartAccount);
    error NotInitialized(address smartAccount);

    /**
     * @dev This function is called by the smart account during installation of the module
     * @param data arbitrary data that may be required on the module during `onInstall`
     * initialization
     *
     * MUST revert on error (i.e. if module is already enabled)
     */
    function onInstall(bytes calldata data) external payable;

    /**
     * @dev This function is called by the smart account during uninstallation of the module
     * @param data arbitrary data that may be required on the module during `onUninstall`
     * de-initialization
     *
     * MUST revert on error
     */
    function onUninstall(bytes calldata data) external payable;

    /**
     * @dev Returns boolean value if module is a certain type
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     *
     * MUST return true if the module is of the given type and false otherwise
     */
    function isModuleType(uint256 moduleTypeId) external view returns (bool);

    /**
     * @dev Returns if the module was already initialized for a provided smartaccount
     */
    function isInitialized(address smartAccount) external view returns (bool);
}

interface IValidator is IModule {
    error InvalidTargetAddress(address target);

    /**
     * @dev Validates a transaction on behalf of the account.
     *         This function is intended to be called by the MSA during the ERC-4337 validation phase
     *         Note: solely relying on bytes32 hash and signature is not sufficient for some
     * validation implementations (i.e. SessionKeys often need access to userOp.calldata)
     * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.
     * The MSA MUST clean up the userOp before sending it to the validator.
     * @param userOpHash The hash of the user operation to be validated
     * @return return value according to ERC-4337
     */
    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        payable
        returns (uint256);

    /**
     * Validator can be used for ERC-1271 validation
     */
    function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data)
        external
        view
        returns (bytes4);
}

interface IExecutor is IModule {}

interface IHook is IModule {
    function preCheck(address msgSender, uint256 msgValue, bytes calldata msgData)
        external
        payable
        returns (bytes memory hookData);

    function postCheck(bytes calldata hookData) external payable;
}

interface IFallback is IModule {}

interface IPolicy is IModule {
    function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp) external payable returns (uint256);
    function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
        external
        view
        returns (uint256);
}

interface ISigner is IModule {
    function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        payable
        returns (uint256);
    function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
        external
        view
        returns (bytes4);
}

File 13 of 18 : 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 maxFeePerGas and maxPriorityFeePerGas - Same as EIP-1559 gas parameter.
 * @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; //maxPriorityFee and maxFeePerGas;
    bytes paymasterAndData;
    bytes signature;
}

File 14 of 18 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {CallType, ExecType, ExecModeSelector} from "./Types.sol";
import {PassFlag, ValidationMode, ValidationType} from "./Types.sol";
import {ValidationData} from "./Types.sol";

// --- ERC7579 calltypes ---
// Default CallType
CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);
// Batched CallType
CallType constant CALLTYPE_BATCH = CallType.wrap(0x01);
CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);
// @dev Implementing delegatecall is OPTIONAL!
// implement delegatecall with extreme care.
CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);

// --- ERC7579 exectypes ---
// @dev default behavior is to revert on failure
// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure
// Since this is value 0x00, no additional encoding is required for simple accounts
ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
// @dev account may elect to change execution behavior. For example "try exec" / "allow fail"
ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);

// --- ERC7579 mode selector ---
ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000));

// --- Kernel permission skip flags ---
PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001);
PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002);

// --- Kernel validation modes ---
ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00);
ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01);
ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02);

// --- Kernel validation types ---
ValidationType constant VALIDATION_TYPE_ROOT = ValidationType.wrap(0x00);
ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01);
ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02);

// --- storage slots ---
// bytes32(uint256(keccak256('kernel.v3.selector')) - 1)
bytes32 constant SELECTOR_MANAGER_STORAGE_SLOT = 0x7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b;
// bytes32(uint256(keccak256('kernel.v3.executor')) - 1)
bytes32 constant EXECUTOR_MANAGER_STORAGE_SLOT = 0x1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b86;
// bytes32(uint256(keccak256('kernel.v3.hook')) - 1)
bytes32 constant HOOK_MANAGER_STORAGE_SLOT = 0x4605d5f70bb605094b2e761eccdc27bed9a362d8612792676bf3fb9b12832ffc;
// bytes32(uint256(keccak256('kernel.v3.validation')) - 1)
bytes32 constant VALIDATION_MANAGER_STORAGE_SLOT = 0x7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f;
bytes32 constant ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

// --- Kernel validation nonce incremental size limit ---
uint32 constant MAX_NONCE_INCREMENT_SIZE = 10;

// -- EIP712 type hash ---
bytes32 constant ENABLE_TYPE_HASH = 0xb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505;
bytes32 constant KERNEL_WRAPPER_TYPE_HASH = 0x1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83;

// --- ERC constants ---
// ERC4337 constants
uint256 constant SIG_VALIDATION_FAILED_UINT = 1;
uint256 constant SIG_VALIDATION_SUCCESS_UINT = 0;
ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT);

// ERC-1271 constants
bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e;
bytes4 constant ERC1271_INVALID = 0xffffffff;

uint256 constant MODULE_TYPE_VALIDATOR = 1;
uint256 constant MODULE_TYPE_EXECUTOR = 2;
uint256 constant MODULE_TYPE_FALLBACK = 3;
uint256 constant MODULE_TYPE_HOOK = 4;
uint256 constant MODULE_TYPE_POLICY = 5;
uint256 constant MODULE_TYPE_SIGNER = 6;

File 15 of 18 : Types.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.23;

// Custom type for improved developer experience
type ExecMode is bytes32;

type CallType is bytes1;

type ExecType is bytes1;

type ExecModeSelector is bytes4;

type ExecModePayload is bytes22;

using {eqModeSelector as ==} for ExecModeSelector global;
using {eqCallType as ==} for CallType global;
using {notEqCallType as !=} for CallType global;
using {eqExecType as ==} for ExecType global;

function eqCallType(CallType a, CallType b) pure returns (bool) {
    return CallType.unwrap(a) == CallType.unwrap(b);
}

function notEqCallType(CallType a, CallType b) pure returns (bool) {
    return CallType.unwrap(a) != CallType.unwrap(b);
}

function eqExecType(ExecType a, ExecType b) pure returns (bool) {
    return ExecType.unwrap(a) == ExecType.unwrap(b);
}

function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) {
    return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b);
}

type ValidationMode is bytes1;

type ValidationId is bytes21;

type ValidationType is bytes1;

type PermissionId is bytes4;

type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address

type PassFlag is bytes2;

using {vModeEqual as ==} for ValidationMode global;
using {vTypeEqual as ==} for ValidationType global;
using {vIdentifierEqual as ==} for ValidationId global;
using {vModeNotEqual as !=} for ValidationMode global;
using {vTypeNotEqual as !=} for ValidationType global;
using {vIdentifierNotEqual as !=} for ValidationId global;

// nonce = uint192(key) + nonce
// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey
// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000
// key = 0x00 + 0x01 + 0x1234...ff + 0x0000
// key = 0x00 + 0x02 + ( ) + 0x000

function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
    return ValidationMode.unwrap(a) == ValidationMode.unwrap(b);
}

function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
    return ValidationMode.unwrap(a) != ValidationMode.unwrap(b);
}

function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) {
    return ValidationType.unwrap(a) == ValidationType.unwrap(b);
}

function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) {
    return ValidationType.unwrap(a) != ValidationType.unwrap(b);
}

function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) {
    return ValidationId.unwrap(a) == ValidationId.unwrap(b);
}

function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) {
    return ValidationId.unwrap(a) != ValidationId.unwrap(b);
}

type ValidationData is uint256;

type ValidAfter is uint48;

type ValidUntil is uint48;

function getValidationResult(ValidationData validationData) pure returns (address result) {
    assembly {
        result := validationData
    }
}

function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) {
    return uint256(ValidAfter.unwrap(validAfter)) << 208 | uint256(ValidUntil.unwrap(validUntil)) << 160;
}

function parseValidationData(uint256 validationData)
    pure
    returns (ValidAfter validAfter, ValidUntil validUntil, address result)
{
    assembly {
        result := validationData
        validUntil := and(shr(160, validationData), 0xffffffffffff)
        switch iszero(validUntil)
        case 1 { validUntil := 0xffffffffffff }
        validAfter := shr(208, validationData)
    }
}

File 16 of 18 : Base64URL.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Base64.sol";

library Base64URL {
    function encode(bytes memory data) internal pure returns (string memory) {
        string memory strb64 = Base64.encode(data);
        bytes memory b64 = bytes(strb64);

        // Base64 can end with "=" or "=="; Base64URL has no padding.
        uint256 equalsCount = 0;
        if (b64.length > 2 && b64[b64.length - 2] == "=") equalsCount = 2;
        else if (b64.length > 1 && b64[b64.length - 1] == "=") equalsCount = 1;

        uint256 len = b64.length - equalsCount;
        bytes memory result = new bytes(len);

        for (uint256 i = 0; i < len; i++) {
            if (b64[i] == "+") {
                result[i] = "-";
            } else if (b64[i] == "/") {
                result[i] = "_";
            } else {
                result[i] = b64[i];
            }
        }

        return string(result);
    }
}

File 17 of 18 : P256.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * Helper library for external contracts to verify P256 signatures.
 *
 */
library P256 {
    address constant DAIMO_VERIFIER = 0xc2b78104907F722DABAc4C69f826a522B2754De4;
    address constant PRECOMPILED_VERIFIER = 0x0000000000000000000000000000000000000100;

    function verifySignatureAllowMalleability(
        bytes32 message_hash,
        uint256 r,
        uint256 s,
        uint256 x,
        uint256 y,
        bool usePrecompiled
    ) internal view returns (bool) {
        bytes memory args = abi.encode(message_hash, r, s, x, y);

        if (usePrecompiled) {
            (bool success, bytes memory ret) = PRECOMPILED_VERIFIER.staticcall(args);
            if (success == false || ret.length == 0) {
                return false;
            }
            return abi.decode(ret, (uint256)) == 1;
        } else {
            (, bytes memory ret) = DAIMO_VERIFIER.staticcall(args);
            return abi.decode(ret, (uint256)) == 1;
        }
    }

    /// P256 curve order n/2 for malleability check
    uint256 constant P256_N_DIV_2 = 57896044605178124381348723474703786764998477612067880171211129530534256022184;

    function verifySignature(bytes32 message_hash, uint256 r, uint256 s, uint256 x, uint256 y, bool usePrecompiled) internal view returns (bool) {
        // check for signature malleability
        if (s > P256_N_DIV_2) {
            return false;
        }

        return verifySignatureAllowMalleability(message_hash, r, s, x, y, usePrecompiled);
    }
}

File 18 of 18 : WebAuthn.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./Base64URL.sol";
import "./P256.sol";

/**
 * Helper library for external contracts to verify WebAuthn signatures.
 *
 */
library WebAuthn {
    /// Checks whether substr occurs in str starting at a given byte offset.
    function contains(string memory substr, string memory str, uint256 location) internal pure returns (bool) {
        bytes memory substrBytes = bytes(substr);
        bytes memory strBytes = bytes(str);

        uint256 substrLen = substrBytes.length;
        uint256 strLen = strBytes.length;

        for (uint256 i = 0; i < substrLen; i++) {
            if (location + i >= strLen) {
                return false;
            }

            if (substrBytes[i] != strBytes[location + i]) {
                return false;
            }
        }

        return true;
    }

    bytes1 constant AUTH_DATA_FLAGS_UP = 0x01; // Bit 0
    bytes1 constant AUTH_DATA_FLAGS_UV = 0x04; // Bit 2
    bytes1 constant AUTH_DATA_FLAGS_BE = 0x08; // Bit 3
    bytes1 constant AUTH_DATA_FLAGS_BS = 0x10; // Bit 4

    /// Verifies the authFlags in authenticatorData. Numbers in inline comment
    /// correspond to the same numbered bullets in
    /// https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion.
    function checkAuthFlags(bytes1 flags, bool requireUserVerification) internal pure returns (bool) {
        // 17. Verify that the UP bit of the flags in authData is set.
        if (flags & AUTH_DATA_FLAGS_UP != AUTH_DATA_FLAGS_UP) {
            return false;
        }

        // 18. If user verification was determined to be required, verify that
        // the UV bit of the flags in authData is set. Otherwise, ignore the
        // value of the UV flag.
        if (requireUserVerification && (flags & AUTH_DATA_FLAGS_UV) != AUTH_DATA_FLAGS_UV) {
            return false;
        }

        // 19. If the BE bit of the flags in authData is not set, verify that
        // the BS bit is not set.
        if (flags & AUTH_DATA_FLAGS_BE != AUTH_DATA_FLAGS_BE) {
            if (flags & AUTH_DATA_FLAGS_BS == AUTH_DATA_FLAGS_BS) {
                return false;
            }
        }

        return true;
    }

    /**
     * Verifies a Webauthn P256 signature (Authentication Assertion) as described
     * in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. We do not
     * verify all the steps as described in the specification, only ones relevant
     * to our context. Please carefully read through this list before usage.
     * Specifically, we do verify the following:
     * - Verify that authenticatorData (which comes from the authenticator,
     *   such as iCloud Keychain) indicates a well-formed assertion. If
     *   requireUserVerification is set, checks that the authenticator enforced
     *   user verification. User verification should be required if,
     *   and only if, options.userVerification is set to required in the request
     * - Verifies that the client JSON is of type "webauthn.get", i.e. the client
     *   was responding to a request to assert authentication.
     * - Verifies that the client JSON contains the requested challenge.
     * - Finally, verifies that (r, s) constitute a valid signature over both
     *   the authenicatorData and client JSON, for public key (x, y).
     *
     * We make some assumptions about the particular use case of this verifier,
     * so we do NOT verify the following:
     * - Does NOT verify that the origin in the clientDataJSON matches the
     *   Relying Party's origin: It is considered the authenticator's
     *   responsibility to ensure that the user is interacting with the correct
     *   RP. This is enforced by most high quality authenticators properly,
     *   particularly the iCloud Keychain and Google Password Manager were
     *   tested.
     * - Does NOT verify That c.topOrigin is well-formed: We assume c.topOrigin
     *   would never be present, i.e. the credentials are never used in a
     *   cross-origin/iframe context. The website/app set up should disallow
     *   cross-origin usage of the credentials. This is the default behaviour for
     *   created credentials in common settings.
     * - Does NOT verify that the rpIdHash in authData is the SHA-256 hash of an
     *   RP ID expected by the Relying Party: This means that we rely on the
     *   authenticator to properly enforce credentials to be used only by the
     *   correct RP. This is generally enforced with features like Apple App Site
     *   Association and Google Asset Links. To protect from edge cases in which
     *   a previously-linked RP ID is removed from the authorised RP IDs,
     *   we recommend that messages signed by the authenticator include some
     *   expiry mechanism.
     * - Does NOT verify the credential backup state: This assumes the credential
     *   backup state is NOT used as part of Relying Party business logic or
     *   policy.
     * - Does NOT verify the values of the client extension outputs: This assumes
     *   that the Relying Party does not use client extension outputs.
     * - Does NOT verify the signature counter: Signature counters are intended
     *   to enable risk scoring for the Relying Party. This assumes risk scoring
     *   is not used as part of Relying Party business logic or policy.
     * - Does NOT verify the attestation object: This assumes that
     *   response.attestationObject is NOT present in the response, i.e. the
     *   RP does not intend to verify an attestation.
     */
    function verifySignature(
        bytes memory challenge,
        bytes memory authenticatorData,
        bool requireUserVerification,
        string memory clientDataJSON,
        uint256 challengeLocation,
        uint256 responseTypeLocation,
        uint256 r,
        uint256 s,
        uint256 x,
        uint256 y,
        bool usePrecompiled
    ) internal view returns (bool) {
        /// @notice defer the result to the end so dummy signature can go through all verification process including p256.verifySignature
        bool deferredResult = true;

        // Check that authenticatorData has good flags
        if (authenticatorData.length < 37 || !checkAuthFlags(authenticatorData[32], requireUserVerification)) {
            deferredResult = false;
        }

        // Check that response is for an authentication assertion
        string memory responseType = '"type":"webauthn.get"';
        if (!contains(responseType, clientDataJSON, responseTypeLocation)) {
            deferredResult = false;
        }

        // Check that challenge is in the clientDataJSON
        string memory challengeB64url = Base64URL.encode(challenge);
        string memory challengeProperty = string.concat('"challenge":"', challengeB64url, '"');

        if (!contains(challengeProperty, clientDataJSON, challengeLocation)) {
            deferredResult = false;
        }

        // Check that the public key signed sha256(authenticatorData || sha256(clientDataJSON))
        bytes32 clientDataJSONHash = sha256(bytes(clientDataJSON));
        bytes32 messageHash = sha256(abi.encodePacked(authenticatorData, clientDataJSONHash));

        // if responseTypeLocation is set to max, it means the signature is a dummy signature
        if (responseTypeLocation == type(uint256).max) {
            return P256.verifySignature(messageHash, r, s, x, y, false);
        }

        bool verified = P256.verifySignature(messageHash, r, s, x, y, usePrecompiled);

        if (verified && deferredResult) {
            return true;
        }
        return false;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": true,
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"InvalidTargetAddress","type":"error"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"NotInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"kernel","type":"address"}],"name":"ValidatorRegistered","type":"event"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"typeID","type":"uint256"}],"name":"isModuleType","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"isValidSignatureWithSender","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onInstall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"onUninstall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"kernel","type":"address"}],"name":"validatorStorage","outputs":[{"internalType":"bytes","name":"validatorData","type":"bytes"}],"stateMutability":"view","type":"function"}]

60808060405234610016576113ef908161001b8239f35b5f80fdfe60406080815260049081361015610014575f80fd5b5f3560e01c806322ea7134146103f25780636d61fe701461026b5780638a91b0e3146101ca578063970032031461013e578063d60b347f14610110578063ecd05961146100f05763f551e2ee14610069575f80fd5b346100ec5760603660031901126100ec57610082610456565b50604435916001600160401b0383116100ec576100a76100bd91602094369101610608565b5f84516100b3816104a4565b52602435916106bc565b156100dd57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b0319906100cc565b5f80fd5b5090346100ec5760203660031901126100ec576001602092519135148152f35b50346100ec5760203660031901126100ec57602090610135610130610456565b610666565b90519015158152f35b506003199181833601126100ec576001600160401b039281358481116100ec57610120813603928301126100ec575f8451610178816104a4565b5261010481013591602219018212156100ec5701908101359283116100ec576024019180360383136100ec576020926101b491602435916106bc565b156101c2575f905b51908152f35b6001906101bc565b509060203660031901126100ec5780356001600160401b0381116100ec576101f59036908301610608565b505061020033610666565b156102555750335f525f6020525f20610219815461046c565b908161022157005b81601f5f9311600114610232575055005b908083918252610251601f60208420940160051c840160018501610635565b5555005b602491519063f91bd6f160e01b82523390820152fd5b50602091826003193601126100ec576001600160401b039181358381116100ec576102999036908401610608565b9290916102a533610666565b6103db57335f525f86525f209383116103c857506102c3835461046c565b601f811161038f575b505f93601f831160011461032c5750928192935f92610321575b50508160011b915f199060031b1c19161790555b337fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c888532515f80a2005b013590505f806102e6565b90601f19831694845f52825f20925f905b87821061037757505083600195961061035e575b505050811b0190556102fa565b01355f19600384901b60f8161c191690555f8080610351565b8060018496829495870135815501950192019061033d565b6103b890845f52855f20601f850160051c8101918786106103be575b601f0160051c0190610635565b5f6102cc565b90915081906103ab565b604190634e487b7160e01b5f525260245ffd5b6024925051906393360fbf60e01b82523390820152fd5b50346100ec5760203660031901126100ec576001600160a01b03610414610456565b165f525f602052610426815f20610545565b90805180926020825261044881518092816020860152602086860191016105e7565b601f01601f19168101030190f35b600435906001600160a01b03821682036100ec57565b90600182811c9216801561049a575b602083101461048657565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047b565b602081019081106001600160401b038211176104bf57604052565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176104bf57604052565b606081019081106001600160401b038211176104bf57604052565b60c081019081106001600160401b038211176104bf57604052565b90601f801991011681019081106001600160401b038211176104bf57604052565b9060405191825f82546105578161046c565b908184526020946001916001811690815f146105c55750600114610587575b50505061058592500383610524565b565b5f90815285812095935091905b8183106105ad57505061058593508201015f8080610576565b85548884018501529485019487945091830191610594565b9250505061058594925060ff191682840152151560051b8201015f8080610576565b5f5b8381106105f85750505f910152565b81810151838201526020016105e9565b9181601f840112156100ec578235916001600160401b0383116100ec57602083818601950101116100ec57565b818110610640575050565b5f8155600101610635565b6001600160401b0381116104bf57601f01601f191660200190565b60018060a01b03165f525f60205261068160405f205461046c565b151590565b9291926106928261064b565b916106a06040519384610524565b8294818452818301116100ec578281602093845f960137010152565b91908015610bef5760019181831015610bef578284013560f81c61ff00853560f01c161791826002019081600211610bdb578082116100ec57610700918187610c10565b50508183116100ec57600491600285013560f81c83811015610bc85760038601935f19928381019683155f1461084457505050505061076d9293507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20923691610686565b80519160209282019060c0838584019303126100ec5783830151926001600160401b03938481116100ec5781019280603f850112156100ec576107b881878601516040809701610c28565b94848301519081116100ec5782019080603f830112156100ec57868201516107e1928601610c28565b606082015160808301519160c060a08501519401519687151588036100ec57335f525f8952610811875f20610545565b9587878051810103126100ec5789886108419b89015198015198519181830152815261083c816104d3565b610c6e565b90565b5f969495969881851494858015610bbb575b1561096e57505050602019019580871161095b5780876108769286610c10565b9790359460209889811061094a575b505061093757501561092e576108e891925b604093845190878201928352858201528481526108b3816104ee565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20933691610686565b91825183019260c0818686019503126100ec5784810151936001600160401b03948581116100ec57820181603f820112156100ec57818186896107b89401519101610c28565b6108e891610897565b602190634e487b7160e01b5f525260245ffd5b890360031b1b909416935f80610885565b601182634e487b7160e01b5f525260245ffd5b9293999197969850949350610ba8576003146109c15760405162461bcd60e51b81526020818901526016602482015275496e76616c6964207369676e6174757265207479706560501b6044820152606490fd5b6060908397969701968360028901980301126100ec5735936001600160401b03948581116100ec578201866022820112156100ec57868160236003610a099401359101610686565b926023830135926043810135908782116100ec570194876022870112156100ec57600386013595878711610b95576005928760051b9960209a8b9360409a610a558c5196840187610524565b855260238d8601928201019283116100ec57908c60238a98979695949301915b838310610b825750505050908291935f935b610b35575b5050505003610afb57507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20908051810160c0828783019203126100ec57858201518581116100ec57820181603f820112156100ec57818186896107b89401519101610c28565b835162461bcd60e51b8152908101869052601460248201527324b73b30b634b21026b2b935b63290383937b7b360611b6044820152606490fd5b909192938251851015610b7c578495508b8495831b84010151908181105f14610b6e575f528b5282895f205b9501929190879594610a87565b905f528b5282895f20610b61565b93610a8c565b823581528a9850918101918e9101610a75565b604184634e487b7160e01b5f525260245ffd5b602188634e487b7160e01b5f525260245ffd5b505f9a5060028114610856565b602184634e487b7160e01b5f525260245ffd5b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b91908201809211610bdb57565b909392938483116100ec5784116100ec578101920390565b90929192610c358161064b565b91610c436040519384610524565b8294828452828201116100ec5760206105859301906105e7565b908151811015610bef570160200190565b979593919096949297600197805160258110908115610f79575b50610f71575b604092835192610c9d846104d3565b60158452610ccb8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b8882015261106c565b15610f69575b610cda90611199565b5f8151600281119081610f39575b5015610eed57506002905b8051918203918211610bdb578290610d0a8361064b565b92610d1788519485610524565b808452610d238161064b565b8488019290601f19013684375f5b828110610e6957505050610d89602e610d8e94610d6f938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906105e7565b8101601160f91b602d82015203600e810184520182610524565b610ffc565b15610e61575b5f610dac8492838751928284809451938492016105e7565b8101039060025afa15610e5757610e005f918251610df0868051809388610ddc81840197888151938492016105e7565b820190898201520387810184520182610524565b85519283928392519283916105e7565b8101039060025afa15610e4e57505f51965f1914610e3f57610e229596611164565b9081610e37575b50610e32575f90565b600190565b90505f610e29565b919350919350610841946110d1565b513d5f823e3d90fd5b82513d5f823e3d90fd5b5f9950610d94565b92935090916001906001600160f81b0319602b60f81b81610e8a8487610c5d565b511603610eab5750602d610e9e8288610c5d565b535b019085939291610d31565b602f60f81b81610ebb8487610c5d565b511603610ed55750605f610ecf8288610c5d565b53610ea0565b610edf8285610c5d565b51165f1a610ecf8288610c5d565b908051600181119081610f0a575b5015610cf35760019150610cf3565b5f19810191508111610bdb57603d60f81b906001600160f81b031990610f309084610c5d565b5116145f610efb565b600119810191508111610bdb57603d60f81b906001600160f81b031990610f609085610c5d565b5116145f610ce8565b5f9a50610cd1565b5f9850610c8e565b905060201015610bef576040810151610f9b906001600160f81b031916610fa2565b155f610c88565b6001600160f81b0319600160f81b821601610ff757603f60fa1b600160fa1b821601610ff757601f60fb1b600160fb1b821601610fe0575b50600190565b600160fc1b90811614610ff3575f610fda565b5f90565b505f90565b908151918151905f5b848110611016575050505050600190565b6017818101809111610bdb5783811015611062576001600160f81b031961104a816110418587610c5d565b51169287610c5d565b51160361105957600101611005565b50505050505f90565b5050505050505f90565b919082519281515f5b85811061108757505050505050600190565b816110928287610c03565b1015611062576001600160f81b0319806110ac8386610c5d565b5116906110c26110bc8489610c03565b87610c5d565b51160361106257600101611075565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411611059575f948594604051936020850195865260408501526060840152608083015260a082015260a0815261112b81610509565b519073c2b78104907f722dabac4c69f826a522b2754de45afa5061114d611313565b6020818051810103126100ec576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a882116110625761084195611342565b908151156112ff57604051916111ae836104ee565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604084015280519260029160028501809511610bdb57600394859004600281901b93906001600160fe1b03811603610bdb579461124e6112388561064b565b946112466040519687610524565b80865261064b565b6020850190601f1901368237928291835184019760208901928351945f85525b8a81106112b2575050505060039394959650525106806001146112a057600214611296575090565b603d905f19015390565b50603d90815f19820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c16870101518785015316840101518582015301969961126e565b905060405161130d816104a4565b5f815290565b3d1561133d573d906113248261064b565b916113326040519384610524565b82523d5f602084013e565b606090565b92935f959192948695604051946020860196875260408601526060850152608084015260a083015260a0825261137782610509565b831461112b5751906101005afa61138c611313565b901580156113b0575b610ff7576020818051810103126100ec576020015160011490565b5080511561139556fea2646970667358221220191125a7587dc583ebfb366c2669d2554a0ffb0308f5a9ab2d5e4e03b5d8cac664736f6c63430008180033

Deployed Bytecode

0x60406080815260049081361015610014575f80fd5b5f3560e01c806322ea7134146103f25780636d61fe701461026b5780638a91b0e3146101ca578063970032031461013e578063d60b347f14610110578063ecd05961146100f05763f551e2ee14610069575f80fd5b346100ec5760603660031901126100ec57610082610456565b50604435916001600160401b0383116100ec576100a76100bd91602094369101610608565b5f84516100b3816104a4565b52602435916106bc565b156100dd57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b0319906100cc565b5f80fd5b5090346100ec5760203660031901126100ec576001602092519135148152f35b50346100ec5760203660031901126100ec57602090610135610130610456565b610666565b90519015158152f35b506003199181833601126100ec576001600160401b039281358481116100ec57610120813603928301126100ec575f8451610178816104a4565b5261010481013591602219018212156100ec5701908101359283116100ec576024019180360383136100ec576020926101b491602435916106bc565b156101c2575f905b51908152f35b6001906101bc565b509060203660031901126100ec5780356001600160401b0381116100ec576101f59036908301610608565b505061020033610666565b156102555750335f525f6020525f20610219815461046c565b908161022157005b81601f5f9311600114610232575055005b908083918252610251601f60208420940160051c840160018501610635565b5555005b602491519063f91bd6f160e01b82523390820152fd5b50602091826003193601126100ec576001600160401b039181358381116100ec576102999036908401610608565b9290916102a533610666565b6103db57335f525f86525f209383116103c857506102c3835461046c565b601f811161038f575b505f93601f831160011461032c5750928192935f92610321575b50508160011b915f199060031b1c19161790555b337fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c888532515f80a2005b013590505f806102e6565b90601f19831694845f52825f20925f905b87821061037757505083600195961061035e575b505050811b0190556102fa565b01355f19600384901b60f8161c191690555f8080610351565b8060018496829495870135815501950192019061033d565b6103b890845f52855f20601f850160051c8101918786106103be575b601f0160051c0190610635565b5f6102cc565b90915081906103ab565b604190634e487b7160e01b5f525260245ffd5b6024925051906393360fbf60e01b82523390820152fd5b50346100ec5760203660031901126100ec576001600160a01b03610414610456565b165f525f602052610426815f20610545565b90805180926020825261044881518092816020860152602086860191016105e7565b601f01601f19168101030190f35b600435906001600160a01b03821682036100ec57565b90600182811c9216801561049a575b602083101461048657565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047b565b602081019081106001600160401b038211176104bf57604052565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176104bf57604052565b606081019081106001600160401b038211176104bf57604052565b60c081019081106001600160401b038211176104bf57604052565b90601f801991011681019081106001600160401b038211176104bf57604052565b9060405191825f82546105578161046c565b908184526020946001916001811690815f146105c55750600114610587575b50505061058592500383610524565b565b5f90815285812095935091905b8183106105ad57505061058593508201015f8080610576565b85548884018501529485019487945091830191610594565b9250505061058594925060ff191682840152151560051b8201015f8080610576565b5f5b8381106105f85750505f910152565b81810151838201526020016105e9565b9181601f840112156100ec578235916001600160401b0383116100ec57602083818601950101116100ec57565b818110610640575050565b5f8155600101610635565b6001600160401b0381116104bf57601f01601f191660200190565b60018060a01b03165f525f60205261068160405f205461046c565b151590565b9291926106928261064b565b916106a06040519384610524565b8294818452818301116100ec578281602093845f960137010152565b91908015610bef5760019181831015610bef578284013560f81c61ff00853560f01c161791826002019081600211610bdb578082116100ec57610700918187610c10565b50508183116100ec57600491600285013560f81c83811015610bc85760038601935f19928381019683155f1461084457505050505061076d9293507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20923691610686565b80519160209282019060c0838584019303126100ec5783830151926001600160401b03938481116100ec5781019280603f850112156100ec576107b881878601516040809701610c28565b94848301519081116100ec5782019080603f830112156100ec57868201516107e1928601610c28565b606082015160808301519160c060a08501519401519687151588036100ec57335f525f8952610811875f20610545565b9587878051810103126100ec5789886108419b89015198015198519181830152815261083c816104d3565b610c6e565b90565b5f969495969881851494858015610bbb575b1561096e57505050602019019580871161095b5780876108769286610c10565b9790359460209889811061094a575b505061093757501561092e576108e891925b604093845190878201928352858201528481526108b3816104ee565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20933691610686565b91825183019260c0818686019503126100ec5784810151936001600160401b03948581116100ec57820181603f820112156100ec57818186896107b89401519101610c28565b6108e891610897565b602190634e487b7160e01b5f525260245ffd5b890360031b1b909416935f80610885565b601182634e487b7160e01b5f525260245ffd5b9293999197969850949350610ba8576003146109c15760405162461bcd60e51b81526020818901526016602482015275496e76616c6964207369676e6174757265207479706560501b6044820152606490fd5b6060908397969701968360028901980301126100ec5735936001600160401b03948581116100ec578201866022820112156100ec57868160236003610a099401359101610686565b926023830135926043810135908782116100ec570194876022870112156100ec57600386013595878711610b95576005928760051b9960209a8b9360409a610a558c5196840187610524565b855260238d8601928201019283116100ec57908c60238a98979695949301915b838310610b825750505050908291935f935b610b35575b5050505003610afb57507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20908051810160c0828783019203126100ec57858201518581116100ec57820181603f820112156100ec57818186896107b89401519101610c28565b835162461bcd60e51b8152908101869052601460248201527324b73b30b634b21026b2b935b63290383937b7b360611b6044820152606490fd5b909192938251851015610b7c578495508b8495831b84010151908181105f14610b6e575f528b5282895f205b9501929190879594610a87565b905f528b5282895f20610b61565b93610a8c565b823581528a9850918101918e9101610a75565b604184634e487b7160e01b5f525260245ffd5b602188634e487b7160e01b5f525260245ffd5b505f9a5060028114610856565b602184634e487b7160e01b5f525260245ffd5b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b91908201809211610bdb57565b909392938483116100ec5784116100ec578101920390565b90929192610c358161064b565b91610c436040519384610524565b8294828452828201116100ec5760206105859301906105e7565b908151811015610bef570160200190565b979593919096949297600197805160258110908115610f79575b50610f71575b604092835192610c9d846104d3565b60158452610ccb8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b8882015261106c565b15610f69575b610cda90611199565b5f8151600281119081610f39575b5015610eed57506002905b8051918203918211610bdb578290610d0a8361064b565b92610d1788519485610524565b808452610d238161064b565b8488019290601f19013684375f5b828110610e6957505050610d89602e610d8e94610d6f938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906105e7565b8101601160f91b602d82015203600e810184520182610524565b610ffc565b15610e61575b5f610dac8492838751928284809451938492016105e7565b8101039060025afa15610e5757610e005f918251610df0868051809388610ddc81840197888151938492016105e7565b820190898201520387810184520182610524565b85519283928392519283916105e7565b8101039060025afa15610e4e57505f51965f1914610e3f57610e229596611164565b9081610e37575b50610e32575f90565b600190565b90505f610e29565b919350919350610841946110d1565b513d5f823e3d90fd5b82513d5f823e3d90fd5b5f9950610d94565b92935090916001906001600160f81b0319602b60f81b81610e8a8487610c5d565b511603610eab5750602d610e9e8288610c5d565b535b019085939291610d31565b602f60f81b81610ebb8487610c5d565b511603610ed55750605f610ecf8288610c5d565b53610ea0565b610edf8285610c5d565b51165f1a610ecf8288610c5d565b908051600181119081610f0a575b5015610cf35760019150610cf3565b5f19810191508111610bdb57603d60f81b906001600160f81b031990610f309084610c5d565b5116145f610efb565b600119810191508111610bdb57603d60f81b906001600160f81b031990610f609085610c5d565b5116145f610ce8565b5f9a50610cd1565b5f9850610c8e565b905060201015610bef576040810151610f9b906001600160f81b031916610fa2565b155f610c88565b6001600160f81b0319600160f81b821601610ff757603f60fa1b600160fa1b821601610ff757601f60fb1b600160fb1b821601610fe0575b50600190565b600160fc1b90811614610ff3575f610fda565b5f90565b505f90565b908151918151905f5b848110611016575050505050600190565b6017818101809111610bdb5783811015611062576001600160f81b031961104a816110418587610c5d565b51169287610c5d565b51160361105957600101611005565b50505050505f90565b5050505050505f90565b919082519281515f5b85811061108757505050505050600190565b816110928287610c03565b1015611062576001600160f81b0319806110ac8386610c5d565b5116906110c26110bc8489610c03565b87610c5d565b51160361106257600101611075565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411611059575f948594604051936020850195865260408501526060840152608083015260a082015260a0815261112b81610509565b519073c2b78104907f722dabac4c69f826a522b2754de45afa5061114d611313565b6020818051810103126100ec576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a882116110625761084195611342565b908151156112ff57604051916111ae836104ee565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604084015280519260029160028501809511610bdb57600394859004600281901b93906001600160fe1b03811603610bdb579461124e6112388561064b565b946112466040519687610524565b80865261064b565b6020850190601f1901368237928291835184019760208901928351945f85525b8a81106112b2575050505060039394959650525106806001146112a057600214611296575090565b603d905f19015390565b50603d90815f19820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c16870101518785015316840101518582015301969961126e565b905060405161130d816104a4565b5f815290565b3d1561133d573d906113248261064b565b916113326040519384610524565b82523d5f602084013e565b606090565b92935f959192948695604051946020860196875260408601526060850152608084015260a083015260a0825261137782610509565b831461112b5751906101005afa61138c611313565b901580156113b0575b610ff7576020818051810103126100ec576020015160011490565b5080511561139556fea2646970667358221220191125a7587dc583ebfb366c2669d2554a0ffb0308f5a9ab2d5e4e03b5d8cac664736f6c63430008180033

Block Transaction Difficulty 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.