ETH Price: $3,282.61 (+1.16%)

Contract

0x8AA55d4BfAE101609078681A69B5bc3181516612
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
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
196380022024-04-12 7:21:47274 days ago1712906507  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WebAuthnSigner

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 10 : WebAuthnSigner.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "kernel/sdk/moduleBase/SignerBase.sol";
import {VALIDATION_SUCCESS, VALIDATION_FAILED} from "kernel/interfaces/IERC7579Modules.sol";
import {PackedUserOperation} from "kernel/interfaces/PackedUserOperation.sol";
import {ERC1271_MAGICVALUE, ERC1271_INVALID} from "kernel/types/Constants.sol";
import {WebAuthn} from "./WebAuthn.sol";

struct WebAuthnSignerData {
    uint256 pubKeyX;
    uint256 pubKeyY;
}

/**
 * @title WebAuthnSigner
 * @notice This signer uses the P256 curve to validate signatures.
 */
contract WebAuthnSigner is SignerBase {
    // The location of the challenge in the clientDataJSON
    uint256 constant CHALLENGE_LOCATION = 23;

    // Emitted when a bad key is provided.
    error InvalidPublicKey();

    // Emitted when the public key of a kernel is changed.
    event WebAuthnPublicKeyRegistered(
        address indexed kernel, bytes32 indexed authenticatorIdHash, uint256 pubKeyX, uint256 pubKeyY
    );

    mapping(address => uint256) public usedIds;
    // The P256 public keys of a kernel.
    mapping(bytes32 id => mapping(address kernel => WebAuthnSignerData)) public webAuthnSignerStorage;

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

    function _isInitialized(address kernel) internal view returns (bool) {
        return usedIds[kernel] > 0;
    }

    /**
     * @notice Validate a user operation.
     */
    function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        payable
        override
        returns (uint256)
    {
        return _verifySignature(id, userOp.sender, userOpHash, userOp.signature);
    }

    /**
     * @notice Verify a signature with sender for ERC-1271 validation.
     */
    function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
        external
        view
        override
        returns (bytes4)
    {
        return _verifySignature(id, sender, hash, sig) == VALIDATION_SUCCESS ? ERC1271_MAGICVALUE : ERC1271_INVALID;
    }

    /**
     * @notice Verify a signature.
     */
    function _verifySignature(bytes32 id, address sender, bytes32 hash, bytes calldata signature)
        private
        view
        returns (uint256)
    {
        // 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
        WebAuthnSignerData memory webAuthnData = webAuthnSignerStorage[id][sender];

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

        // return the validation data
        if (isValid) {
            return VALIDATION_SUCCESS;
        }

        return VALIDATION_FAILED;
    }
    /**
     * @notice Install WebAuthn signer for a kernel account.
     * @dev The kernel account need to be the `msg.sender`.
     * @dev The public key is encoded as `abi.encode(WebAuthnSignerData)` inside the data, so (uint256,uint256).
     * @dev The authenticatorIdHash is the hash of the authenticatorId. It enables to find public keys on-chain via event logs.
     */

    function _signerOninstall(bytes32 id, bytes calldata _data) internal override {
        // check if the webauthn validator is already initialized
        if (_isInitialized(msg.sender)) revert AlreadyInitialized(msg.sender);
        usedIds[msg.sender]++;
        // check validity of the public key
        (WebAuthnSignerData memory webAuthnData, bytes32 authenticatorIdHash) =
            abi.decode(_data, (WebAuthnSignerData, bytes32));
        if (webAuthnData.pubKeyX == 0 || webAuthnData.pubKeyY == 0) {
            revert InvalidPublicKey();
        }
        // Update the key (so a sstore)
        webAuthnSignerStorage[id][msg.sender] = webAuthnData;
        // And emit the event
        emit WebAuthnPublicKeyRegistered(msg.sender, authenticatorIdHash, webAuthnData.pubKeyX, webAuthnData.pubKeyY);
    }

    /**
     * @notice Uninstall WebAuthn validator for a kernel account.
     * @dev The kernel account need to be the `msg.sender`.
     */
    function _signerOnUninstall(bytes32 id, bytes calldata) internal override {
        if (!_isInitialized(msg.sender)) revert NotInitialized(msg.sender);
        delete webAuthnSignerStorage[id][msg.sender];
        usedIds[msg.sender]--;
    }
}

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

import {ISigner} from "../../interfaces/IERC7579Modules.sol";
import {PackedUserOperation} from "../../interfaces/PackedUserOperation.sol";

abstract contract SignerBase is ISigner {
    function onInstall(bytes calldata data) external payable {
        bytes32 id = bytes32(data[0:32]);
        bytes calldata _data = data[32:];
        _signerOninstall(id, _data);
    }

    function onUninstall(bytes calldata data) external payable {
        bytes32 id = bytes32(data[0:32]);
        bytes calldata _data = data[32:];
        _signerOnUninstall(id, _data);
    }

    function isModuleType(uint256 id) external pure returns (bool) {
        return id == 6;
    }

    function isInitialized(address) external view virtual returns (bool); // TODO : not sure if this is the right way to do it
    function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        payable
        virtual
        returns (uint256);
    function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
        external
        view
        virtual
        returns (bytes4);

    function _signerOninstall(bytes32 id, bytes calldata _data) internal virtual;
    function _signerOnUninstall(bytes32 id, bytes calldata _data) internal virtual;
}

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

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

uint256 constant VALIDATION_SUCCESS = 0;
uint256 constant VALIDATION_FAILED = 1;

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;
uint256 constant MODULE_TYPE_ACTION = 7;

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 validaton phase
     *         Note: solely relying on bytes32 hash and signature is not suffcient 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, bytes calldata msgData) external payable returns (bytes memory hookData);
    function postCheck(bytes calldata hookData) external payable returns (bool success);
}

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);
}

interface IAction is IModule {}

File 4 of 10 : 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 5 of 10 : Constants.sol
pragma solidity ^0.8.0;

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

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

// @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);

ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000));

PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001);
PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002);

// FLAG
ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00);
ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01);
ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02);

// TYPES, ENUM
ValidationType constant VALIDATION_TYPE_SUDO = ValidationType.wrap(0x00);
ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01);
ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02);

// ERC4337 constants
uint256 constant SIG_VALIDATION_FAILED_UINT = 1;
ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT);

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

File 6 of 10 : 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;
    }
}

File 7 of 10 : Types.sol
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 8 of 10 : Base64URL.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "openzeppelin-contracts/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 9 of 10 : 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 10 of 10 : 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;
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/kernel_v3/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "kernel/=lib/kernel_v3/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/kernel_v3/lib/solady/src/",
    "ExcessivelySafeCall/=lib/kernel_v3/lib/ExcessivelySafeCall/src/",
    "kernel_v3/=lib/kernel_v3/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidPublicKey","type":"error"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"NotInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"kernel","type":"address"},{"indexed":true,"internalType":"bytes32","name":"authenticatorIdHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pubKeyY","type":"uint256"}],"name":"WebAuthnPublicKeyRegistered","type":"event"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"checkSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"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":"checkUserOpSignature","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"kernel","type":"address"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isModuleType","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onInstall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onUninstall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"usedIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"address","name":"kernel","type":"address"}],"name":"webAuthnSignerStorage","outputs":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint256","name":"pubKeyY","type":"uint256"}],"stateMutability":"view","type":"function"}]

6080806040523461001657610e9f908161001c8239f35b600080fdfe60406080815260048036101561001457600080fd5b6000803560e01c80630ccab7a1146103df5780631811663f14610393578063244d6cb21461035c578063392dffaf146102da5780636d61fe70146101935780638a91b0e3146100e4578063d60b347f146100995763ecd059611461007757600080fd5b3461009657602036600319011261009657506006602092519135148152f35b80fd5b5082346100e05760203660031901126100e0576020906100d76100ba610488565b6001600160a01b0316600090815260208190526040902054151590565b90519015158152f35b5080fd5b5091602036600319011261018f57813567ffffffffffffffff811161018b57610110903690840161049e565b60201161018b5733600090815260208190526040902054156101755735835260016020528083203384526020528260018282208281550155826020528220908154908115610162575060001901905580f35b634e487b7160e01b845260119052602483fd5b815163f91bd6f160e01b81523381850152602490fd5b8380fd5b8280fd5b50919060208060031936011261018b57813567ffffffffffffffff81116102a9576101c1903690840161049e565b80839293116102ad57336000908152602081905260409020546102c457338652858252848620805460001981146102b15760010190558201829003601f1901606081126102ad5784136102a9578351610219816104cc565b81830135938482528584013583830195818752159081156102a0575b5061029257509160016060927fdaa12c36d531747b295ac442f2dc73409156b4e78117b4b178bc019014b6cf5b9483358952828252878920338a52825287892090519687825551928391015586519586528501520135923392a380f35b855163145a1fdd60e31b8152fd5b90501538610235565b8480fd5b8580fd5b634e487b7160e01b885260118652602488fd5b84516393360fbf60e01b81523381860152602490fd5b5091903461018f57608036600319011261018f576102f661046d565b60643567ffffffffffffffff81116102a9579161032a9161031d602096943690840161049e565b929091604435913561058f565b1515905061034d57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b03199061033c565b5082346100e05760203660031901126100e05760209181906001600160a01b03610384610488565b16815280845220549051908152f35b5091903461018f578160031936011261018f579181926103b161046d565b9035825260016020528282209060018060a01b03168252602052206001815491015482519182526020820152f35b508290600319926060843601126100e05760243567ffffffffffffffff9485821161018b576101208236039182011261018b5782820135916001600160a01b03831683036102a95761010481013591602219018212156102a957018281013595861161018b576024019285360384136100965750916020949161046693604435913561058f565b9051908152f35b602435906001600160a01b038216820361048357565b600080fd5b600435906001600160a01b038216820361048357565b9181601f840112156104835782359167ffffffffffffffff8311610483576020838186019501011161048357565b6040810190811067ffffffffffffffff8211176104e857604052565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176104e857604052565b90601f8019910116810190811067ffffffffffffffff8211176104e857604052565b67ffffffffffffffff81116104e857601f01601f191660200190565b9291926105648261053c565b91610572604051938461051a565b829481845281830111610483578281602093846000960137010152565b9392909281019060c0818303126104835767ffffffffffffffff9080358281116104835781019280601f85011215610483576105d2816020958681359101610558565b92848301359081116104835782019080601f830112156104835781856105fa93359101610558565b9360a082013595861515870361048357610676976000526001855260406000209060018060a01b03166000528452604060002060016040519161063c836104cc565b805483520154948082019586526040519281840152825261065c826104cc565b5193519460808301359360406060850135940135926106ce565b61067f57600190565b600090565b908151811015610695570160200190565b634e487b7160e01b600052603260045260246000fd5b60005b8381106106be5750506000910152565b81810151838201526020016106ae565b979593919096949297600197805160258110908115610a28575b50610a1f575b6040928351926106fd846104cc565b6015845261072b8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b88820152610b28565b15610a16575b61073a90610c57565b600081516002811190816109d2575b501561097157506002905b805191820391821161095b57829061076b8361053c565b926107788851948561051a565b8084526107848161053c565b8488019290601f190136843760005b8281106108d6575050506107eb602e6107f0946107d1938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906106ab565b8101601160f91b602d82015203600e81018452018261051a565b610ab5565b156108cd575b600061080f8492838751928284809451938492016106ab565b8101039060025afa156108c257610864600091825161085486805180938861084081840197888151938492016106ab565b82019089820152038781018452018261051a565b85519283928392519283916106ab565b8101039060025afa156108b8575060005196600019146108a6576108889596610c22565b908161089e575b5061089957600090565b600190565b90503861088f565b9193509193506108b594610b8e565b90565b513d6000823e3d90fd5b82513d6000823e3d90fd5b600099506107f6565b92935090916001906001600160f81b0319602b60f81b816108f78487610684565b5116036109185750602d61090b8288610684565b535b019085939291610793565b602f60f81b816109288487610684565b5116036109425750605f61093c8288610684565b5361090d565b61094c8285610684565b511660001a61093c8288610684565b634e487b7160e01b600052601160045260246000fd5b90805160018111908161098e575b50156107545760019150610754565b6000198101915081116109be57603d60f81b906001600160f81b0319906109b59084610684565b5116143861097f565b634e487b7160e01b83526011600452602483fd5b600119810191508111610a0257603d60f81b906001600160f81b0319906109f99085610684565b51161438610749565b634e487b7160e01b82526011600452602482fd5b60009a50610731565b600098506106ee565b905060201015610695576040810151610a4a906001600160f81b031916610a51565b15386106e8565b6001600160f81b0319600160f81b821601610aa257603f60fa1b600160fa1b821601610aa257601f60fb1b600160fb1b821601610a8f575b50600190565b600160fc1b9081161461067f5738610a89565b50600090565b9190820180921161095b57565b9081519181519060005b848110610ad0575050505050600190565b601781810180911161095b5783811015610b1d576001600160f81b0319610b0481610afb8587610684565b51169287610684565b511603610b1357600101610abf565b5050505050600090565b505050505050600090565b9190825192815160005b858110610b4457505050505050600190565b81610b4f8287610aa8565b1015610b1d576001600160f81b031980610b698386610684565b511690610b7f610b798489610aa8565b87610684565b511603610b1d57600101610b32565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411610b13576000948594604051936020850195865260408501526060840152608083015260a082015260a08152610be9816104fe565b519073c2b78104907f722dabac4c69f826a522b2754de45afa50610c0b610df7565b602081805181010312610483576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88211610b1d576108b595610e27565b90815115610dd157604051916060830183811067ffffffffffffffff8211176104e857604052604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408401528051926002916002850180951161095b57600394859004600281901b93906001600160fe1b0381160361095b5794610d1d610d078561053c565b94610d15604051968761051a565b80865261053c565b6020850190601f190136823792829183518401976020890192835194600085525b8a8110610d8457505050506003939495965052510680600114610d7157600214610d66575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699610d3e565b90506040516020810181811067ffffffffffffffff8211176104e8576040526000815290565b3d15610e22573d90610e088261053c565b91610e16604051938461051a565b82523d6000602084013e565b606090565b92936000959192948695604051946020860196875260408601526060850152608084015260a083015260a08252610e5d826104fe565b8314610be95751906101005afa610e72610df7565b90158015610e96575b610aa257602081805181010312610483576020015160011490565b50805115610e7b56

Deployed Bytecode

0x60406080815260048036101561001457600080fd5b6000803560e01c80630ccab7a1146103df5780631811663f14610393578063244d6cb21461035c578063392dffaf146102da5780636d61fe70146101935780638a91b0e3146100e4578063d60b347f146100995763ecd059611461007757600080fd5b3461009657602036600319011261009657506006602092519135148152f35b80fd5b5082346100e05760203660031901126100e0576020906100d76100ba610488565b6001600160a01b0316600090815260208190526040902054151590565b90519015158152f35b5080fd5b5091602036600319011261018f57813567ffffffffffffffff811161018b57610110903690840161049e565b60201161018b5733600090815260208190526040902054156101755735835260016020528083203384526020528260018282208281550155826020528220908154908115610162575060001901905580f35b634e487b7160e01b845260119052602483fd5b815163f91bd6f160e01b81523381850152602490fd5b8380fd5b8280fd5b50919060208060031936011261018b57813567ffffffffffffffff81116102a9576101c1903690840161049e565b80839293116102ad57336000908152602081905260409020546102c457338652858252848620805460001981146102b15760010190558201829003601f1901606081126102ad5784136102a9578351610219816104cc565b81830135938482528584013583830195818752159081156102a0575b5061029257509160016060927fdaa12c36d531747b295ac442f2dc73409156b4e78117b4b178bc019014b6cf5b9483358952828252878920338a52825287892090519687825551928391015586519586528501520135923392a380f35b855163145a1fdd60e31b8152fd5b90501538610235565b8480fd5b8580fd5b634e487b7160e01b885260118652602488fd5b84516393360fbf60e01b81523381860152602490fd5b5091903461018f57608036600319011261018f576102f661046d565b60643567ffffffffffffffff81116102a9579161032a9161031d602096943690840161049e565b929091604435913561058f565b1515905061034d57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b03199061033c565b5082346100e05760203660031901126100e05760209181906001600160a01b03610384610488565b16815280845220549051908152f35b5091903461018f578160031936011261018f579181926103b161046d565b9035825260016020528282209060018060a01b03168252602052206001815491015482519182526020820152f35b508290600319926060843601126100e05760243567ffffffffffffffff9485821161018b576101208236039182011261018b5782820135916001600160a01b03831683036102a95761010481013591602219018212156102a957018281013595861161018b576024019285360384136100965750916020949161046693604435913561058f565b9051908152f35b602435906001600160a01b038216820361048357565b600080fd5b600435906001600160a01b038216820361048357565b9181601f840112156104835782359167ffffffffffffffff8311610483576020838186019501011161048357565b6040810190811067ffffffffffffffff8211176104e857604052565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176104e857604052565b90601f8019910116810190811067ffffffffffffffff8211176104e857604052565b67ffffffffffffffff81116104e857601f01601f191660200190565b9291926105648261053c565b91610572604051938461051a565b829481845281830111610483578281602093846000960137010152565b9392909281019060c0818303126104835767ffffffffffffffff9080358281116104835781019280601f85011215610483576105d2816020958681359101610558565b92848301359081116104835782019080601f830112156104835781856105fa93359101610558565b9360a082013595861515870361048357610676976000526001855260406000209060018060a01b03166000528452604060002060016040519161063c836104cc565b805483520154948082019586526040519281840152825261065c826104cc565b5193519460808301359360406060850135940135926106ce565b61067f57600190565b600090565b908151811015610695570160200190565b634e487b7160e01b600052603260045260246000fd5b60005b8381106106be5750506000910152565b81810151838201526020016106ae565b979593919096949297600197805160258110908115610a28575b50610a1f575b6040928351926106fd846104cc565b6015845261072b8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b88820152610b28565b15610a16575b61073a90610c57565b600081516002811190816109d2575b501561097157506002905b805191820391821161095b57829061076b8361053c565b926107788851948561051a565b8084526107848161053c565b8488019290601f190136843760005b8281106108d6575050506107eb602e6107f0946107d1938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906106ab565b8101601160f91b602d82015203600e81018452018261051a565b610ab5565b156108cd575b600061080f8492838751928284809451938492016106ab565b8101039060025afa156108c257610864600091825161085486805180938861084081840197888151938492016106ab565b82019089820152038781018452018261051a565b85519283928392519283916106ab565b8101039060025afa156108b8575060005196600019146108a6576108889596610c22565b908161089e575b5061089957600090565b600190565b90503861088f565b9193509193506108b594610b8e565b90565b513d6000823e3d90fd5b82513d6000823e3d90fd5b600099506107f6565b92935090916001906001600160f81b0319602b60f81b816108f78487610684565b5116036109185750602d61090b8288610684565b535b019085939291610793565b602f60f81b816109288487610684565b5116036109425750605f61093c8288610684565b5361090d565b61094c8285610684565b511660001a61093c8288610684565b634e487b7160e01b600052601160045260246000fd5b90805160018111908161098e575b50156107545760019150610754565b6000198101915081116109be57603d60f81b906001600160f81b0319906109b59084610684565b5116143861097f565b634e487b7160e01b83526011600452602483fd5b600119810191508111610a0257603d60f81b906001600160f81b0319906109f99085610684565b51161438610749565b634e487b7160e01b82526011600452602482fd5b60009a50610731565b600098506106ee565b905060201015610695576040810151610a4a906001600160f81b031916610a51565b15386106e8565b6001600160f81b0319600160f81b821601610aa257603f60fa1b600160fa1b821601610aa257601f60fb1b600160fb1b821601610a8f575b50600190565b600160fc1b9081161461067f5738610a89565b50600090565b9190820180921161095b57565b9081519181519060005b848110610ad0575050505050600190565b601781810180911161095b5783811015610b1d576001600160f81b0319610b0481610afb8587610684565b51169287610684565b511603610b1357600101610abf565b5050505050600090565b505050505050600090565b9190825192815160005b858110610b4457505050505050600190565b81610b4f8287610aa8565b1015610b1d576001600160f81b031980610b698386610684565b511690610b7f610b798489610aa8565b87610684565b511603610b1d57600101610b32565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411610b13576000948594604051936020850195865260408501526060840152608083015260a082015260a08152610be9816104fe565b519073c2b78104907f722dabac4c69f826a522b2754de45afa50610c0b610df7565b602081805181010312610483576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88211610b1d576108b595610e27565b90815115610dd157604051916060830183811067ffffffffffffffff8211176104e857604052604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408401528051926002916002850180951161095b57600394859004600281901b93906001600160fe1b0381160361095b5794610d1d610d078561053c565b94610d15604051968761051a565b80865261053c565b6020850190601f190136823792829183518401976020890192835194600085525b8a8110610d8457505050506003939495965052510680600114610d7157600214610d66575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699610d3e565b90506040516020810181811067ffffffffffffffff8211176104e8576040526000815290565b3d15610e22573d90610e088261053c565b91610e16604051938461051a565b82523d6000602084013e565b606090565b92936000959192948695604051946020860196875260408601526060850152608084015260a083015260a08252610e5d826104fe565b8314610be95751906101005afa610e72610df7565b90158015610e96575b610aa257602081805181010312610483576020015160011490565b50805115610e7b56

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
[ 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.