Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19638002 | 274 days ago | Contract Creation | 0 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
Contract Source Code (Solidity Standard Json-Input format)
// 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]--; } }
// 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; }
// 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 {}
// 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; }
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;
// 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; } }
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) } }
// 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); } }
// 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); } }
// 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; } }
{ "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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
6080806040523461001657610e9f908161001c8239f35b600080fdfe60406080815260048036101561001457600080fd5b6000803560e01c80630ccab7a1146103df5780631811663f14610393578063244d6cb21461035c578063392dffaf146102da5780636d61fe70146101935780638a91b0e3146100e4578063d60b347f146100995763ecd059611461007757600080fd5b3461009657602036600319011261009657506006602092519135148152f35b80fd5b5082346100e05760203660031901126100e0576020906100d76100ba610488565b6001600160a01b0316600090815260208190526040902054151590565b90519015158152f35b5080fd5b5091602036600319011261018f57813567ffffffffffffffff811161018b57610110903690840161049e565b60201161018b5733600090815260208190526040902054156101755735835260016020528083203384526020528260018282208281550155826020528220908154908115610162575060001901905580f35b634e487b7160e01b845260119052602483fd5b815163f91bd6f160e01b81523381850152602490fd5b8380fd5b8280fd5b50919060208060031936011261018b57813567ffffffffffffffff81116102a9576101c1903690840161049e565b80839293116102ad57336000908152602081905260409020546102c457338652858252848620805460001981146102b15760010190558201829003601f1901606081126102ad5784136102a9578351610219816104cc565b81830135938482528584013583830195818752159081156102a0575b5061029257509160016060927fdaa12c36d531747b295ac442f2dc73409156b4e78117b4b178bc019014b6cf5b9483358952828252878920338a52825287892090519687825551928391015586519586528501520135923392a380f35b855163145a1fdd60e31b8152fd5b90501538610235565b8480fd5b8580fd5b634e487b7160e01b885260118652602488fd5b84516393360fbf60e01b81523381860152602490fd5b5091903461018f57608036600319011261018f576102f661046d565b60643567ffffffffffffffff81116102a9579161032a9161031d602096943690840161049e565b929091604435913561058f565b1515905061034d57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b03199061033c565b5082346100e05760203660031901126100e05760209181906001600160a01b03610384610488565b16815280845220549051908152f35b5091903461018f578160031936011261018f579181926103b161046d565b9035825260016020528282209060018060a01b03168252602052206001815491015482519182526020820152f35b508290600319926060843601126100e05760243567ffffffffffffffff9485821161018b576101208236039182011261018b5782820135916001600160a01b03831683036102a95761010481013591602219018212156102a957018281013595861161018b576024019285360384136100965750916020949161046693604435913561058f565b9051908152f35b602435906001600160a01b038216820361048357565b600080fd5b600435906001600160a01b038216820361048357565b9181601f840112156104835782359167ffffffffffffffff8311610483576020838186019501011161048357565b6040810190811067ffffffffffffffff8211176104e857604052565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176104e857604052565b90601f8019910116810190811067ffffffffffffffff8211176104e857604052565b67ffffffffffffffff81116104e857601f01601f191660200190565b9291926105648261053c565b91610572604051938461051a565b829481845281830111610483578281602093846000960137010152565b9392909281019060c0818303126104835767ffffffffffffffff9080358281116104835781019280601f85011215610483576105d2816020958681359101610558565b92848301359081116104835782019080601f830112156104835781856105fa93359101610558565b9360a082013595861515870361048357610676976000526001855260406000209060018060a01b03166000528452604060002060016040519161063c836104cc565b805483520154948082019586526040519281840152825261065c826104cc565b5193519460808301359360406060850135940135926106ce565b61067f57600190565b600090565b908151811015610695570160200190565b634e487b7160e01b600052603260045260246000fd5b60005b8381106106be5750506000910152565b81810151838201526020016106ae565b979593919096949297600197805160258110908115610a28575b50610a1f575b6040928351926106fd846104cc565b6015845261072b8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b88820152610b28565b15610a16575b61073a90610c57565b600081516002811190816109d2575b501561097157506002905b805191820391821161095b57829061076b8361053c565b926107788851948561051a565b8084526107848161053c565b8488019290601f190136843760005b8281106108d6575050506107eb602e6107f0946107d1938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906106ab565b8101601160f91b602d82015203600e81018452018261051a565b610ab5565b156108cd575b600061080f8492838751928284809451938492016106ab565b8101039060025afa156108c257610864600091825161085486805180938861084081840197888151938492016106ab565b82019089820152038781018452018261051a565b85519283928392519283916106ab565b8101039060025afa156108b8575060005196600019146108a6576108889596610c22565b908161089e575b5061089957600090565b600190565b90503861088f565b9193509193506108b594610b8e565b90565b513d6000823e3d90fd5b82513d6000823e3d90fd5b600099506107f6565b92935090916001906001600160f81b0319602b60f81b816108f78487610684565b5116036109185750602d61090b8288610684565b535b019085939291610793565b602f60f81b816109288487610684565b5116036109425750605f61093c8288610684565b5361090d565b61094c8285610684565b511660001a61093c8288610684565b634e487b7160e01b600052601160045260246000fd5b90805160018111908161098e575b50156107545760019150610754565b6000198101915081116109be57603d60f81b906001600160f81b0319906109b59084610684565b5116143861097f565b634e487b7160e01b83526011600452602483fd5b600119810191508111610a0257603d60f81b906001600160f81b0319906109f99085610684565b51161438610749565b634e487b7160e01b82526011600452602482fd5b60009a50610731565b600098506106ee565b905060201015610695576040810151610a4a906001600160f81b031916610a51565b15386106e8565b6001600160f81b0319600160f81b821601610aa257603f60fa1b600160fa1b821601610aa257601f60fb1b600160fb1b821601610a8f575b50600190565b600160fc1b9081161461067f5738610a89565b50600090565b9190820180921161095b57565b9081519181519060005b848110610ad0575050505050600190565b601781810180911161095b5783811015610b1d576001600160f81b0319610b0481610afb8587610684565b51169287610684565b511603610b1357600101610abf565b5050505050600090565b505050505050600090565b9190825192815160005b858110610b4457505050505050600190565b81610b4f8287610aa8565b1015610b1d576001600160f81b031980610b698386610684565b511690610b7f610b798489610aa8565b87610684565b511603610b1d57600101610b32565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411610b13576000948594604051936020850195865260408501526060840152608083015260a082015260a08152610be9816104fe565b519073c2b78104907f722dabac4c69f826a522b2754de45afa50610c0b610df7565b602081805181010312610483576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88211610b1d576108b595610e27565b90815115610dd157604051916060830183811067ffffffffffffffff8211176104e857604052604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408401528051926002916002850180951161095b57600394859004600281901b93906001600160fe1b0381160361095b5794610d1d610d078561053c565b94610d15604051968761051a565b80865261053c565b6020850190601f190136823792829183518401976020890192835194600085525b8a8110610d8457505050506003939495965052510680600114610d7157600214610d66575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699610d3e565b90506040516020810181811067ffffffffffffffff8211176104e8576040526000815290565b3d15610e22573d90610e088261053c565b91610e16604051938461051a565b82523d6000602084013e565b606090565b92936000959192948695604051946020860196875260408601526060850152608084015260a083015260a08252610e5d826104fe565b8314610be95751906101005afa610e72610df7565b90158015610e96575b610aa257602081805181010312610483576020015160011490565b50805115610e7b56
Deployed Bytecode
0x60406080815260048036101561001457600080fd5b6000803560e01c80630ccab7a1146103df5780631811663f14610393578063244d6cb21461035c578063392dffaf146102da5780636d61fe70146101935780638a91b0e3146100e4578063d60b347f146100995763ecd059611461007757600080fd5b3461009657602036600319011261009657506006602092519135148152f35b80fd5b5082346100e05760203660031901126100e0576020906100d76100ba610488565b6001600160a01b0316600090815260208190526040902054151590565b90519015158152f35b5080fd5b5091602036600319011261018f57813567ffffffffffffffff811161018b57610110903690840161049e565b60201161018b5733600090815260208190526040902054156101755735835260016020528083203384526020528260018282208281550155826020528220908154908115610162575060001901905580f35b634e487b7160e01b845260119052602483fd5b815163f91bd6f160e01b81523381850152602490fd5b8380fd5b8280fd5b50919060208060031936011261018b57813567ffffffffffffffff81116102a9576101c1903690840161049e565b80839293116102ad57336000908152602081905260409020546102c457338652858252848620805460001981146102b15760010190558201829003601f1901606081126102ad5784136102a9578351610219816104cc565b81830135938482528584013583830195818752159081156102a0575b5061029257509160016060927fdaa12c36d531747b295ac442f2dc73409156b4e78117b4b178bc019014b6cf5b9483358952828252878920338a52825287892090519687825551928391015586519586528501520135923392a380f35b855163145a1fdd60e31b8152fd5b90501538610235565b8480fd5b8580fd5b634e487b7160e01b885260118652602488fd5b84516393360fbf60e01b81523381860152602490fd5b5091903461018f57608036600319011261018f576102f661046d565b60643567ffffffffffffffff81116102a9579161032a9161031d602096943690840161049e565b929091604435913561058f565b1515905061034d57630b135d3f60e11b905b516001600160e01b03199091168152f35b6001600160e01b03199061033c565b5082346100e05760203660031901126100e05760209181906001600160a01b03610384610488565b16815280845220549051908152f35b5091903461018f578160031936011261018f579181926103b161046d565b9035825260016020528282209060018060a01b03168252602052206001815491015482519182526020820152f35b508290600319926060843601126100e05760243567ffffffffffffffff9485821161018b576101208236039182011261018b5782820135916001600160a01b03831683036102a95761010481013591602219018212156102a957018281013595861161018b576024019285360384136100965750916020949161046693604435913561058f565b9051908152f35b602435906001600160a01b038216820361048357565b600080fd5b600435906001600160a01b038216820361048357565b9181601f840112156104835782359167ffffffffffffffff8311610483576020838186019501011161048357565b6040810190811067ffffffffffffffff8211176104e857604052565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176104e857604052565b90601f8019910116810190811067ffffffffffffffff8211176104e857604052565b67ffffffffffffffff81116104e857601f01601f191660200190565b9291926105648261053c565b91610572604051938461051a565b829481845281830111610483578281602093846000960137010152565b9392909281019060c0818303126104835767ffffffffffffffff9080358281116104835781019280601f85011215610483576105d2816020958681359101610558565b92848301359081116104835782019080601f830112156104835781856105fa93359101610558565b9360a082013595861515870361048357610676976000526001855260406000209060018060a01b03166000528452604060002060016040519161063c836104cc565b805483520154948082019586526040519281840152825261065c826104cc565b5193519460808301359360406060850135940135926106ce565b61067f57600190565b600090565b908151811015610695570160200190565b634e487b7160e01b600052603260045260246000fd5b60005b8381106106be5750506000910152565b81810151838201526020016106ae565b979593919096949297600197805160258110908115610a28575b50610a1f575b6040928351926106fd846104cc565b6015845261072b8c8360209674113a3cb832911d113bb2b130baba34371733b2ba1160591b88820152610b28565b15610a16575b61073a90610c57565b600081516002811190816109d2575b501561097157506002905b805191820391821161095b57829061076b8361053c565b926107788851948561051a565b8084526107848161053c565b8488019290601f190136843760005b8281106108d6575050506107eb602e6107f0946107d1938a519485926c1131b430b63632b733b2911d1160991b8c850152518092602d8501906106ab565b8101601160f91b602d82015203600e81018452018261051a565b610ab5565b156108cd575b600061080f8492838751928284809451938492016106ab565b8101039060025afa156108c257610864600091825161085486805180938861084081840197888151938492016106ab565b82019089820152038781018452018261051a565b85519283928392519283916106ab565b8101039060025afa156108b8575060005196600019146108a6576108889596610c22565b908161089e575b5061089957600090565b600190565b90503861088f565b9193509193506108b594610b8e565b90565b513d6000823e3d90fd5b82513d6000823e3d90fd5b600099506107f6565b92935090916001906001600160f81b0319602b60f81b816108f78487610684565b5116036109185750602d61090b8288610684565b535b019085939291610793565b602f60f81b816109288487610684565b5116036109425750605f61093c8288610684565b5361090d565b61094c8285610684565b511660001a61093c8288610684565b634e487b7160e01b600052601160045260246000fd5b90805160018111908161098e575b50156107545760019150610754565b6000198101915081116109be57603d60f81b906001600160f81b0319906109b59084610684565b5116143861097f565b634e487b7160e01b83526011600452602483fd5b600119810191508111610a0257603d60f81b906001600160f81b0319906109f99085610684565b51161438610749565b634e487b7160e01b82526011600452602482fd5b60009a50610731565b600098506106ee565b905060201015610695576040810151610a4a906001600160f81b031916610a51565b15386106e8565b6001600160f81b0319600160f81b821601610aa257603f60fa1b600160fa1b821601610aa257601f60fb1b600160fb1b821601610a8f575b50600190565b600160fc1b9081161461067f5738610a89565b50600090565b9190820180921161095b57565b9081519181519060005b848110610ad0575050505050600190565b601781810180911161095b5783811015610b1d576001600160f81b0319610b0481610afb8587610684565b51169287610684565b511603610b1357600101610abf565b5050505050600090565b505050505050600090565b9190825192815160005b858110610b4457505050505050600190565b81610b4f8287610aa8565b1015610b1d576001600160f81b031980610b698386610684565b511690610b7f610b798489610aa8565b87610684565b511603610b1d57600101610b32565b9192937f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88411610b13576000948594604051936020850195865260408501526060840152608083015260a082015260a08152610be9816104fe565b519073c2b78104907f722dabac4c69f826a522b2754de45afa50610c0b610df7565b602081805181010312610483576020015160011490565b94939291907f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a88211610b1d576108b595610e27565b90815115610dd157604051916060830183811067ffffffffffffffff8211176104e857604052604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408401528051926002916002850180951161095b57600394859004600281901b93906001600160fe1b0381160361095b5794610d1d610d078561053c565b94610d15604051968761051a565b80865261053c565b6020850190601f190136823792829183518401976020890192835194600085525b8a8110610d8457505050506003939495965052510680600114610d7157600214610d66575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699610d3e565b90506040516020810181811067ffffffffffffffff8211176104e8576040526000815290565b3d15610e22573d90610e088261053c565b91610e16604051938461051a565b82523d6000602084013e565b606090565b92936000959192948695604051946020860196875260408601526060850152608084015260a083015260a08252610e5d826104fe565b8314610be95751906101005afa610e72610df7565b90158015610e96575b610aa257602081805181010312610483576020015160011490565b50805115610e7b56
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.