Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 362469591 | 201 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
UniversalGaslessDelegate
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> pragma solidity 0.8.27; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { ERC7579Utils, Execution, Mode, CallType, ExecType, ModeSelector } from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol"; import { IERC7821 } from "./interface/IERC7821.sol"; import { TokenReceiver } from "./mixins/TokenReceiver.sol"; import { TypedAuthorization } from "./mixins/TypedAuthorization.sol"; import { NonceBitmap } from "./mixins/NonceBitmap.sol"; import { NonceStorage } from "./library/NonceStorageStruct.sol"; import { LibErrors } from "./library/LibErrors.sol"; import { IKillSwitch } from "./interface/IKillSwitch.sol"; /** * @title UniversalGaslessDelegate * @notice An EIP-7702 compatible delegate contract for enabling gasless transactions through delegation. This * contract implements a pattern where logic can execute on behalf of users who have signed authorized payload. * * @dev Implements flexible standards such as EIP-7821 to enhance the EOA experience with contract functionality. It * allows third parties to submit transactions for execution on behalf of users (i.e. gasless operations), as * long as users have provided the necessary authorization. * * Core Features: * - Leverages on EIP-7702 for delegate-based transaction execution * - Supports EIP-7579/EIP-7821 execution modes for single and batch transactions (see {supportsExecutionMode}) * - Integrates EIP-712 typed data signing for structured transaction authorization * - Implements unordered nonces for authorization replay protection * - Provides ERC-1271 signature validation compatibility for existing protocols * - Includes token receiver capabilities (ERC-721 and ERC-1155) * - Emergency pause functionality via KillSwitch contract * * @custom:security-contact [email protected] */ contract UniversalGaslessDelegate is IERC1271, IERC7821, NonceBitmap, TokenReceiver, TypedAuthorization { // ============================================================= // CONSTANTS / IMMUTABLE // ============================================================= /** * @notice The address of the implementation contract * @dev This is used to detect direct calls to the implementation contract. It is set to the address of the * implementation contract at deployment time. */ address private immutable __implementation = address(this); // solhint-disable-line immutable-vars-naming /** * @dev Storage location for the nonce bitmap. Derived from performing the following operation: * keccak256(abi.encode(uint256(keccak256("fireblocks.global.security.nonces")) - 1)) & ~bytes32(uint256(0xff)) */ bytes32 private constant _NONCE_STORAGE_LOCATION = 0xb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab700; /** * @notice Reference to the KillSwitch contract that can pause the Universal Gasless Delegate functionality * @dev This immutable reference points to a contract implementing the IKillSwitch interface * that can pause operations in case of emergencies. The contract is checked for validity * and unpaused status during construction. */ IKillSwitch private immutable _KILLSWITCH_CONTRACT; /** * @notice Enumeration of the different execution modes supported by the contract * @dev These values correspond to the execution modes defined in {supportsExecutionMode}, with INVALID as the * default 0 state * * - INVALID: Represents an invalid/unsupported execution mode (0) * - SINGLE_CALL_OPDATA_AUTH: Single call with authorization via opData (1) * - BATCH_CALL_OPDATA_AUTH: Batch call with authorization via optional opData (2) * - BATCH_CALL: Batch call with self-call authorization (3) */ enum ExecutionModeId { // 0: Invalid mode INVALID, // 1: CallType = Single (0x00), ExecType = Revert (0x00), ModeSelector = Auth via opData (0x78210001) SINGLE_CALL_OPDATA_AUTH, // 2: CallType = Batch (0x01), ExecType = Revert (0x00), ModeSelector = Auth via opData (0x78210001) BATCH_CALL_OPDATA_AUTH, // 3: CallType = Batch (0x01), ExecType = Revert (0x00), ModeSelector = Default (0x00000000) BATCH_CALL } // ============================================================= // STATE STORAGE // // This contract follows ERC-7201 for Namespaced storage // Global storage: // - See {_NONCE_STORAGE_LOCATION} for NonceStorage // ============================================================= // ============================================================= // EVENTS // ============================================================= // ============================================================= // MODIFIERS // ============================================================= /** * @notice This modifier is used to ensure that the function is called through a proxy, which in the EIP-7702 * context means that the function is called on a Delegated EOA. * @dev Prevents direct calls to the implementation. */ modifier onlyProxy() { if (address(this) == __implementation) revert LibErrors.UnauthorizedCallContext(); _; } /** * @notice Restricts function access to calls originating solely from the contract itself * @dev Reverts with {LibErrors.UnauthorizedCaller} if msg.sender is not the Delegated EOA itself, in either the * EOA or contract context. */ modifier onlySelf() { if (msg.sender != address(this)) revert LibErrors.UnauthorizedCaller(); _; } /** * @notice This modifier ensures that the contract is not paused via the KillSwitch * @dev Reverts if the KillSwitch contract indicates the system is paused * This modifier is used to protect state-modifying functions from being executed during * emergency situations. */ modifier whenNotPaused() { if (_KILLSWITCH_CONTRACT.paused()) revert LibErrors.EnforcedPause(); _; } // ============================================================= // FUNCTIONS // ============================================================= /** * @notice Initializes the 7702 delegate implementation contract * * @dev Calling Conditions: * * - `killswitchContract` must not be the zero address * - `killswitchContract` must implement {IKillSwitch} * - `killswitchContract` must not be in paused state * * Reverts with: * - no error data (i.e. standard `revert()`) if the contract does not return a bool value on the * static-call to `paused()` * - `InvalidImplementation()` if the contract is paused * @param killswitchContract Address of the killswitch contract */ constructor(address killswitchContract) TypedAuthorization() { _KILLSWITCH_CONTRACT = IKillSwitch(killswitchContract); // check if it is a valid IKillSwitch contract that is not paused require(!_KILLSWITCH_CONTRACT.paused(), LibErrors.InvalidImplementation()); } // ==================== EXTERNAL AND PUBLIC ==================== /** * @notice Allows direct ETH transfers to the contract * @dev Executed when the contract receives a plain ETH transfer (empty calldata) * * Calling Conditions: * - The function should be called in the context of the Delegated EOA. Calling it directly on the implementation * address will revert due to the `onlyProxy` check. */ receive() external payable onlyProxy { } /** * @notice Handles non-matching function calls with ETH value * @dev Executed when the contract receives a call with non-empty calldata that doesn't match any function. * Ensures backward compatibility with EOA-like behavior for receiving transactions with arbitrary calldata, * like strings on a "value with memo" pattern. * * Calling Conditions: * - The function should be called in the context of the Delegated EOA. Calling it directly on the implementation * address will revert due to the `onlyProxy` check. * * NOTE: Using payable fallback functions for receiving Ether is not recommended, since when calldata is present, * the fallback is invoked and would not fail for interface confusions on the part of the sender. This fallback * exists primarily to ensure backward compatibility with standard EOA behavior. */ fallback() external payable onlyProxy { } /** * @notice Executes one or more calls on behalf of this Delegated EOA, supporting both single and batch operations * with an optional authorization mechanism. The caller can be either the Delegated EOA itself or another account * provided that the latter has a valid signature for the execution(s) to be made. * * @dev Processes execution requests according to the EIP-7579 and EIP-7821 specification, which define the mode * format and execution data structure. This function supports three different execution modes as detailed in * {supportsExecutionMode}. * * The `executionData` parameter follows EIP-7821 encoding rules: * - For modes with opData for authorization (SINGLE_CALL_OPDATA_AUTH and BATCH_CALL_OPDATA_AUTH) the following * encoding is expected `abi.encode(sobExecutionData, opData)`, where: * - in SINGLE_CALL_OPDATA_AUTH, `sobExecutionData` is abi.encodePacked(target, value, callData) * - in BATCH_CALL_OPDATA_AUTH, `sobExecutionData` is abi.encode(calls) * - `opData` is abi.encodePacked(nonce, deadline, signature) * - For self-call mode (BATCH_CALL): `abi.encode(calls)` with no optional `opData` * * Authorization flow: * * Note that while for mode BATCH_CALL_OPDATA_AUTH, opData is optional (fallback to `msg.sender` verification), * for mode SINGLE_CALL_OPDATA_AUTH, opData is required (no fallback to `msg.sender`). For a single call of this * type, the EOA should be making the call to target directly and not through the delegate contract. * * 1. For modes with opData authorization (SINGLE_CALL_OPDATA_AUTH and BATCH_CALL_OPDATA_AUTH): * - Calculate authorization digest using EIP-712 typed data signing * - Validate that the nonce is not already used * - Verify the signature has not expired (current block timestamp <= deadline) * - Verify the caller matches the relayer in the signed authorization * - Verify signature matches the Delegated EOA's * 2. For self-call mode (BATCH_CALL only): * - Verify caller is the delegated EOA itself (`msg.sender == address(this)`) * * Note: This implementation does NOT perform the target replacement gas optimization listed in EIP-7821. * Explicitly, {_call} will NOT replace `address(0)` with `address(this)` as the `target` parameter. * * Note: The ERC7579Utils.decodeBatch function performs validation and will throw * {ERC7579DecodingError} if the input is not properly formatted. * * Calling Conditions: * - The function should be called in the context of the Delegated EOA. Calling it directly on the implementation * address will revert. (checked by `onlyProxy`) * - The implementation contract should not be paused. (checked by `whenNotPaused`) * - If the target of the execution is the Delegated EOA itself, it can only call the `invalidateNonce` function. * * @param mode The execution mode that defines how the execution data should be processed * @param executionData The encoded execution data and optional authorization data (opData) */ function execute(bytes32 mode, bytes calldata executionData) external payable whenNotPaused onlyProxy { // Decode the execution data according to the mode ExecutionModeId modeId = _executionModeId(mode); // Revert if mode is not supported if (modeId == ExecutionModeId.INVALID) _determineExecutionModeRevertCause(mode); bytes calldata sobExecutionData; bytes calldata opData; (sobExecutionData, opData) = _extractExecAndOpData(executionData); // Check if optional opData is present. If not, we rely on the caller being the Delegated EOA itself for auth if (opData.length != 0) { // Decode opData to extract nonce, deadline and signature (uint256 nonce, uint256 deadline, bytes calldata signature) = _decodeOpData(opData); // Check if signature has expired require(block.timestamp <= deadline, LibErrors.ExpiredSignature(deadline)); // irrespective of single or batch, the nonce is always used on modes with opData auth _useUnorderedNonce(nonce); if (modeId == ExecutionModeId.SINGLE_CALL_OPDATA_AUTH) { // Perform authentication using opData and execute single call (address target, uint256 value, bytes calldata callData) = ERC7579Utils.decodeSingle(sobExecutionData); // create AuthorizedExecutions EIP712 hash bytes32 sDigest = _hashTypedSingleExecutionAuthorization(mode, target, value, callData, nonce, deadline, msg.sender); //validate signature require(address(this) == ECDSA.recover(sDigest, signature), LibErrors.UnauthorizedExecution()); // Execute the call _call(target, value, callData); return; } if (modeId == ExecutionModeId.BATCH_CALL_OPDATA_AUTH) { // Perform authentication using opData and execute batch calls Execution[] calldata executionBatch = ERC7579Utils.decodeBatch(sobExecutionData); // create AuthorizedExecutions EIP712 hash bytes32 bDigest = _hashTypedBatchExecutionAuthorization(mode, executionBatch, nonce, deadline, msg.sender); //validate signature require(address(this) == ECDSA.recover(bDigest, signature), LibErrors.UnauthorizedExecution()); // Execute the batch calls _execBatch(executionBatch); return; } // BATCH_CALL mode does not support an opData component if (modeId == ExecutionModeId.BATCH_CALL) revert LibErrors.UnauthorizedExecution(); } else { require(msg.sender == address(this), LibErrors.UnauthorizedCaller()); // For mode SINGLE_CALL_OPDATA_AUTH, opData is required for authorization if (modeId == ExecutionModeId.SINGLE_CALL_OPDATA_AUTH) revert LibErrors.UnauthorizedExecution(); // Evaluate modes BATCH_CALL_OPDATA_AUTH and BATCH_CALL under no opData, self-call authorization Execution[] calldata executionBatch = ERC7579Utils.decodeBatch(executionData); // Execute the batch calls _execBatch(executionBatch); return; } } /** * @notice This function marks a nonce as used * @dev This function is used to invalidate a nonce * * Calling Conditions: * - The caller must be the Delegated EOA or the contract itself (checked by `onlySelf`) * - If the contract context is paused, the call must come from the Delegated EOA directly * * Reverts with {LibErrors.InvalidNonce} if the nonce has already been used. * * @param nonce The nonce to invalidate */ function invalidateNonce(uint256 nonce) external override onlyProxy onlySelf { _useUnorderedNonce(nonce); } /** * @notice Returns the fields and values that describe the domain separator to be used as part of EIP-712 * signatures verified by this contract. * * @dev This function overrides {TypedAuthorization.eip712Domain()} to ensure it can only be called in the context * of a delegated EOA (via proxy). Calling it directly on the implementation address will revert with * {LibErrors.UnauthorizedCallContext}. */ function eip712Domain() public view virtual override onlyProxy returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return super.eip712Domain(); } /** * @inheritdoc NonceBitmap */ function getNonceBitmap(uint248 wordPos) public view override onlyProxy returns (uint256 bitmap) { return super.getNonceBitmap(wordPos); } /** * @inheritdoc NonceBitmap */ function isNonceUsed(uint256 nonce) public view override onlyProxy returns (bool isUsed) { return super.isNonceUsed(nonce); } /** * @notice This function provides a standard method for external contracts to validate a signature for a given * hash, ensuring that such signatures have been created by the Delegated EOA. * * It also provides legacy (pre EIP-7702) compatibility with the ERC-1271 standard for signature validation, where * protocols might choose to validate signatures using this function, if they find in their logic that it is the * way to do it where the account has code. * * @dev Validates if the provided signature is valid for the given data hash and attributable to the Delegated EOA. * This function is provided for compliance with the ERC-1271 standard for signature validation. * * Calling Conditions: * * - The function should be called in the context of the Delegated EOA. Calling it directly on the implementation * address will revert. * * @param _hash Hash of the data to be signed * @param _signature Signature byte array associated with the hash * @return magicValue The function selector if signature is valid, or 0xffffffff if invalid */ function isValidSignature( bytes32 _hash, bytes calldata _signature ) external view onlyProxy returns (bytes4 magicValue) { if (_isValidRawSignature(_hash, _signature)) { return IERC1271.isValidSignature.selector; } else { return 0xffffffff; } } /** * @notice Returns whether the delegate contract is currently paused * @dev This function checks the pause state of the KillSwitch contract. Unlike most functions, * it can be called both on the implementation contract and on delegated EOAs, as it should convey the same * meaning. It signals if delegate implementation is safe to use. * * @return isPausedState True if the contract is paused via the KillSwitch, false otherwise */ function isPaused() external view returns (bool isPausedState) { return _KILLSWITCH_CONTRACT.paused(); } /** * @notice This function is provided for frontends to detect support. It checks if the contract supports * a specific execution mode. * * @dev Determines whether the contract supports the specified execution mode. Supported execution modes are * detailed in the table below: * * ``` * +------------------+----------+----------+------------+-------------------+-------------+ * | Mode ID | CallType | ExecType | Unused | ModeSelector | ModePayload | * | | (1 byte) | (1 byte) | (4 bytes) | (4 bytes) | (22 bytes) | * +------------------+----------+----------+------------+-------------------+-------------+ * | SINGLE_CALL_ | 0x00 | 0x00 | 0x00000000 | 0x78210001 | ANY | * | OPDATA_AUTH (1) | (Single) | (Revert) | (Empty) | (Auth via opData) | | * +------------------+----------+----------+------------+-------------------+-------------+ * | BATCH_CALL_ | 0x01 | 0x00 | 0x00000000 | 0x78210001 | ANY | * | OPDATA_AUTH (2) | (Batch) | (Revert) | (Empty) | (Auth via opData) | | * +------------------+----------+----------+------------+-------------------+-------------+ * | BATCH_CALL | 0x01 | 0x00 | 0x00000000 | 0x00000000 | ANY | * | (3) | (Batch) | (Revert) | (Empty) | (Default) | | * +------------------+----------+----------+------------+-------------------+-------------+ * ``` * * @param mode The fully-qualified execution mode to check * @return isSupported True if the mode is supported, false otherwise */ function supportsExecutionMode(bytes32 mode) external pure returns (bool isSupported) { return _executionModeId(mode) != ExecutionModeId.INVALID; } /** * @notice This function can be queried to check if the contract implements a specific interface * @dev Interface detection as per ERC-165 standard * * Calling Conditions: * * - The function should be called in the context of the Delegated EOA. Calling it directly on the implementation * address will revert. * * @param interfaceId The interface identifier to check * @return isSupported True when `interfaceId` is either: * - the {IERC7821} interface id * - the {IERC1271} interface id * - the {IERC721Receiver} interface id (checked in TokenReceiver) * - the {IERC1155Receiver} interface id (checked in ERC1155Holder) * - the {IERC165} interface id (checked in ERC1155Holder -> ERC165) */ function supportsInterface(bytes4 interfaceId) public view override onlyProxy returns (bool isSupported) { return interfaceId == type(IERC7821).interfaceId || interfaceId == type(IERC1271).interfaceId || super.supportsInterface(interfaceId); } // ========================= INTERNAL ========================== /** * @notice This function calls the target with specified value and data. It is multipurpose and can be used for * both invoking a function on target contract or for sending ETH to non-contract addresses. * @dev Performs a low-level call to the target contract and verifies the result. * * Note: This function prevents reentrancy when the target is the Delegated EOA. Following a whitelist pattern, * the only function selector allowed in this situation is the `invalidateNonce` function. If any other function, * for example `execute`, is called, it will revert with a `ReentrantCall` error. * * Calling Conditions: * * - The call to perform does not constitute a reentrant call to the execute function. * * @param target The address of the contract to call * @param value The amount of ETH to send with the call * @param data The calldata to send to the target */ function _call(address target, uint256 value, bytes calldata data) internal { // Reject any calls to self that are not the invalidateNonce function if (target == address(this) && data.length >= 4 && bytes4(data[:4]) != this.invalidateNonce.selector) { revert LibErrors.ReentrantCall(); } (bool success, bytes memory returndata) = target.call{ value: value }(data); Address.verifyCallResult(success, returndata); } /** * @notice Internal function that executes a batch of calls sequentially * @dev Processes an array of Execution structs, calling each target with the specified value and calldata. * This function ensures each call is processed in sequence and bubbles up any errors from failed calls. * * Security considerations: * - All calls are made in the context of the Delegated EOA (address(this)) * - This is an internal function without authorization checks * * @param executionBatch An array of Execution structs containing target addresses, values, and calldata */ function _execBatch(Execution[] calldata executionBatch) internal { for (uint256 i = 0; i < executionBatch.length; ++i) { _call(executionBatch[i].target, executionBatch[i].value, executionBatch[i].callData); } } /** * @notice Identifies the type of execution mode * @dev Analyzes the execution mode and returns the {ExecutionModeId} identifier: * * - INVALID if the mode is not supported * - SINGLE_CALL_OPDATA_AUTH for CallType = Single (0x00), ExecType = Revert on failure (0x00), * Unused = EMPTY, ModeSelector = Authorization via **required** `opData` (0x78210001), ModePayload = ANY * - BATCH_CALL_OPDATA_AUTH for CallType = Batch (0x01), ExecType = Revert on failure (0x00), * Unused = EMPTY, ModeSelector = Authorization via optional `opData` (0x78210001), ModePayload = ANY * - BATCH_CALL for CallType = Batch (0x01), ExecType = Revert on failure (0x00), * Unused = EMPTY, ModeSelector = Default (0x00000000), ModePayload = ANY * * @param mode The execution mode to analyze * @return The enum value representing the execution mode type/identifier */ function _executionModeId(bytes32 mode) internal pure returns (ExecutionModeId) { // Check if the mode is supported. Only checks the first 10 bytes of the mode bytes10 execModeMinusPayload = bytes10(mode); if (execModeMinusPayload == bytes10(0x00000000000078210001)) { return ExecutionModeId.SINGLE_CALL_OPDATA_AUTH; } if (execModeMinusPayload == bytes10(0x01000000000078210001)) { return ExecutionModeId.BATCH_CALL_OPDATA_AUTH; } if (execModeMinusPayload == bytes10(0x01000000000000000000)) { return ExecutionModeId.BATCH_CALL; } return ExecutionModeId.INVALID; } /** * @notice Provides a custom error (if possible) to convey information when an execution mode is not supported * @dev Analyzes the components of an execution mode and reverts with a specific error message * based on which component is invalid. * * Reverts with: * - {ERC7579UnsupportedCallType} if CallType is neither Single (0x00) nor Batch (0x01) * - {ERC7579UnsupportedExecType} if ExecType is not Revert (0x00) * - {UnsupportedModeSelector} if ModeSelector is neither Auth (0x78210001) nor Default (0x00000000) * - {UnsupportedExecutionMode} for any other unsupported mode configuration * * @param mode The execution mode to analyze for the revert cause */ function _determineExecutionModeRevertCause(bytes32 mode) internal pure { // Extract the components from the mode (CallType callType, ExecType execType, ModeSelector modeSelector,) = ERC7579Utils.decodeMode(Mode.wrap(mode)); // Check for callType being 0x00 (Single) or 0x01 (Batch) if (!(callType == ERC7579Utils.CALLTYPE_SINGLE || callType == ERC7579Utils.CALLTYPE_BATCH)) { revert ERC7579Utils.ERC7579UnsupportedCallType(callType); } // Check for execType being 0x00 (Revert on failure) if (!(execType == ERC7579Utils.EXECTYPE_DEFAULT)) { revert ERC7579Utils.ERC7579UnsupportedExecType(execType); } // Check for modeSelector being 0x78210001 (Auth via opData) or 0x00000000 (Default) if (!(modeSelector == ModeSelector.wrap(0x78210001) || modeSelector == ModeSelector.wrap(0x00000000))) { revert LibErrors.UnsupportedModeSelector(ModeSelector.unwrap(modeSelector)); } // Revert with default error for other causes revert LibErrors.UnsupportedExecutionMode(); } /** * @notice Extracts single/batch execution data and optional opData from `executionData` * @dev Decodes executionData to separate the call(s) from the optional `opData` according to EIP-7821. * * Here, we perform low-level ABI-decoding of dynamic types with the intent of: * - gracefully handling structural errors that otherwise would result in a generic revert * - maintaining calldata references * * The function determines if opData is present by examining the offset values: * - If only one dynamic type is present, only `singleOrBatchExecutionData` will be relevant, as `opData` is * set to empty * - If two dynamic typed values are present, both execution data and opData are extracted * * Reverts: * - with {LibErrors.ExecutionDataExtractionError} if offsets are invalid * * @param executionData The encoded execution data passed to execute() * @return singleOrBatchExecutionData The extracted singleOrBatchExecutionData data * @return opData The extracted operation data (empty if not provided) */ function _extractExecAndOpData(bytes calldata executionData) internal pure returns (bytes calldata singleOrBatchExecutionData, bytes calldata opData) { // Read the primary offset in a local variable first uint256 cOffset; assembly { cOffset := calldataload(executionData.offset) } if (cOffset < 32) revert LibErrors.ExecutionDataExtractionError(); assembly { let cPos := add(executionData.offset, cOffset) singleOrBatchExecutionData.offset := add(cPos, 0x20) singleOrBatchExecutionData.length := calldataload(cPos) } // If the first offset is 64, we have a second item for opData if (cOffset >= 64) { uint256 oOffset; assembly { oOffset := calldataload(add(executionData.offset, 0x20)) } // Revert if the offset is invalid if (oOffset < 64 || oOffset >= executionData.length) revert LibErrors.ExecutionDataExtractionError(); assembly { let oPos := add(executionData.offset, oOffset) opData.offset := add(oPos, 0x20) opData.length := calldataload(oPos) } } else { assembly { opData.length := 0 } } } /** * @notice Decodes the `opData` parameter, extracting the nonce, deadline and signature components * @dev Parses the opData byte array to extract the nonce, deadline and ECDSA signature according to an expected * packed format. * * The opData is expected to be in ABI packed encoding format: * - 32 bytes for nonce * - 32 bytes for deadline * - 65 bytes for signature (r, s, v) * * Reverts with {LibErrors.OpDataDecodingError} if opData is not at least 129 bytes. * * @param opData The data containing nonce, deadline and signature * @return nonce The extracted nonce value used for replay protection * @return deadline The timestamp after which the signature is no longer valid * @return signature The extracted 65-byte ECDSA signature */ function _decodeOpData(bytes calldata opData) internal pure returns (uint256 nonce, uint256 deadline, bytes calldata signature) { // opData must contain a nonce, deadline and a signature, for a total of 129 bytes require(opData.length == 129, LibErrors.OpDataDecodingError()); // Extract nonce from the first 32 bytes nonce = uint256(bytes32(opData[:32])); // Extract deadline from the next 32 bytes deadline = uint256(bytes32(opData[32:64])); // Extract signature from the remaining bytes signature = opData[64:]; } /** * @notice Verifies if a signature is valid for a given hash in the context of the Delegated EOA, supporting any * ECDSA signature flow including EIP-712. * * @dev Internal implementation for signature validation, reusable to support ERC1271 compatibility and any ECDSA * signature verification requirements, including EIP-712 signatures. * * Note this function does not perform any nonce-validity checks. * * Signature Validity Conditions: * * - The signature does not derive the `address(0)`. * - The signature has invalid length. * - The signature has an S value that is in the lower half order * - The signature must derive `address(this)`. * * @param _hash The hash of the data that was signed * @param _signature A 65-byte ECDSA signature produced by the signer * @return isValid true if the signature is valid, false otherwise */ function _isValidRawSignature(bytes32 _hash, bytes calldata _signature) internal view returns (bool isValid) { (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(_hash, _signature); return address(this) == recovered && err == ECDSA.RecoverError.NoError; } /** * @notice This function is used to get the namespaced, structured nonce storage * @dev This function is used to get the nonce storage pointer * @custom:storage-location erc7201:fireblocks.global.security.nonces * @return $ The reference to the {NonceStorage} struct in storage */ function _nonceStorage() internal pure override returns (NonceStorage storage $) { assembly ("memory-safe") { $.slot := _NONCE_STORAGE_LOCATION } } /** * @notice Returns the address of the verifying contract to be used in the EIP712 domain separator * @dev The verifyingContract used is the address of the implementation contract, set during deployment, to prevent * replay attacks if an EOA re-delegates to a different implementation. * @return verifyingContract The address of the implementation contract */ function _verifyingContractAddress() internal view override returns (address verifyingContract) { // During the construction phase, the value of `__implementation` might be empty, which is not a valid // verifying contract. Therefore, we coalesce to the eventual implementation address. return __implementation == address(0) ? address(this) : __implementation; } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1271.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (account/utils/draft-ERC7579Utils.sol)
pragma solidity ^0.8.20;
import {Execution} from "../../interfaces/draft-IERC7579.sol";
import {Packing} from "../../utils/Packing.sol";
import {Address} from "../../utils/Address.sol";
type Mode is bytes32;
type CallType is bytes1;
type ExecType is bytes1;
type ModeSelector is bytes4;
type ModePayload is bytes22;
/**
* @dev Library with common ERC-7579 utility functions.
*
* See https://eips.ethereum.org/EIPS/eip-7579[ERC-7579].
*/
// slither-disable-next-line unused-state
library ERC7579Utils {
using Packing for *;
/// @dev A single `call` execution.
CallType internal constant CALLTYPE_SINGLE = CallType.wrap(0x00);
/// @dev A batch of `call` executions.
CallType internal constant CALLTYPE_BATCH = CallType.wrap(0x01);
/// @dev A `delegatecall` execution.
CallType internal constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);
/// @dev Default execution type that reverts on failure.
ExecType internal constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
/// @dev Execution type that does not revert on failure.
ExecType internal constant EXECTYPE_TRY = ExecType.wrap(0x01);
/**
* @dev Emits when an {EXECTYPE_TRY} execution fails.
* @param batchExecutionIndex The index of the failed call in the execution batch.
* @param returndata The returned data from the failed call.
*/
event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes returndata);
/// @dev The provided {CallType} is not supported.
error ERC7579UnsupportedCallType(CallType callType);
/// @dev The provided {ExecType} is not supported.
error ERC7579UnsupportedExecType(ExecType execType);
/// @dev The provided module doesn't match the provided module type.
error ERC7579MismatchedModuleTypeId(uint256 moduleTypeId, address module);
/// @dev The module is not installed.
error ERC7579UninstalledModule(uint256 moduleTypeId, address module);
/// @dev The module is already installed.
error ERC7579AlreadyInstalledModule(uint256 moduleTypeId, address module);
/// @dev The module type is not supported.
error ERC7579UnsupportedModuleType(uint256 moduleTypeId);
/// @dev Input calldata not properly formatted and possibly malicious.
error ERC7579DecodingError();
/// @dev Executes a single call.
function execSingle(
bytes calldata executionCalldata,
ExecType execType
) internal returns (bytes[] memory returnData) {
(address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata);
returnData = new bytes[](1);
returnData[0] = _call(0, execType, target, value, callData);
}
/// @dev Executes a batch of calls.
function execBatch(
bytes calldata executionCalldata,
ExecType execType
) internal returns (bytes[] memory returnData) {
Execution[] calldata executionBatch = decodeBatch(executionCalldata);
returnData = new bytes[](executionBatch.length);
for (uint256 i = 0; i < executionBatch.length; ++i) {
returnData[i] = _call(
i,
execType,
executionBatch[i].target,
executionBatch[i].value,
executionBatch[i].callData
);
}
}
/// @dev Executes a delegate call.
function execDelegateCall(
bytes calldata executionCalldata,
ExecType execType
) internal returns (bytes[] memory returnData) {
(address target, bytes calldata callData) = decodeDelegate(executionCalldata);
returnData = new bytes[](1);
returnData[0] = _delegatecall(0, execType, target, callData);
}
/// @dev Encodes the mode with the provided parameters. See {decodeMode}.
function encodeMode(
CallType callType,
ExecType execType,
ModeSelector selector,
ModePayload payload
) internal pure returns (Mode mode) {
return
Mode.wrap(
CallType
.unwrap(callType)
.pack_1_1(ExecType.unwrap(execType))
.pack_2_4(bytes4(0))
.pack_6_4(ModeSelector.unwrap(selector))
.pack_10_22(ModePayload.unwrap(payload))
);
}
/// @dev Decodes the mode into its parameters. See {encodeMode}.
function decodeMode(
Mode mode
) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) {
return (
CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)),
ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)),
ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)),
ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10))
);
}
/// @dev Encodes a single call execution. See {decodeSingle}.
function encodeSingle(
address target,
uint256 value,
bytes calldata callData
) internal pure returns (bytes memory executionCalldata) {
return abi.encodePacked(target, value, callData);
}
/// @dev Decodes a single call execution. See {encodeSingle}.
function decodeSingle(
bytes calldata executionCalldata
) internal pure returns (address target, uint256 value, bytes calldata callData) {
target = address(bytes20(executionCalldata[0:20]));
value = uint256(bytes32(executionCalldata[20:52]));
callData = executionCalldata[52:];
}
/// @dev Encodes a delegate call execution. See {decodeDelegate}.
function encodeDelegate(
address target,
bytes calldata callData
) internal pure returns (bytes memory executionCalldata) {
return abi.encodePacked(target, callData);
}
/// @dev Decodes a delegate call execution. See {encodeDelegate}.
function decodeDelegate(
bytes calldata executionCalldata
) internal pure returns (address target, bytes calldata callData) {
target = address(bytes20(executionCalldata[0:20]));
callData = executionCalldata[20:];
}
/// @dev Encodes a batch of executions. See {decodeBatch}.
function encodeBatch(Execution[] memory executionBatch) internal pure returns (bytes memory executionCalldata) {
return abi.encode(executionBatch);
}
/// @dev Decodes a batch of executions. See {encodeBatch}.
///
/// NOTE: This function runs some checks and will throw a {ERC7579DecodingError} if the input is not properly formatted.
function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) {
unchecked {
uint256 bufferLength = executionCalldata.length;
// Check executionCalldata is not empty.
if (bufferLength < 32) revert ERC7579DecodingError();
// Get the offset of the array (pointer to the array length).
uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0:32]));
// The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the
// buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk.
if (arrayLengthOffset > bufferLength - 32) revert ERC7579DecodingError();
// Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow.
uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 32]));
// Check that the buffer is long enough to store the array elements as "offset pointer":
// - each element of the array is an "offset pointer" to the data.
// - each "offset pointer" (to an array element) takes 32 bytes.
// - validity of the calldata at that location is checked when the array element is accessed, so we only
// need to check that the buffer is large enough to hold the pointers.
//
// Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk.
// Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow.
if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 32 < arrayLength * 32)
revert ERC7579DecodingError();
assembly ("memory-safe") {
executionBatch.offset := add(add(executionCalldata.offset, arrayLengthOffset), 32)
executionBatch.length := arrayLength
}
}
}
/// @dev Executes a `call` to the target with the provided {ExecType}.
function _call(
uint256 index,
ExecType execType,
address target,
uint256 value,
bytes calldata data
) private returns (bytes memory) {
(bool success, bytes memory returndata) = target.call{value: value}(data);
return _validateExecutionMode(index, execType, success, returndata);
}
/// @dev Executes a `delegatecall` to the target with the provided {ExecType}.
function _delegatecall(
uint256 index,
ExecType execType,
address target,
bytes calldata data
) private returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return _validateExecutionMode(index, execType, success, returndata);
}
/// @dev Validates the execution mode and returns the returndata.
function _validateExecutionMode(
uint256 index,
ExecType execType,
bool success,
bytes memory returndata
) private returns (bytes memory) {
if (execType == ERC7579Utils.EXECTYPE_DEFAULT) {
Address.verifyCallResult(success, returndata);
} else if (execType == ERC7579Utils.EXECTYPE_TRY) {
if (!success) emit ERC7579TryExecuteFail(index, returndata);
} else {
revert ERC7579UnsupportedExecType(execType);
}
return returndata;
}
}
// Operators
using {eqCallType as ==} for CallType global;
using {eqExecType as ==} for ExecType global;
using {eqModeSelector as ==} for ModeSelector global;
using {eqModePayload as ==} for ModePayload global;
/// @dev Compares two `CallType` values for equality.
function eqCallType(CallType a, CallType b) pure returns (bool) {
return CallType.unwrap(a) == CallType.unwrap(b);
}
/// @dev Compares two `ExecType` values for equality.
function eqExecType(ExecType a, ExecType b) pure returns (bool) {
return ExecType.unwrap(a) == ExecType.unwrap(b);
}
/// @dev Compares two `ModeSelector` values for equality.
function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {
return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);
}
/// @dev Compares two `ModePayload` values for equality.
function eqModePayload(ModePayload a, ModePayload b) pure returns (bool) {
return ModePayload.unwrap(a) == ModePayload.unwrap(b);
}// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2016-2025 Zeppelin Group Ltd
pragma solidity 0.8.27;
/**
* @dev Interface for minimal batch executor.
*
* @custom:source
* https://github.com/OpenZeppelin/openzeppelin-community-contracts/blob/e19d51c/contracts/interfaces/IERC7821.sol
*/
interface IERC7821 {
/**
* @dev Executes the calls in `executionData`.
* Reverts and bubbles up error if any call fails.
*
* `executionData` encoding:
* - If `opData` is empty, `executionData` is simply `abi.encode(calls)`.
* - Else, `executionData` is `abi.encode(calls, opData)`.
* See: https://eips.ethereum.org/EIPS/eip-7579
*
* Supported modes:
* - `bytes32(0x01000000000000000000...)`: does not support optional `opData`.
* - `bytes32(0x01000000000078210001...)`: supports optional `opData`.
*
* Authorization checks:
* - If `opData` is empty, the implementation SHOULD require that
* `msg.sender == address(this)`.
* - If `opData` is not empty, the implementation SHOULD use the signature
* encoded in `opData` to determine if the caller can perform the execution.
*
* `opData` may be used to store additional data for authentication,
* paymaster data, gas limits, etc.
*/
function execute(bytes32 mode, bytes calldata executionData) external payable;
/**
* @dev This function is provided for frontends to detect support.
* Only returns true for:
* - `bytes32(0x01000000000000000000...)`: does not support optional `opData`.
* - `bytes32(0x01000000000078210001...)`: supports optional `opData`.
*/
function supportsExecutionMode(bytes32 mode) external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> pragma solidity 0.8.27; import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; /** * @title TokenReceiver * @notice This helper contract implements the necessary methods to successfully receive ERC1155 and ERC721 tokens. * It is used as a base contract for accounts that need to handle token transfers. * * @dev This contract implements: * - the {IERC1155Receiver} interface allowing it to receive ERC1155 tokens * - the {IERC721Receiver} interface allowing it to receive ERC721 tokens * - the EIP-165 standard for interface detection of the same and the two above interfaces * * @custom:security-contact [email protected] */ abstract contract TokenReceiver is ERC721Holder, ERC1155Holder { /** * @notice This function can be queried to check if the contract implements a specific interface * @dev Interface detection as per ERC-165 standard * * Returns true when `interfaceId` is either: * - the {IERC721Receiver} interface id * - the {IERC1155Receiver} interface id (checked in ERC1155Holder) * - the {IERC165} interface id (checked in ERC1155Holder -> ERC165) * * @param interfaceId The interface identifier to check * @return isSupported True if the contract supports `interfaceId` */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool isSupported) { return interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> pragma solidity 0.8.27; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { IERC5267 } from "@openzeppelin/contracts/interfaces/IERC5267.sol"; import { Execution } from "@openzeppelin/contracts/interfaces/draft-IERC7579.sol"; /** * @title Typed Structured Execution Authorization * @notice Implementation of EIP712 that provides structured hashing functions for typed data in the context of * meta-transactions. This contract computes the message digests that off-chain wallets must sign to * authorize executions through the EIP-7702 delegate contract, supporting batch operations out of the box. * * This contract is an implementation of EIP-712 with select elements being part of the EIP712Domain * * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data. * * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest ({_hashTypedDataV4}) that is then signed * via ECDSA. This contract also supports ERC-5267, but such proposal does not have a prerequisite on ERC-165 which * means that there is no need to signal it via a `supportsInterface` function. * * The implementation of the domain separator was designed to be as lean as possible, preserving only the chainId and * verifyingContract fields. It retains logic for properly updating the chain id to protect against replay attacks on * an eventual fork of the chain. The verifyingContract to be used should be defined by deriving contracts, allowing * for flexibility in the verification of EIP-712 signatures. This is particularly useful in the context of EIP-7702 * delegate contracts, where the verifyingContract may be the proxy contract itself or the implementation contract. * This contract implements the version of the encoding known as "signTypedDataV4". * * This contract is derived from the OpenZeppelin Contracts implementation of EIP-712 (utils/cryptography/EIP712.sol). * * @custom:security-contact [email protected] */ abstract contract TypedAuthorization is IERC5267 { // ============================================================= // CONSTANTS / IMMUTABLE // ============================================================= /** * @notice The EIP712 domain typehash used for computing the domain separator * @dev Hash of the type string: "EIP712Domain(uint256 chainId,address verifyingContract)" */ bytes32 private constant _DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); /** * @notice The typehash for the Execution type used in the structured data * @dev Hash of the type string: "Execution(address target,uint256 value,bytes data)" */ bytes32 internal constant _EXECUTION_TYPEHASH = keccak256("Execution(address target,uint256 value,bytes data)"); /** * @notice The typehash for the AuthorizedExecutions type used in the typed data * @dev Hash of the type string that combines the execution authorization with the execution data * This defines the structure of the typed data that will be signed for authorizing executions */ bytes32 internal constant _EXECUTION_AUTHORIZATION_TYPEHASH = keccak256( // solhint-disable-next-line max-line-length "AuthorizedExecutions(Execution[] calls,uint256 deadline,bytes32 mode,uint256 nonce,address relayer)Execution(address target,uint256 value,bytes data)" ); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; // solhint-disable-line immutable-vars-naming uint256 private immutable _cachedChainId; // solhint-disable-line immutable-vars-naming // ============================================================= // CONSTRUCTOR // ============================================================= /** * @notice Initializes the EIP712 domain separator cache using an internally defined verifying-contract address */ constructor() { _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); } // ============================================================= // PUBLIC FUNCTIONS // ============================================================= /** * @inheritdoc IERC5267 */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0c", // 01100 string(""), // empty name string(""), // empty version block.chainid, _verifyingContractAddress(), bytes32(0), // empty salt new uint256[](0) ); } // ============================================================= // INTERNAL FUNCTIONS // ============================================================= /** * @notice Returns the domain separator for the current chain. * @dev Returns the cached separator if the chain id hasn't changed, otherwise rebuilds it. * @return domainSeparator The domain separator bytes32 value */ function _domainSeparatorV4() internal view returns (bytes32 domainSeparator) { // Use cached value if chainId matches, otherwise rebuild return block.chainid == _cachedChainId ? _cachedDomainSeparator : _buildDomainSeparator(); } /** * @notice Builds the EIP712 domain separator using the current chain ID and the implementation-specific address * as the verifying contract. * @return domainSeparator The domain separator bytes32 value */ function _buildDomainSeparator() private view returns (bytes32 domainSeparator) { return keccak256(abi.encode(_DOMAIN_TYPEHASH, block.chainid, _verifyingContractAddress())); } /** * @notice Given a hashed struct, returns the hash of the fully encoded EIP712 message for this domain. * * See https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[definition of hashed struct]. * * @dev This hash can be used with {ECDSA-recover} to obtain the signer of a message * * @param structHash The hash of the struct being signed * @return hashedData The EIP712 typed data hash */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32 hashedData) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @notice Create a hash of the fully encoded EIP712 message for a single authorized execution * @dev Creates a typed hash for a single execution with the given parameters * * @param mode The execution mode * @param target The target address * @param value The value to send * @param data The call data * @param nonce The nonce * @param deadline The timestamp after which the signature is no longer valid * @param relayer The address of the relayer that is authorized to submit this transaction * @return hashedData The `AuthorizedExecutions` typed hash */ function _hashTypedSingleExecutionAuthorization( bytes32 mode, address target, uint256 value, bytes memory data, uint256 nonce, uint256 deadline, address relayer ) internal view returns (bytes32 hashedData) { // Directly calculate the execution hash for the single execution bytes32 seHash = keccak256(abi.encode(_EXECUTION_TYPEHASH, target, value, keccak256(data))); // When there's only one item, the executionsHash (plural) is just the packaged single hash bytes32 executionsHash = keccak256(abi.encodePacked(seHash)); // Create the final hash including the calls, deadline, mode, nonce and relayer bytes32 structHash = keccak256(abi.encode(_EXECUTION_AUTHORIZATION_TYPEHASH, executionsHash, deadline, mode, nonce, relayer)); return _hashTypedDataV4(structHash); } /** * @notice Create a hash of the fully encoded EIP712 message for a batch of executions * @dev Creates a typed hash for multiple executions with the given parameters * * @param mode The execution mode * @param calls The array of executions * @param nonce The nonce * @param deadline The timestamp after which the signature is no longer valid * @param relayer The address of the relayer that is authorized to submit this transaction * @return hashedData The `AuthorizedExecutions` typed hash */ function _hashTypedBatchExecutionAuthorization( bytes32 mode, Execution[] memory calls, uint256 nonce, uint256 deadline, address relayer ) internal view returns (bytes32 hashedData) { // Hash each execution in the batch bytes32[] memory executionHashes = new bytes32[](calls.length); for (uint256 i = 0; i < calls.length; i++) { executionHashes[i] = keccak256( abi.encode(_EXECUTION_TYPEHASH, calls[i].target, calls[i].value, keccak256(calls[i].callData)) ); } // Hash the array of execution hashes bytes32 executionsHash = keccak256(abi.encodePacked(executionHashes)); // Create the final hash including the calls, deadline, mode, nonce and relayer bytes32 structHash = keccak256(abi.encode(_EXECUTION_AUTHORIZATION_TYPEHASH, executionsHash, deadline, mode, nonce, relayer)); return _hashTypedDataV4(structHash); } /** * @notice This function determines the address of the verifying contract to be used in the EIP712 domain separator * @dev This function must be overridden by the deriving contract to provide the appropriate contract address, * which could be the address of the implementation contract or the proxy contract. * @return verifyingContract The address of the verifying contract */ function _verifyingContractAddress() internal view virtual returns (address verifyingContract); }
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> pragma solidity 0.8.27; import { NonceStorage } from "../library/NonceStorageStruct.sol"; import { LibErrors } from "../library/LibErrors.sol"; /** * @title NonceBitmap * @notice This contract manages unordered nonces using a Bitmap approach to efficiently store and track nonce usage. * @dev Provides functionality for managing and querying nonces * @custom:security-contact [email protected] */ abstract contract NonceBitmap { // ============================================================= // FUNCTIONS // ============================================================= // ========================= EXTERNAL ========================== /** * @notice This function marks a nonce as used * @dev This function is used to invalidate a nonce. Reverts with {LibErrors.InvalidNonce} * if the nonce has already been used. * * Deriving contracts must ensure proper access control. * * @param nonce The nonce to invalidate */ function invalidateNonce(uint256 nonce) external virtual { _useUnorderedNonce(nonce); } /** * @notice Returns the nonce bitmap at a given word position * @param wordPos The word position to check * @return bitmap The nonce bitmap at the given position */ function getNonceBitmap(uint248 wordPos) public view virtual returns (uint256 bitmap) { return _nonceStorage().nonceBitmap[wordPos]; } /** * @notice This function checks if a nonce is already used * @dev Checks whether a nonce has been flipped in the bitmap * @param nonce The nonce to check * @return isUsed True if the nonce has been used, false otherwise */ function isNonceUsed(uint256 nonce) public view virtual returns (bool isUsed) { (uint256 wordPos, uint256 bitPos) = _bitmapPositions(nonce); uint256 bit = 1 << bitPos; return _nonceStorage().nonceBitmap[wordPos] & bit != 0; } // ========================= INTERNAL ========================== /** * @notice Returns the index of the bitmap and the bit position within the bitmap * @param nonce The nonce to get the associated word and bit positions * @return wordPos The word position or index into the nonceBitmap * @return bitPos The bit position * @dev The first 248 bits of the nonce value is the index of the desired bitmap * @dev The last 8 bits of the nonce value is the position of the bit in the bitmap */ function _bitmapPositions(uint256 nonce) internal pure returns (uint256 wordPos, uint256 bitPos) { wordPos = uint248(nonce >> 8); bitPos = uint8(nonce); } /** * @notice This represents the function signature to be used when accessing the Nonce Storage * @dev Returns storage reference for nonce bitmap * @return $ Storage reference to the nonce bitmap */ function _nonceStorage() internal pure virtual returns (NonceStorage storage $); /** * @notice Sets the nonce to used * @dev Checks whether a nonce is taken and sets the bit at the bit position in the bitmap. * * Reverts with {LibErrors.InvalidNonce} if the nonce has already been used. * * @param nonce The nonce to spend */ function _useUnorderedNonce(uint256 nonce) internal { (uint256 wordPos, uint256 bitPos) = _bitmapPositions(nonce); uint256 bit = 1 << bitPos; uint256 flipped = _nonceStorage().nonceBitmap[wordPos] ^= bit; if (flipped & bit == 0) revert LibErrors.InvalidNonce(); } }
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity 0.8.27; // ============================================================= // STRUCTS // ============================================================= /** * @notice Storage structure for nonce bitmap that helps prevent replay attacks of off-chain signatures * @dev This structure is used to track used nonces in a memory-efficient way using a bitmap * * The `@custom:storage-location` tag is to be defined by the implementing contract. */ struct NonceStorage { /** * @notice Unordered nonces with a bitmap. The key of the mapping is the "nonce value". * @dev The first 248 bits of the nonce value is the index of the desired bitmap * @dev The last 8 bits of the nonce value is the position of the bit in the bitmap */ mapping(uint256 => uint256) nonceBitmap; }
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity 0.8.27; /** * @title Errors Library * @author Fireblocks * @notice The Errors Library provides error messages for the Fireblocks ecosystem of smart contracts. */ library LibErrors { /** * @notice This error indicates that a signature has expired * @dev Indicates that current block timestamp is past the deadline */ error ExpiredSignature(uint256 deadline); /** * @notice This error indicates that a nonce has already been used. * @dev The nonce has already been used for this account. */ error InvalidNonce(); /** * @notice This error indicates that an address provided does not implement a required interface. * @dev Indicates that a contract does not implement a required interface. */ error InvalidImplementation(); /** * @notice This error indicates that there was an error decoding the opData parameter. * @dev Indicates that there was an error decoding the operation data (opData). */ error OpDataDecodingError(); /** * @notice This error indicates that there was an error extracting data from the execution payload. * @dev Indicates that there was an error decoding the execution payload based on an expected structure. */ error ExecutionDataExtractionError(); /** * @notice This error indicates that a call to the `execute` function on the same Delegate EOA was attempted, from * the context of a running `execute` function. This would indicate a reentrant call, and therefore is blocked. * @dev Thrown when a reentrant call is detected. */ error ReentrantCall(); /** * @notice This error indicates that the function caller is not the expected. For example, not the EOA itself. * @dev Indicates that the function caller is not the expected address. */ error UnauthorizedCaller(); /** * @notice This error indicates that a call is being invoked in the wrong target. For example, the implementation * contract instead of the Delegated EOA address. * @dev Indicates that the call is from an unauthorized context, such as a direct call to the * implementation contract. */ error UnauthorizedCallContext(); /** * @notice This error indicates that an execution request was rejected due to invalid authorization. * @dev Thrown when an execution request fails signature verification checks. * * This can occur when: * - The signature provided cannot be attributed to the expected signer (the EOA that has performed an EIP-7702 * delegation to this contract) * - The provided signature does not match the given execution payload * - The `opData` component was present and non-zero but the mode provided does not support it */ error UnauthorizedExecution(); /** * @notice This error indicates that the requested execution mode is not supported by the contract. * @dev Thrown when an execution request uses an execution mode configuration that is not * recognized or supported by the contract. This is a general error when the specific * component causing the unsupported mode cannot be determined. * * See also: * - {UnsupportedModeSelector}: For more specific errors related to mode selectors * - {ERC7579UnsupportedCallType}: For errors related to call types * - {ERC7579UnsupportedExecType}: For errors related to execution types */ error UnsupportedExecutionMode(); /** * @notice This error indicates that the execution mode selector is not supported by the contract. * @dev Indicates that the execution mode selector is not supported by the contract. * @param modeSelector The function selector that was not recognized as a valid mode. */ error UnsupportedModeSelector(bytes4 modeSelector); // ==================== IMPORTED ERRORS ==================== // These are errors that are observed in inherited contracts // or libraries and therefore are known to be thrown by the // contract. They are collated here for developer convenience. // ========================================================= /** * @notice This error indicates that the operation failed because the contract is paused. * @dev The operation failed because the contract is paused. * * Moved into a library to avoid the need for a contract to inherit/import from {Pausable}. This error is original * from OpenZeppelin's {Pausable} contract: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Pausable.sol */ error EnforcedPause(); /** * @notice This error indicates that an ERC7579 execute "call type" is not supported. * @dev Thrown when an unsupported call type is used in an EIP-7579 execution mode. * @param callType The unsupported call type byte. */ error ERC7579UnsupportedCallType(bytes1 callType); /** * @notice This error indicates that an ERC7579 execute "execution type" is not supported. * @dev Thrown when an unsupported exec type is used in an EIP-7579 execution mode. * @param execType The unsupported execution type byte. */ error ERC7579UnsupportedExecType(bytes1 execType); }
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: Copyright (C) 2025 Fireblocks <[email protected]> pragma solidity 0.8.27; /** * @title IKillSwitch * @notice Interface for the KillSwitch contract * @dev Defines the standard functions for a KillSwitch that can pause and unpause system functionality */ interface IKillSwitch { // ============================================================= // FUNCTIONS // ============================================================= /** * @notice Pauses delegate contract operations for all delegated EOAs */ function pause() external; /** * @notice Resumes normal operation of delegated EOAs */ function unpause() external; /** * @notice Checks if the delegate contract functionality is paused * @return True if the contract is paused, false otherwise */ function paused() external view returns (bool); }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (interfaces/draft-IERC7579.sol)
pragma solidity ^0.8.20;
import {PackedUserOperation} from "./draft-IERC4337.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;
/// @dev Minimal configuration interface for ERC-7579 modules
interface IERC7579Module {
/**
* @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 (e.g. if module is already enabled)
*/
function onInstall(bytes calldata data) external;
/**
* @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;
/**
* @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 ERC-7579 Validation module (type 1).
*
* A module that implements logic to validate user operations and signatures.
*/
interface IERC7579Validator is IERC7579Module {
/**
* @dev Validates a UserOperation
* @param userOp the ERC-4337 PackedUserOperation
* @param userOpHash the hash of the ERC-4337 PackedUserOperation
*
* MUST validate that the signature is a valid signature of the userOpHash
* SHOULD return ERC-4337's SIG_VALIDATION_FAILED (and not revert) on signature mismatch
* See {IAccount-validateUserOp} for additional information on the return value
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256);
/**
* @dev Validates a signature using ERC-1271
* @param sender the address that sent the ERC-1271 request to the smart account
* @param hash the hash of the ERC-1271 request
* @param signature the signature of the ERC-1271 request
*
* MUST return the ERC-1271 `MAGIC_VALUE` if the signature is valid
* MUST NOT modify state
*/
function isValidSignatureWithSender(
address sender,
bytes32 hash,
bytes calldata signature
) external view returns (bytes4);
}
/**
* @dev ERC-7579 Hooks module (type 4).
*
* A module that implements logic to execute before and after the account executes a user operation,
* either individually or batched.
*/
interface IERC7579Hook is IERC7579Module {
/**
* @dev Called by the smart account before execution
* @param msgSender the address that called the smart account
* @param value the value that was sent to the smart account
* @param msgData the data that was sent to the smart account
*
* MAY return arbitrary data in the `hookData` return value
*/
function preCheck(
address msgSender,
uint256 value,
bytes calldata msgData
) external returns (bytes memory hookData);
/**
* @dev Called by the smart account after execution
* @param hookData the data that was returned by the `preCheck` function
*
* MAY validate the `hookData` to validate transaction context of the `preCheck` function
*/
function postCheck(bytes calldata hookData) external;
}
struct Execution {
address target;
uint256 value;
bytes callData;
}
/**
* @dev ERC-7579 Execution.
*
* Accounts should implement this interface so that the Entrypoint and ERC-7579 modules can execute operations.
*/
interface IERC7579Execution {
/**
* @dev Executes a transaction on behalf of the account.
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
*
* MUST ensure adequate authorization control: e.g. onlyEntryPointOrSelf if used with ERC-4337
* If a mode is requested that is not supported by the Account, it MUST revert
*/
function execute(bytes32 mode, bytes calldata executionCalldata) external payable;
/**
* @dev Executes a transaction on behalf of the account.
* This function is intended to be called by Executor Modules
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
* @return returnData An array with the returned data of each executed subcall
*
* MUST ensure adequate authorization control: i.e. onlyExecutorModule
* If a mode is requested that is not supported by the Account, it MUST revert
*/
function executeFromExecutor(
bytes32 mode,
bytes calldata executionCalldata
) external payable returns (bytes[] memory returnData);
}
/**
* @dev ERC-7579 Account Config.
*
* Accounts should implement this interface to expose information that identifies the account, supported modules and capabilities.
*/
interface IERC7579AccountConfig {
/**
* @dev Returns the account id of the smart account
* @return accountImplementationId the account id of the smart account
*
* MUST return a non-empty string
* The accountId SHOULD be structured like so:
* "vendorname.accountname.semver"
* The id SHOULD be unique across all smart accounts
*/
function accountId() external view returns (string memory accountImplementationId);
/**
* @dev Function to check if the account supports a certain execution mode (see above)
* @param encodedMode the encoded mode
*
* MUST return true if the account supports the mode and false otherwise
*/
function supportsExecutionMode(bytes32 encodedMode) external view returns (bool);
/**
* @dev Function to check if the account supports a certain module typeId
* @param moduleTypeId the module type ID according to the ERC-7579 spec
*
* MUST return true if the account supports the module type and false otherwise
*/
function supportsModule(uint256 moduleTypeId) external view returns (bool);
}
/**
* @dev ERC-7579 Module Config.
*
* Accounts should implement this interface to allow installing and uninstalling modules.
*/
interface IERC7579ModuleConfig {
event ModuleInstalled(uint256 moduleTypeId, address module);
event ModuleUninstalled(uint256 moduleTypeId, address module);
/**
* @dev Installs a Module of a certain type on the smart account
* @param moduleTypeId the module type ID according to the ERC-7579 spec
* @param module the module address
* @param initData arbitrary data that may be required on the module during `onInstall`
* initialization.
*
* MUST implement authorization control
* MUST call `onInstall` on the module with the `initData` parameter if provided
* MUST emit ModuleInstalled event
* MUST revert if the module is already installed or the initialization on the module failed
*/
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external;
/**
* @dev Uninstalls a Module of a certain type on the smart account
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param deInitData arbitrary data that may be required on the module during `onInstall`
* initialization.
*
* MUST implement authorization control
* MUST call `onUninstall` on the module with the `deInitData` parameter if provided
* MUST emit ModuleUninstalled event
* MUST revert if the module is not installed or the deInitialization on the module failed
*/
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external;
/**
* @dev Returns whether a module is installed on the smart account
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param additionalContext arbitrary data that may be required to determine if the module is installed
*
* MUST return true if the module is installed and false otherwise
*/
function isModuleInstalled(
uint256 moduleTypeId,
address module,
bytes calldata additionalContext
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Packing.sol)
// This file was procedurally generated from scripts/generate/templates/Packing.js.
pragma solidity ^0.8.20;
/**
* @dev Helper library packing and unpacking multiple values into bytesXX.
*
* Example usage:
*
* ```solidity
* library MyPacker {
* type MyType is bytes32;
*
* function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) {
* bytes12 subpack = Packing.pack_4_8(selector, bytes8(period));
* bytes32 pack = Packing.pack_20_12(bytes20(account), subpack);
* return MyType.wrap(pack);
* }
*
* function _unpack(MyType self) external pure returns (address, bytes4, uint64) {
* bytes32 pack = MyType.unwrap(self);
* return (
* address(Packing.extract_32_20(pack, 0)),
* Packing.extract_32_4(pack, 20),
* uint64(Packing.extract_32_8(pack, 24))
* );
* }
* }
* ```
*
* _Available since v5.1._
*/
// solhint-disable func-name-mixedcase
library Packing {
error OutOfRangeAccess();
function pack_1_1(bytes1 left, bytes1 right) internal pure returns (bytes2 result) {
assembly ("memory-safe") {
left := and(left, shl(248, not(0)))
right := and(right, shl(248, not(0)))
result := or(left, shr(8, right))
}
}
function pack_2_2(bytes2 left, bytes2 right) internal pure returns (bytes4 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_4(bytes2 left, bytes4 right) internal pure returns (bytes6 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_6(bytes2 left, bytes6 right) internal pure returns (bytes8 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_8(bytes2 left, bytes8 right) internal pure returns (bytes10 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_10(bytes2 left, bytes10 right) internal pure returns (bytes12 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(176, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_20(bytes2 left, bytes20 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(96, not(0)))
result := or(left, shr(16, right))
}
}
function pack_2_22(bytes2 left, bytes22 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(240, not(0)))
right := and(right, shl(80, not(0)))
result := or(left, shr(16, right))
}
}
function pack_4_2(bytes4 left, bytes2 right) internal pure returns (bytes6 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_4(bytes4 left, bytes4 right) internal pure returns (bytes8 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_6(bytes4 left, bytes6 right) internal pure returns (bytes10 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_8(bytes4 left, bytes8 right) internal pure returns (bytes12 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_12(bytes4 left, bytes12 right) internal pure returns (bytes16 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_16(bytes4 left, bytes16 right) internal pure returns (bytes20 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(128, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_20(bytes4 left, bytes20 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(96, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_24(bytes4 left, bytes24 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(64, not(0)))
result := or(left, shr(32, right))
}
}
function pack_4_28(bytes4 left, bytes28 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(224, not(0)))
right := and(right, shl(32, not(0)))
result := or(left, shr(32, right))
}
}
function pack_6_2(bytes6 left, bytes2 right) internal pure returns (bytes8 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(48, right))
}
}
function pack_6_4(bytes6 left, bytes4 right) internal pure returns (bytes10 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(48, right))
}
}
function pack_6_6(bytes6 left, bytes6 right) internal pure returns (bytes12 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(48, right))
}
}
function pack_6_10(bytes6 left, bytes10 right) internal pure returns (bytes16 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(176, not(0)))
result := or(left, shr(48, right))
}
}
function pack_6_16(bytes6 left, bytes16 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(128, not(0)))
result := or(left, shr(48, right))
}
}
function pack_6_22(bytes6 left, bytes22 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(208, not(0)))
right := and(right, shl(80, not(0)))
result := or(left, shr(48, right))
}
}
function pack_8_2(bytes8 left, bytes2 right) internal pure returns (bytes10 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_4(bytes8 left, bytes4 right) internal pure returns (bytes12 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_8(bytes8 left, bytes8 right) internal pure returns (bytes16 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_12(bytes8 left, bytes12 right) internal pure returns (bytes20 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_16(bytes8 left, bytes16 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(128, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_20(bytes8 left, bytes20 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(96, not(0)))
result := or(left, shr(64, right))
}
}
function pack_8_24(bytes8 left, bytes24 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(192, not(0)))
right := and(right, shl(64, not(0)))
result := or(left, shr(64, right))
}
}
function pack_10_2(bytes10 left, bytes2 right) internal pure returns (bytes12 result) {
assembly ("memory-safe") {
left := and(left, shl(176, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(80, right))
}
}
function pack_10_6(bytes10 left, bytes6 right) internal pure returns (bytes16 result) {
assembly ("memory-safe") {
left := and(left, shl(176, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(80, right))
}
}
function pack_10_10(bytes10 left, bytes10 right) internal pure returns (bytes20 result) {
assembly ("memory-safe") {
left := and(left, shl(176, not(0)))
right := and(right, shl(176, not(0)))
result := or(left, shr(80, right))
}
}
function pack_10_12(bytes10 left, bytes12 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(176, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(80, right))
}
}
function pack_10_22(bytes10 left, bytes22 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(176, not(0)))
right := and(right, shl(80, not(0)))
result := or(left, shr(80, right))
}
}
function pack_12_4(bytes12 left, bytes4 right) internal pure returns (bytes16 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(96, right))
}
}
function pack_12_8(bytes12 left, bytes8 right) internal pure returns (bytes20 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(96, right))
}
}
function pack_12_10(bytes12 left, bytes10 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(176, not(0)))
result := or(left, shr(96, right))
}
}
function pack_12_12(bytes12 left, bytes12 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(96, right))
}
}
function pack_12_16(bytes12 left, bytes16 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(128, not(0)))
result := or(left, shr(96, right))
}
}
function pack_12_20(bytes12 left, bytes20 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(160, not(0)))
right := and(right, shl(96, not(0)))
result := or(left, shr(96, right))
}
}
function pack_16_4(bytes16 left, bytes4 right) internal pure returns (bytes20 result) {
assembly ("memory-safe") {
left := and(left, shl(128, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(128, right))
}
}
function pack_16_6(bytes16 left, bytes6 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(128, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(128, right))
}
}
function pack_16_8(bytes16 left, bytes8 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(128, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(128, right))
}
}
function pack_16_12(bytes16 left, bytes12 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(128, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(128, right))
}
}
function pack_16_16(bytes16 left, bytes16 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(128, not(0)))
right := and(right, shl(128, not(0)))
result := or(left, shr(128, right))
}
}
function pack_20_2(bytes20 left, bytes2 right) internal pure returns (bytes22 result) {
assembly ("memory-safe") {
left := and(left, shl(96, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(160, right))
}
}
function pack_20_4(bytes20 left, bytes4 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(96, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(160, right))
}
}
function pack_20_8(bytes20 left, bytes8 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(96, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(160, right))
}
}
function pack_20_12(bytes20 left, bytes12 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(96, not(0)))
right := and(right, shl(160, not(0)))
result := or(left, shr(160, right))
}
}
function pack_22_2(bytes22 left, bytes2 right) internal pure returns (bytes24 result) {
assembly ("memory-safe") {
left := and(left, shl(80, not(0)))
right := and(right, shl(240, not(0)))
result := or(left, shr(176, right))
}
}
function pack_22_6(bytes22 left, bytes6 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(80, not(0)))
right := and(right, shl(208, not(0)))
result := or(left, shr(176, right))
}
}
function pack_22_10(bytes22 left, bytes10 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(80, not(0)))
right := and(right, shl(176, not(0)))
result := or(left, shr(176, right))
}
}
function pack_24_4(bytes24 left, bytes4 right) internal pure returns (bytes28 result) {
assembly ("memory-safe") {
left := and(left, shl(64, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(192, right))
}
}
function pack_24_8(bytes24 left, bytes8 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(64, not(0)))
right := and(right, shl(192, not(0)))
result := or(left, shr(192, right))
}
}
function pack_28_4(bytes28 left, bytes4 right) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
left := and(left, shl(32, not(0)))
right := and(right, shl(224, not(0)))
result := or(left, shr(224, right))
}
}
function extract_2_1(bytes2 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 1) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_2_1(bytes2 self, bytes1 value, uint8 offset) internal pure returns (bytes2 result) {
bytes1 oldValue = extract_2_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_4_1(bytes4 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 3) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_4_1(bytes4 self, bytes1 value, uint8 offset) internal pure returns (bytes4 result) {
bytes1 oldValue = extract_4_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_4_2(bytes4 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_4_2(bytes4 self, bytes2 value, uint8 offset) internal pure returns (bytes4 result) {
bytes2 oldValue = extract_4_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_6_1(bytes6 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 5) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_6_1(bytes6 self, bytes1 value, uint8 offset) internal pure returns (bytes6 result) {
bytes1 oldValue = extract_6_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_6_2(bytes6 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_6_2(bytes6 self, bytes2 value, uint8 offset) internal pure returns (bytes6 result) {
bytes2 oldValue = extract_6_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_6_4(bytes6 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_6_4(bytes6 self, bytes4 value, uint8 offset) internal pure returns (bytes6 result) {
bytes4 oldValue = extract_6_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_8_1(bytes8 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 7) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_8_1(bytes8 self, bytes1 value, uint8 offset) internal pure returns (bytes8 result) {
bytes1 oldValue = extract_8_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_8_2(bytes8 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_8_2(bytes8 self, bytes2 value, uint8 offset) internal pure returns (bytes8 result) {
bytes2 oldValue = extract_8_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_8_4(bytes8 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_8_4(bytes8 self, bytes4 value, uint8 offset) internal pure returns (bytes8 result) {
bytes4 oldValue = extract_8_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_8_6(bytes8 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_8_6(bytes8 self, bytes6 value, uint8 offset) internal pure returns (bytes8 result) {
bytes6 oldValue = extract_8_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_10_1(bytes10 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 9) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_10_1(bytes10 self, bytes1 value, uint8 offset) internal pure returns (bytes10 result) {
bytes1 oldValue = extract_10_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_10_2(bytes10 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_10_2(bytes10 self, bytes2 value, uint8 offset) internal pure returns (bytes10 result) {
bytes2 oldValue = extract_10_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_10_4(bytes10 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_10_4(bytes10 self, bytes4 value, uint8 offset) internal pure returns (bytes10 result) {
bytes4 oldValue = extract_10_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_10_6(bytes10 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_10_6(bytes10 self, bytes6 value, uint8 offset) internal pure returns (bytes10 result) {
bytes6 oldValue = extract_10_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_10_8(bytes10 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_10_8(bytes10 self, bytes8 value, uint8 offset) internal pure returns (bytes10 result) {
bytes8 oldValue = extract_10_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_1(bytes12 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 11) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_12_1(bytes12 self, bytes1 value, uint8 offset) internal pure returns (bytes12 result) {
bytes1 oldValue = extract_12_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_2(bytes12 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 10) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_12_2(bytes12 self, bytes2 value, uint8 offset) internal pure returns (bytes12 result) {
bytes2 oldValue = extract_12_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_4(bytes12 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_12_4(bytes12 self, bytes4 value, uint8 offset) internal pure returns (bytes12 result) {
bytes4 oldValue = extract_12_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_6(bytes12 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_12_6(bytes12 self, bytes6 value, uint8 offset) internal pure returns (bytes12 result) {
bytes6 oldValue = extract_12_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_8(bytes12 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_12_8(bytes12 self, bytes8 value, uint8 offset) internal pure returns (bytes12 result) {
bytes8 oldValue = extract_12_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_12_10(bytes12 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_12_10(bytes12 self, bytes10 value, uint8 offset) internal pure returns (bytes12 result) {
bytes10 oldValue = extract_12_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_1(bytes16 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 15) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_16_1(bytes16 self, bytes1 value, uint8 offset) internal pure returns (bytes16 result) {
bytes1 oldValue = extract_16_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_2(bytes16 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 14) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_16_2(bytes16 self, bytes2 value, uint8 offset) internal pure returns (bytes16 result) {
bytes2 oldValue = extract_16_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_4(bytes16 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_16_4(bytes16 self, bytes4 value, uint8 offset) internal pure returns (bytes16 result) {
bytes4 oldValue = extract_16_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_6(bytes16 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 10) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_16_6(bytes16 self, bytes6 value, uint8 offset) internal pure returns (bytes16 result) {
bytes6 oldValue = extract_16_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_8(bytes16 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_16_8(bytes16 self, bytes8 value, uint8 offset) internal pure returns (bytes16 result) {
bytes8 oldValue = extract_16_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_10(bytes16 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_16_10(bytes16 self, bytes10 value, uint8 offset) internal pure returns (bytes16 result) {
bytes10 oldValue = extract_16_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_16_12(bytes16 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_16_12(bytes16 self, bytes12 value, uint8 offset) internal pure returns (bytes16 result) {
bytes12 oldValue = extract_16_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_1(bytes20 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 19) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_20_1(bytes20 self, bytes1 value, uint8 offset) internal pure returns (bytes20 result) {
bytes1 oldValue = extract_20_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_2(bytes20 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 18) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_20_2(bytes20 self, bytes2 value, uint8 offset) internal pure returns (bytes20 result) {
bytes2 oldValue = extract_20_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_4(bytes20 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 16) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_20_4(bytes20 self, bytes4 value, uint8 offset) internal pure returns (bytes20 result) {
bytes4 oldValue = extract_20_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_6(bytes20 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 14) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_20_6(bytes20 self, bytes6 value, uint8 offset) internal pure returns (bytes20 result) {
bytes6 oldValue = extract_20_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_8(bytes20 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_20_8(bytes20 self, bytes8 value, uint8 offset) internal pure returns (bytes20 result) {
bytes8 oldValue = extract_20_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_10(bytes20 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 10) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_20_10(bytes20 self, bytes10 value, uint8 offset) internal pure returns (bytes20 result) {
bytes10 oldValue = extract_20_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_12(bytes20 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_20_12(bytes20 self, bytes12 value, uint8 offset) internal pure returns (bytes20 result) {
bytes12 oldValue = extract_20_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_20_16(bytes20 self, uint8 offset) internal pure returns (bytes16 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(128, not(0)))
}
}
function replace_20_16(bytes20 self, bytes16 value, uint8 offset) internal pure returns (bytes20 result) {
bytes16 oldValue = extract_20_16(self, offset);
assembly ("memory-safe") {
value := and(value, shl(128, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_1(bytes22 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 21) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_22_1(bytes22 self, bytes1 value, uint8 offset) internal pure returns (bytes22 result) {
bytes1 oldValue = extract_22_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_2(bytes22 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 20) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_22_2(bytes22 self, bytes2 value, uint8 offset) internal pure returns (bytes22 result) {
bytes2 oldValue = extract_22_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_4(bytes22 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 18) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_22_4(bytes22 self, bytes4 value, uint8 offset) internal pure returns (bytes22 result) {
bytes4 oldValue = extract_22_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_6(bytes22 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 16) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_22_6(bytes22 self, bytes6 value, uint8 offset) internal pure returns (bytes22 result) {
bytes6 oldValue = extract_22_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_8(bytes22 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 14) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_22_8(bytes22 self, bytes8 value, uint8 offset) internal pure returns (bytes22 result) {
bytes8 oldValue = extract_22_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_10(bytes22 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_22_10(bytes22 self, bytes10 value, uint8 offset) internal pure returns (bytes22 result) {
bytes10 oldValue = extract_22_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_12(bytes22 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 10) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_22_12(bytes22 self, bytes12 value, uint8 offset) internal pure returns (bytes22 result) {
bytes12 oldValue = extract_22_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_16(bytes22 self, uint8 offset) internal pure returns (bytes16 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(128, not(0)))
}
}
function replace_22_16(bytes22 self, bytes16 value, uint8 offset) internal pure returns (bytes22 result) {
bytes16 oldValue = extract_22_16(self, offset);
assembly ("memory-safe") {
value := and(value, shl(128, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_22_20(bytes22 self, uint8 offset) internal pure returns (bytes20 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(96, not(0)))
}
}
function replace_22_20(bytes22 self, bytes20 value, uint8 offset) internal pure returns (bytes22 result) {
bytes20 oldValue = extract_22_20(self, offset);
assembly ("memory-safe") {
value := and(value, shl(96, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_1(bytes24 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 23) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_24_1(bytes24 self, bytes1 value, uint8 offset) internal pure returns (bytes24 result) {
bytes1 oldValue = extract_24_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_2(bytes24 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 22) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_24_2(bytes24 self, bytes2 value, uint8 offset) internal pure returns (bytes24 result) {
bytes2 oldValue = extract_24_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_4(bytes24 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 20) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_24_4(bytes24 self, bytes4 value, uint8 offset) internal pure returns (bytes24 result) {
bytes4 oldValue = extract_24_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_6(bytes24 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 18) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_24_6(bytes24 self, bytes6 value, uint8 offset) internal pure returns (bytes24 result) {
bytes6 oldValue = extract_24_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_8(bytes24 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 16) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_24_8(bytes24 self, bytes8 value, uint8 offset) internal pure returns (bytes24 result) {
bytes8 oldValue = extract_24_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_10(bytes24 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 14) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_24_10(bytes24 self, bytes10 value, uint8 offset) internal pure returns (bytes24 result) {
bytes10 oldValue = extract_24_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_12(bytes24 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_24_12(bytes24 self, bytes12 value, uint8 offset) internal pure returns (bytes24 result) {
bytes12 oldValue = extract_24_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_16(bytes24 self, uint8 offset) internal pure returns (bytes16 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(128, not(0)))
}
}
function replace_24_16(bytes24 self, bytes16 value, uint8 offset) internal pure returns (bytes24 result) {
bytes16 oldValue = extract_24_16(self, offset);
assembly ("memory-safe") {
value := and(value, shl(128, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_20(bytes24 self, uint8 offset) internal pure returns (bytes20 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(96, not(0)))
}
}
function replace_24_20(bytes24 self, bytes20 value, uint8 offset) internal pure returns (bytes24 result) {
bytes20 oldValue = extract_24_20(self, offset);
assembly ("memory-safe") {
value := and(value, shl(96, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_24_22(bytes24 self, uint8 offset) internal pure returns (bytes22 result) {
if (offset > 2) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(80, not(0)))
}
}
function replace_24_22(bytes24 self, bytes22 value, uint8 offset) internal pure returns (bytes24 result) {
bytes22 oldValue = extract_24_22(self, offset);
assembly ("memory-safe") {
value := and(value, shl(80, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_1(bytes28 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 27) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_28_1(bytes28 self, bytes1 value, uint8 offset) internal pure returns (bytes28 result) {
bytes1 oldValue = extract_28_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_2(bytes28 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 26) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_28_2(bytes28 self, bytes2 value, uint8 offset) internal pure returns (bytes28 result) {
bytes2 oldValue = extract_28_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_4(bytes28 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 24) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_28_4(bytes28 self, bytes4 value, uint8 offset) internal pure returns (bytes28 result) {
bytes4 oldValue = extract_28_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_6(bytes28 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 22) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_28_6(bytes28 self, bytes6 value, uint8 offset) internal pure returns (bytes28 result) {
bytes6 oldValue = extract_28_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_8(bytes28 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 20) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_28_8(bytes28 self, bytes8 value, uint8 offset) internal pure returns (bytes28 result) {
bytes8 oldValue = extract_28_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_10(bytes28 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 18) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_28_10(bytes28 self, bytes10 value, uint8 offset) internal pure returns (bytes28 result) {
bytes10 oldValue = extract_28_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_12(bytes28 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 16) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_28_12(bytes28 self, bytes12 value, uint8 offset) internal pure returns (bytes28 result) {
bytes12 oldValue = extract_28_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_16(bytes28 self, uint8 offset) internal pure returns (bytes16 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(128, not(0)))
}
}
function replace_28_16(bytes28 self, bytes16 value, uint8 offset) internal pure returns (bytes28 result) {
bytes16 oldValue = extract_28_16(self, offset);
assembly ("memory-safe") {
value := and(value, shl(128, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_20(bytes28 self, uint8 offset) internal pure returns (bytes20 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(96, not(0)))
}
}
function replace_28_20(bytes28 self, bytes20 value, uint8 offset) internal pure returns (bytes28 result) {
bytes20 oldValue = extract_28_20(self, offset);
assembly ("memory-safe") {
value := and(value, shl(96, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_22(bytes28 self, uint8 offset) internal pure returns (bytes22 result) {
if (offset > 6) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(80, not(0)))
}
}
function replace_28_22(bytes28 self, bytes22 value, uint8 offset) internal pure returns (bytes28 result) {
bytes22 oldValue = extract_28_22(self, offset);
assembly ("memory-safe") {
value := and(value, shl(80, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_28_24(bytes28 self, uint8 offset) internal pure returns (bytes24 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(64, not(0)))
}
}
function replace_28_24(bytes28 self, bytes24 value, uint8 offset) internal pure returns (bytes28 result) {
bytes24 oldValue = extract_28_24(self, offset);
assembly ("memory-safe") {
value := and(value, shl(64, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_1(bytes32 self, uint8 offset) internal pure returns (bytes1 result) {
if (offset > 31) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(248, not(0)))
}
}
function replace_32_1(bytes32 self, bytes1 value, uint8 offset) internal pure returns (bytes32 result) {
bytes1 oldValue = extract_32_1(self, offset);
assembly ("memory-safe") {
value := and(value, shl(248, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_2(bytes32 self, uint8 offset) internal pure returns (bytes2 result) {
if (offset > 30) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(240, not(0)))
}
}
function replace_32_2(bytes32 self, bytes2 value, uint8 offset) internal pure returns (bytes32 result) {
bytes2 oldValue = extract_32_2(self, offset);
assembly ("memory-safe") {
value := and(value, shl(240, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_4(bytes32 self, uint8 offset) internal pure returns (bytes4 result) {
if (offset > 28) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(224, not(0)))
}
}
function replace_32_4(bytes32 self, bytes4 value, uint8 offset) internal pure returns (bytes32 result) {
bytes4 oldValue = extract_32_4(self, offset);
assembly ("memory-safe") {
value := and(value, shl(224, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_6(bytes32 self, uint8 offset) internal pure returns (bytes6 result) {
if (offset > 26) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(208, not(0)))
}
}
function replace_32_6(bytes32 self, bytes6 value, uint8 offset) internal pure returns (bytes32 result) {
bytes6 oldValue = extract_32_6(self, offset);
assembly ("memory-safe") {
value := and(value, shl(208, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_8(bytes32 self, uint8 offset) internal pure returns (bytes8 result) {
if (offset > 24) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(192, not(0)))
}
}
function replace_32_8(bytes32 self, bytes8 value, uint8 offset) internal pure returns (bytes32 result) {
bytes8 oldValue = extract_32_8(self, offset);
assembly ("memory-safe") {
value := and(value, shl(192, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_10(bytes32 self, uint8 offset) internal pure returns (bytes10 result) {
if (offset > 22) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(176, not(0)))
}
}
function replace_32_10(bytes32 self, bytes10 value, uint8 offset) internal pure returns (bytes32 result) {
bytes10 oldValue = extract_32_10(self, offset);
assembly ("memory-safe") {
value := and(value, shl(176, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_12(bytes32 self, uint8 offset) internal pure returns (bytes12 result) {
if (offset > 20) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(160, not(0)))
}
}
function replace_32_12(bytes32 self, bytes12 value, uint8 offset) internal pure returns (bytes32 result) {
bytes12 oldValue = extract_32_12(self, offset);
assembly ("memory-safe") {
value := and(value, shl(160, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_16(bytes32 self, uint8 offset) internal pure returns (bytes16 result) {
if (offset > 16) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(128, not(0)))
}
}
function replace_32_16(bytes32 self, bytes16 value, uint8 offset) internal pure returns (bytes32 result) {
bytes16 oldValue = extract_32_16(self, offset);
assembly ("memory-safe") {
value := and(value, shl(128, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_20(bytes32 self, uint8 offset) internal pure returns (bytes20 result) {
if (offset > 12) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(96, not(0)))
}
}
function replace_32_20(bytes32 self, bytes20 value, uint8 offset) internal pure returns (bytes32 result) {
bytes20 oldValue = extract_32_20(self, offset);
assembly ("memory-safe") {
value := and(value, shl(96, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_22(bytes32 self, uint8 offset) internal pure returns (bytes22 result) {
if (offset > 10) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(80, not(0)))
}
}
function replace_32_22(bytes32 self, bytes22 value, uint8 offset) internal pure returns (bytes32 result) {
bytes22 oldValue = extract_32_22(self, offset);
assembly ("memory-safe") {
value := and(value, shl(80, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_24(bytes32 self, uint8 offset) internal pure returns (bytes24 result) {
if (offset > 8) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(64, not(0)))
}
}
function replace_32_24(bytes32 self, bytes24 value, uint8 offset) internal pure returns (bytes32 result) {
bytes24 oldValue = extract_32_24(self, offset);
assembly ("memory-safe") {
value := and(value, shl(64, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
function extract_32_28(bytes32 self, uint8 offset) internal pure returns (bytes28 result) {
if (offset > 4) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(32, not(0)))
}
}
function replace_32_28(bytes32 self, bytes28 value, uint8 offset) internal pure returns (bytes32 result) {
bytes28 oldValue = extract_32_28(self, offset);
assembly ("memory-safe") {
value := and(value, shl(32, not(0)))
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";
/**
* @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*/
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
* {IERC721-setApprovalForAll}.
*/
abstract contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (interfaces/draft-IERC4337.sol)
pragma solidity ^0.8.20;
/**
* @dev A https://github.com/ethereum/ercs/blob/master/ERCS/erc-4337.md#useroperation[user operation] is composed of the following elements:
* - `sender` (`address`): The account making the operation
* - `nonce` (`uint256`): Anti-replay parameter (see “Semi-abstracted Nonce Support” )
* - `factory` (`address`): account factory, only for new accounts
* - `factoryData` (`bytes`): data for account factory (only if account factory exists)
* - `callData` (`bytes`): The data to pass to the sender during the main execution call
* - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call
* - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step
* - `preVerificationGas` (`uint256`): Extra gas to pay the bundler
* - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas)
* - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas)
* - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself)
* - `paymasterVerificationGasLimit` (`uint256`): The amount of gas to allocate for the paymaster validation code
* - `paymasterPostOpGasLimit` (`uint256`): The amount of gas to allocate for the paymaster post-operation code
* - `paymasterData` (`bytes`): Data for paymaster (only if paymaster exists)
* - `signature` (`bytes`): Data passed into the account to verify authorization
*
* When passed to on-chain contacts, the following packed version is used.
* - `sender` (`address`)
* - `nonce` (`uint256`)
* - `initCode` (`bytes`): concatenation of factory address and factoryData (or empty)
* - `callData` (`bytes`)
* - `accountGasLimits` (`bytes32`): concatenation of verificationGas (16 bytes) and callGas (16 bytes)
* - `preVerificationGas` (`uint256`)
* - `gasFees` (`bytes32`): concatenation of maxPriorityFeePerGas (16 bytes) and maxFeePerGas (16 bytes)
* - `paymasterAndData` (`bytes`): concatenation of paymaster fields (or empty)
* - `signature` (`bytes`)
*/
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode; // `abi.encodePacked(factory, factoryData)`
bytes callData;
bytes32 accountGasLimits; // `abi.encodePacked(verificationGasLimit, callGasLimit)` 16 bytes each
uint256 preVerificationGas;
bytes32 gasFees; // `abi.encodePacked(maxPriorityFeePerGas, maxFeePerGas)` 16 bytes each
bytes paymasterAndData; // `abi.encodePacked(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData)` (20 bytes, 16 bytes, 16 bytes, dynamic)
bytes signature;
}
/**
* @dev Aggregates and validates multiple signatures for a batch of user operations.
*
* A contract could implement this interface with custom validation schemes that allow signature aggregation,
* enabling significant optimizations and gas savings for execution and transaction data cost.
*
* Bundlers and clients whitelist supported aggregators.
*
* See https://eips.ethereum.org/EIPS/eip-7766[ERC-7766]
*/
interface IAggregator {
/**
* @dev Validates the signature for a user operation.
* Returns an alternative signature that should be used during bundling.
*/
function validateUserOpSignature(
PackedUserOperation calldata userOp
) external view returns (bytes memory sigForUserOp);
/**
* @dev Returns an aggregated signature for a batch of user operation's signatures.
*/
function aggregateSignatures(
PackedUserOperation[] calldata userOps
) external view returns (bytes memory aggregatesSignature);
/**
* @dev Validates that the aggregated signature is valid for the user operations.
*
* Requirements:
*
* - The aggregated signature MUST match the given list of operations.
*/
function validateSignatures(PackedUserOperation[] calldata userOps, bytes calldata signature) external view;
}
/**
* @dev Handle nonce management for accounts.
*
* Nonces are used in accounts as a replay protection mechanism and to ensure the order of user operations.
* To avoid limiting the number of operations an account can perform, the interface allows using parallel
* nonces by using a `key` parameter.
*
* See https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 semi-abstracted nonce support].
*/
interface IEntryPointNonces {
/**
* @dev Returns the nonce for a `sender` account and a `key`.
*
* Nonces for a certain `key` are always increasing.
*/
function getNonce(address sender, uint192 key) external view returns (uint256 nonce);
}
/**
* @dev Handle stake management for entities (i.e. accounts, paymasters, factories).
*
* The EntryPoint must implement the following API to let entities like paymasters have a stake,
* and thus have more flexibility in their storage access
* (see https://eips.ethereum.org/EIPS/eip-4337#reputation-scoring-and-throttlingbanning-for-global-entities[reputation, throttling and banning.])
*/
interface IEntryPointStake {
/**
* @dev Returns the balance of the account.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Deposits `msg.value` to the account.
*/
function depositTo(address account) external payable;
/**
* @dev Withdraws `withdrawAmount` from the account to `withdrawAddress`.
*/
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external;
/**
* @dev Adds stake to the account with an unstake delay of `unstakeDelaySec`.
*/
function addStake(uint32 unstakeDelaySec) external payable;
/**
* @dev Unlocks the stake of the account.
*/
function unlockStake() external;
/**
* @dev Withdraws the stake of the account to `withdrawAddress`.
*/
function withdrawStake(address payable withdrawAddress) external;
}
/**
* @dev Entry point for user operations.
*
* User operations are validated and executed by this contract.
*/
interface IEntryPoint is IEntryPointNonces, IEntryPointStake {
/**
* @dev A user operation at `opIndex` failed with `reason`.
*/
error FailedOp(uint256 opIndex, string reason);
/**
* @dev A user operation at `opIndex` failed with `reason` and `inner` returned data.
*/
error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner);
/**
* @dev Batch of aggregated user operations per aggregator.
*/
struct UserOpsPerAggregator {
PackedUserOperation[] userOps;
IAggregator aggregator;
bytes signature;
}
/**
* @dev Executes a batch of user operations.
* @param beneficiary Address to which gas is refunded up completing the execution.
*/
function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary) external;
/**
* @dev Executes a batch of aggregated user operations per aggregator.
* @param beneficiary Address to which gas is refunded up completing the execution.
*/
function handleAggregatedOps(
UserOpsPerAggregator[] calldata opsPerAggregator,
address payable beneficiary
) external;
}
/**
* @dev Base interface for an ERC-4337 account.
*/
interface IAccount {
/**
* @dev Validates a user operation.
*
* * MUST validate the caller is a trusted EntryPoint
* * MUST validate that the signature is a valid signature of the userOpHash, and SHOULD
* return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error MUST revert.
* * MUST pay the entryPoint (caller) at least the “missingAccountFunds” (which might
* be zero, in case the current account’s deposit is high enough)
*
* Returns an encoded packed validation data that is composed of the following elements:
*
* - `authorizer` (`address`): 0 for success, 1 for failure, otherwise the address of an authorizer contract
* - `validUntil` (`uint48`): The UserOp is valid only up to this time. Zero for “infinite”.
* - `validAfter` (`uint48`): The UserOp is valid only after this time.
*/
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}
/**
* @dev Support for executing user operations by prepending the {executeUserOp} function selector
* to the UserOperation's `callData`.
*/
interface IAccountExecute {
/**
* @dev Executes a user operation.
*/
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external;
}
/**
* @dev Interface for a paymaster contract that agrees to pay for the gas costs of a user operation.
*
* NOTE: A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.
*/
interface IPaymaster {
enum PostOpMode {
opSucceeded,
opReverted,
postOpReverted
}
/**
* @dev Validates whether the paymaster is willing to pay for the user operation. See
* {IAccount-validateUserOp} for additional information on the return value.
*
* NOTE: Bundlers will reject this method if it modifies the state, unless it's whitelisted.
*/
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (bytes memory context, uint256 validationData);
/**
* @dev Verifies the sender is the entrypoint.
* @param actualGasCost the actual amount paid (by account or paymaster) for this UserOperation
* @param actualUserOpFeePerGas total gas used by this UserOperation (including preVerification, creation, validation and execution)
*/
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC-1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC-1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
using SafeCast for *;
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev The string being parsed contains characters that are not in scope of the given base.
*/
error StringsInvalidChar();
/**
* @dev The string being parsed is not a properly formatted address.
*/
error StringsInvalidAddressFormat();
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly ("memory-safe") {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
/**
* @dev Parse a decimal string and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input) internal pure returns (uint256) {
return parseUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
uint256 result = 0;
for (uint256 i = begin; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 9) return (false, 0);
result *= 10;
result += chr;
}
return (true, result);
}
/**
* @dev Parse a decimal string and returns the value as a `int256`.
*
* Requirements:
* - The string must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input) internal pure returns (int256) {
return parseInt(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
(bool success, int256 value) = tryParseInt(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
* the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
}
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
/**
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character or if the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, int256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseIntUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseInt} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseIntUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, int256 value) {
bytes memory buffer = bytes(input);
// Check presence of a negative sign.
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
bool positiveSign = sign == bytes1("+");
bool negativeSign = sign == bytes1("-");
uint256 offset = (positiveSign || negativeSign).toUint();
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
if (absSuccess && absValue < ABS_MIN_INT256) {
return (true, negativeSign ? -int256(absValue) : int256(absValue));
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
return (true, type(int256).min);
} else return (false, 0);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input) internal pure returns (uint256) {
return parseHexUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
* invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseHexUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseHexUint} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseHexUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
// skip 0x prefix if present
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 offset = hasPrefix.toUint() * 2;
uint256 result = 0;
for (uint256 i = begin + offset; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 15) return (false, 0);
result *= 16;
unchecked {
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
// This guaratees that adding a value < 16 will not cause an overflow, hence the unchecked.
result += chr;
}
}
return (true, result);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input) internal pure returns (address) {
return parseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
(bool success, address value) = tryParseAddress(input, begin, end);
if (!success) revert StringsInvalidAddressFormat();
return value;
}
/**
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
* formatted address. See {parseAddress} requirements.
*/
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
return tryParseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
* formatted address. See {parseAddress} requirements.
*/
function tryParseAddress(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, address value) {
if (end > bytes(input).length || begin > end) return (false, address(0));
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
// check that input is the correct length
if (end - begin == expectedLength) {
// length guarantees that this does not overflow, and value is at most type(uint160).max
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
return (s, address(uint160(v)));
} else {
return (false, address(0));
}
}
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
uint8 value = uint8(chr);
// Try to parse `chr`:
// - Case 1: [0-9]
// - Case 2: [a-f]
// - Case 3: [A-F]
// - otherwise not supported
unchecked {
if (value > 47 && value < 58) value -= 48;
else if (value > 96 && value < 103) value -= 87;
else if (value > 64 && value < 71) value -= 55;
else return type(uint8).max;
}
return value;
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(buffer, add(0x20, offset)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 1);
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 1);
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}{
"remappings": [
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"forge-std/=node_modules/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": true,
"bytecodeHash": "none",
"appendCBOR": true
},
"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
Contract ABI
API[{"inputs":[{"internalType":"address","name":"killswitchContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"ERC7579DecodingError","type":"error"},{"inputs":[{"internalType":"CallType","name":"callType","type":"bytes1"}],"name":"ERC7579UnsupportedCallType","type":"error"},{"inputs":[{"internalType":"ExecType","name":"execType","type":"bytes1"}],"name":"ERC7579UnsupportedExecType","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExecutionDataExtractionError","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ExpiredSignature","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"OpDataDecodingError","type":"error"},{"inputs":[],"name":"OutOfRangeAccess","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"UnauthorizedExecution","type":"error"},{"inputs":[],"name":"UnsupportedExecutionMode","type":"error"},{"inputs":[{"internalType":"bytes4","name":"modeSelector","type":"bytes4"}],"name":"UnsupportedModeSelector","type":"error"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mode","type":"bytes32"},{"internalType":"bytes","name":"executionData","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint248","name":"wordPos","type":"uint248"}],"name":"getNonceBitmap","outputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"invalidateNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isNonceUsed","outputs":[{"internalType":"bool","name":"isUsed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"isPausedState","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mode","type":"bytes32"}],"name":"supportsExecutionMode","outputs":[{"internalType":"bool","name":"isSupported","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"isSupported","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
61010080604052346101b257602081611e83803803809161002082856101b7565b8339810103126101b257516001600160a01b038116908190036101b2574660a05260c0516004916020916001600160a01b0316806101ad5750305b604051838101917f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218835246604083015260018060a01b03166060820152606081526100a76080826101b7565b5190206080523060c0528060e05260405192838092635c975abb60e01b82525afa9081156101a15760009161015f575b5061014e57604051611c9290816101f1823960805181611a1f015260a051816119f9015260c0518181816101c60152818161038d015281816104c60152818161060f015281816106cf01528181610754015281816108740152818161155101526119b4015260e05181818161017901526104430152f35b63340aafcd60e11b60005260046000fd5b6020813d602011610199575b81610178602093836101b7565b8101031261019557519081151582036101925750386100d7565b80fd5b5080fd5b3d915061016b565b6040513d6000823e3d90fd5b61005b565b600080fd5b601f909101601f19168101906001600160401b038211908210176101da57604052565b634e487b7160e01b600052604160045260246000fdfe6080806040526004361015610028575b5036156100205761001e61153a565b005b61001e61153a565b60003560e01c90816301ffc9a71461081e57508063150b7a02146107b05780631626ba7e1461072c5780634abb262a1461067b5780635d00bb12146105e457806384b0196e1461049e578063b187bd26146103ef578063b70e36f014610365578063bc197c81146102b5578063d03c791414610284578063e9ae5c531461012c5763f23a6e61146100b9573861000f565b346101275760a0600319360112610127576100d2610990565b506100db6109b3565b5060843567ffffffffffffffff8111610127576100fc903690600401610a7b565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b600080fd5b61013536610a99565b906040517f5c975abb00000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa90811561027857600091610249575b5061021f5773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f55761001e92610c8a565b7f9f03a0260000000000000000000000000000000000000000000000000000000060005260046000fd5b7fd93c06650000000000000000000000000000000000000000000000000000000060005260046000fd5b61026b915060203d602011610271575b61026381836109d6565b810190610c39565b846101aa565b503d610259565b6040513d6000823e3d90fd5b346101275760206003193601126101275760206102a26004356115ea565b6102ab81610c51565b6040519015158152f35b346101275760a0600319360112610127576102ce610990565b506102d76109b3565b5060443567ffffffffffffffff8111610127576102f8903690600401610b46565b5060643567ffffffffffffffff811161012757610319903690600401610b46565b5060843567ffffffffffffffff81116101275761033a903690600401610a7b565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f5573033036103c55761001e600435611579565b7f5c427cd90000000000000000000000000000000000000000000000000000000060005260046000fd5b34610127576000600319360112610127576040517f5c975abb00000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa801561027857602091600091610481575b506040519015158152f35b6104989150823d84116102715761026381836109d6565b82610476565b346101275760006003193601126101275773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f5576105856020604051906104ff81836109d6565b600082526040519061051181836109d6565b6000825261051d6119b2565b73ffffffffffffffffffffffffffffffffffffffff6105936040519461054385876109d6565b6000865260003681376040519788977f0c00000000000000000000000000000000000000000000000000000000000000895260e0878a015260e0890190610aed565b908782036040890152610aed565b91466060870152166080850152600060a085015283810360c085015281808451928381520193019160005b8281106105cd57505050500390f35b8351855286955093810193928101926001016105be565b346101275760206003193601126101275760043573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f557600160209160ff8160081c9116906000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab70083521b604060002054161515604051908152f35b34610127576020600319360112610127576004357effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168091036101275773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f5576000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab7006020526020604060002054604051908152f35b346101275761073a36610a99565b73ffffffffffffffffffffffffffffffffffffffff9291927f00000000000000000000000000000000000000000000000000000000000000001630146101f55760209261078692610ba3565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b34610127576080600319360112610127576107c9610990565b506107d26109b3565b5060643567ffffffffffffffff8111610127576107f3903690600401610a7b565b5060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b3461012757602060031936011261012757600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101275773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f557817f399225470000000000000000000000000000000000000000000000000000000060209314908115610966575b81156108d6575b5015158152f35b7f150b7a0200000000000000000000000000000000000000000000000000000000811491508115610909575b50836108cf565b7f4e2312e00000000000000000000000000000000000000000000000000000000081149150811561093c575b5083610902565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610935565b7f1626ba7e00000000000000000000000000000000000000000000000000000000811491506108c8565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361012757565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361012757565b90601f601f19910116810190811067ffffffffffffffff8211176109f957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff81116109f957601f01601f191660200190565b929192610a5082610a28565b91610a5e60405193846109d6565b829481845281830111610127578281602093846000960137010152565b9080601f8301121561012757816020610a9693359101610a44565b90565b6040600319820112610127576004359160243567ffffffffffffffff811161012757826023820112156101275780600401359267ffffffffffffffff84116101275760248483010111610127576024019190565b919082519283825260005b848110610b19575050601f19601f8460006020809697860101520116010190565b80602080928401015182828601015201610af8565b67ffffffffffffffff81116109f95760051b60200190565b9080601f83011215610127578135610b5d81610b2e565b92610b6b60405194856109d6565b81845260208085019260051b82010192831161012757602001905b828210610b935750505090565b8135815260209182019101610b86565b610bc7610bcd9273ffffffffffffffffffffffffffffffffffffffff943691610a44565b90611976565b50911630149081610c27575b5015610c03577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b7fffffffff0000000000000000000000000000000000000000000000000000000090565b9050610c3281610c51565b1538610bd9565b90816020910312610127575180151581036101275790565b60041115610c5b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90610c94826115ea565b91610c9e83610c51565b82156113a357369180359060208210611366578181019060208201946040833594101560001461139a57506020810135604081108015611390575b61136657810196602088019735915b8215611308575050608181036112de57806020116101275786359281604011610127576020880135957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0604060009a019301938742116112b257610d4b86611579565b610d5489610c51565b6001891461110d5750610d6688610c51565b60028814610db15750505050505050600390610d8181610c51565b14610d895750565b807f7daadde30000000000000000000000000000000000000000000000000000000060049252fd5b610dc392939497509894979598611690565b929091610dcf84610b2e565b98610ddd6040519a8b6109d6565b848a5260208a018560051b85013681116111095785915b81831061103857505050895197610e23610e0d8a610b2e565b99610e1b6040519b8c6109d6565b808b52610b2e565b99601f1960208b019b01368c37885b8c51811015610ee757808b610ee08f938473ffffffffffffffffffffffffffffffffffffffff610e6483600198611962565b515116906040610e83846020610e7a8286611962565b51015193611962565b510151602081519101206040519160208301937fc7893c18b7bfea9418ca400815946cd740f303b74b0ff88fb938f83d0c1bd94e855260408401526060830152608082015260808152610ed760a0826109d6565b51902092611962565b5201610e32565b509295989194979a5092959860405190602082018093519091908d5b818110611022575050509473ffffffffffffffffffffffffffffffffffffffff9794610fcd610bc795610fbf610fe69a9686610f4e610fd598610fdd9d03601f1981018352826109d6565b51902060405194859360208501973393899360a09373ffffffffffffffffffffffffffffffffffffffff939796929760c08701987fddfe073f873bee5d1c9e29281fa37f2d0716a8e75ec88b673b4ec2a7c850ec3f8852602088015260408701526060860152608085015216910152565b03601f1981018352826109d6565b5190206119f3565b923691610a44565b90929192611ae1565b163003610ffa57610ff89293506117a0565b565b6004847f7daadde3000000000000000000000000000000000000000000000000000000008152fd5b8251845260209384019390920191600101610f03565b823567ffffffffffffffff811161110557870160608136031261110557604051906060820182811067ffffffffffffffff8211176110d857604052803573ffffffffffffffffffffffffffffffffffffffff811681036110d457825260208101356020830152604081013567ffffffffffffffff81116110d457916110c4602094928594369101610a7b565b6040820152815201920191610df4565b8c80fd5b60248d7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8a80fd5b8880fd5b9591809795985060149a999a116112ae573560601c93866034116112ae57603486013595605401967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc019736611164908a8a610a44565b8051906020012060405160208101917fc7893c18b7bfea9418ca400815946cd740f303b74b0ff88fb938f83d0c1bd94e83528860408301528960608301526080820152608081526111b660a0826109d6565b51902060405160208101918252602081526111d26040826109d6565b519020604080517fddfe073f873bee5d1c9e29281fa37f2d0716a8e75ec88b673b4ec2a7c850ec3f60208201908152918101929092526060820193909352608081019390935260a08301523360c08084019190915282529061123560e0826109d6565b519020611241906119f3565b91369061124d92610a44565b61125691611976565b61125f91611ae1565b73ffffffffffffffffffffffffffffffffffffffff16300361128657610ff8949550611858565b6004867f7daadde3000000000000000000000000000000000000000000000000000000008152fd5b8980fd5b60248a897fbd2a913c000000000000000000000000000000000000000000000000000000008252600452fd5b7f59d8e20f0000000000000000000000000000000000000000000000000000000060005260046000fd5b9695509650505050503033036103c55760019061132481610c51565b1461133c57610ff89161133691611690565b906117a0565b7f7daadde30000000000000000000000000000000000000000000000000000000060005260046000fd5b7fec3e6d970000000000000000000000000000000000000000000000000000000060005260046000fd5b5087811015610cd9565b96600091610ce8565b7fff000000000000000000000000000000000000000000000000000000000000008116907fffffffff000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000008260081b169160301b169180158015611511575b156114e45750806114b757507f7821000100000000000000000000000000000000000000000000000000000000811480156114af575b15611482577f7f1812750000000000000000000000000000000000000000000000000000000060005260046000fd5b7fb73f9c5a0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b508015611453565b7f23a240850000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fb1be6a960000000000000000000000000000000000000000000000000000000060005260045260246000fd5b507f0100000000000000000000000000000000000000000000000000000000000000811461141d565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630146101f557565b600160ff8260081c92161b906000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab70060205260406000208181541880915516156115c057565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fffffffffffffffffffff0000000000000000000000000000000000000000000016797821000100000000000000000000000000000000000000000000811461168a577f01000000000078210001000000000000000000000000000000000000000000008114611684577f01000000000000000000000000000000000000000000000000000000000000001461167f57600090565b600390565b50600290565b50600190565b919091602083106116eb578260201161012757803590601f19840182116116eb5760006020830180841161172d57851061172a575081019081359367ffffffffffffffff8511918215611715575b50506116eb576020019190565b7feb0bcc5d0000000000000000000000000000000000000000000000000000000060005260046000fd5b601f199192508560051b9203011038806116de565b80fd5b5080fd5b91908110156117715760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610127570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005b8181106117b057505050565b6117bb818385611731565b359073ffffffffffffffffffffffffffffffffffffffff821682036101275760206117e7828587611731565b0135916117f5828587611731565b6040810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff82116101275760200181360381136101275760019461185293611858565b016117a4565b9190913073ffffffffffffffffffffffffffffffffffffffff82161480611957575b80611902575b6118d8578360009384936118cd966040519384928337810185815203925af13d156118d0573d906118b082610a28565b916118be60405193846109d6565b82523d6000602084013e611bae565b50565b606090611bae565b7f37ed32e80000000000000000000000000000000000000000000000000000000060005260046000fd5b5083600411610127577fb70e36f0000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008335161415611880565b50600484101561187a565b80518210156117715760209160051b010190565b81519190604183036119a7576119a092506020820151906060604084015193015160001a90611bef565b9192909190565b505060009160029190565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8116610a9657503090565b604290467f000000000000000000000000000000000000000000000000000000000000000003611a75577f0000000000000000000000000000000000000000000000000000000000000000905b604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b611a7d6119b2565b60405173ffffffffffffffffffffffffffffffffffffffff60208201927f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218845246604084015216606082015260608152611ad86080826109d6565b51902090611a40565b611aea81610c51565b80611af3575050565b611afc81610c51565b60018103611b2e577ff645eedf0000000000000000000000000000000000000000000000000000000060005260046000fd5b611b3781610c51565b60028103611b6d57507ffce698f70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b600390611b7981610c51565b14611b815750565b7fd78bce0c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b909190610ff85750805115611bc557805190602001fd5b7fd6bda2750000000000000000000000000000000000000000000000000000000060005260046000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611c79579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156102785760005173ffffffffffffffffffffffffffffffffffffffff811615611c6d5790600090600090565b50600090600190600090565b5050506000916003919056fea164736f6c634300081b000a00000000000000000000000000000000fb2736c301e53904409f03de06c8467a
Deployed Bytecode
0x6080806040526004361015610028575b5036156100205761001e61153a565b005b61001e61153a565b60003560e01c90816301ffc9a71461081e57508063150b7a02146107b05780631626ba7e1461072c5780634abb262a1461067b5780635d00bb12146105e457806384b0196e1461049e578063b187bd26146103ef578063b70e36f014610365578063bc197c81146102b5578063d03c791414610284578063e9ae5c531461012c5763f23a6e61146100b9573861000f565b346101275760a0600319360112610127576100d2610990565b506100db6109b3565b5060843567ffffffffffffffff8111610127576100fc903690600401610a7b565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b600080fd5b61013536610a99565b906040517f5c975abb00000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000fb2736c301e53904409f03de06c8467a165afa90811561027857600091610249575b5061021f5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f55761001e92610c8a565b7f9f03a0260000000000000000000000000000000000000000000000000000000060005260046000fd5b7fd93c06650000000000000000000000000000000000000000000000000000000060005260046000fd5b61026b915060203d602011610271575b61026381836109d6565b810190610c39565b846101aa565b503d610259565b6040513d6000823e3d90fd5b346101275760206003193601126101275760206102a26004356115ea565b6102ab81610c51565b6040519015158152f35b346101275760a0600319360112610127576102ce610990565b506102d76109b3565b5060443567ffffffffffffffff8111610127576102f8903690600401610b46565b5060643567ffffffffffffffff811161012757610319903690600401610b46565b5060843567ffffffffffffffff81116101275761033a903690600401610a7b565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b346101275760206003193601126101275773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f5573033036103c55761001e600435611579565b7f5c427cd90000000000000000000000000000000000000000000000000000000060005260046000fd5b34610127576000600319360112610127576040517f5c975abb00000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000fb2736c301e53904409f03de06c8467a165afa801561027857602091600091610481575b506040519015158152f35b6104989150823d84116102715761026381836109d6565b82610476565b346101275760006003193601126101275773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f5576105856020604051906104ff81836109d6565b600082526040519061051181836109d6565b6000825261051d6119b2565b73ffffffffffffffffffffffffffffffffffffffff6105936040519461054385876109d6565b6000865260003681376040519788977f0c00000000000000000000000000000000000000000000000000000000000000895260e0878a015260e0890190610aed565b908782036040890152610aed565b91466060870152166080850152600060a085015283810360c085015281808451928381520193019160005b8281106105cd57505050500390f35b8351855286955093810193928101926001016105be565b346101275760206003193601126101275760043573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f557600160209160ff8160081c9116906000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab70083521b604060002054161515604051908152f35b34610127576020600319360112610127576004357effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168091036101275773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f5576000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab7006020526020604060002054604051908152f35b346101275761073a36610a99565b73ffffffffffffffffffffffffffffffffffffffff9291927f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f55760209261078692610ba3565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b34610127576080600319360112610127576107c9610990565b506107d26109b3565b5060643567ffffffffffffffff8111610127576107f3903690600401610a7b565b5060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b3461012757602060031936011261012757600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101275773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f557817f399225470000000000000000000000000000000000000000000000000000000060209314908115610966575b81156108d6575b5015158152f35b7f150b7a0200000000000000000000000000000000000000000000000000000000811491508115610909575b50836108cf565b7f4e2312e00000000000000000000000000000000000000000000000000000000081149150811561093c575b5083610902565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610935565b7f1626ba7e00000000000000000000000000000000000000000000000000000000811491506108c8565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361012757565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361012757565b90601f601f19910116810190811067ffffffffffffffff8211176109f957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff81116109f957601f01601f191660200190565b929192610a5082610a28565b91610a5e60405193846109d6565b829481845281830111610127578281602093846000960137010152565b9080601f8301121561012757816020610a9693359101610a44565b90565b6040600319820112610127576004359160243567ffffffffffffffff811161012757826023820112156101275780600401359267ffffffffffffffff84116101275760248483010111610127576024019190565b919082519283825260005b848110610b19575050601f19601f8460006020809697860101520116010190565b80602080928401015182828601015201610af8565b67ffffffffffffffff81116109f95760051b60200190565b9080601f83011215610127578135610b5d81610b2e565b92610b6b60405194856109d6565b81845260208085019260051b82010192831161012757602001905b828210610b935750505090565b8135815260209182019101610b86565b610bc7610bcd9273ffffffffffffffffffffffffffffffffffffffff943691610a44565b90611976565b50911630149081610c27575b5015610c03577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b7fffffffff0000000000000000000000000000000000000000000000000000000090565b9050610c3281610c51565b1538610bd9565b90816020910312610127575180151581036101275790565b60041115610c5b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b90610c94826115ea565b91610c9e83610c51565b82156113a357369180359060208210611366578181019060208201946040833594101560001461139a57506020810135604081108015611390575b61136657810196602088019735915b8215611308575050608181036112de57806020116101275786359281604011610127576020880135957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0604060009a019301938742116112b257610d4b86611579565b610d5489610c51565b6001891461110d5750610d6688610c51565b60028814610db15750505050505050600390610d8181610c51565b14610d895750565b807f7daadde30000000000000000000000000000000000000000000000000000000060049252fd5b610dc392939497509894979598611690565b929091610dcf84610b2e565b98610ddd6040519a8b6109d6565b848a5260208a018560051b85013681116111095785915b81831061103857505050895197610e23610e0d8a610b2e565b99610e1b6040519b8c6109d6565b808b52610b2e565b99601f1960208b019b01368c37885b8c51811015610ee757808b610ee08f938473ffffffffffffffffffffffffffffffffffffffff610e6483600198611962565b515116906040610e83846020610e7a8286611962565b51015193611962565b510151602081519101206040519160208301937fc7893c18b7bfea9418ca400815946cd740f303b74b0ff88fb938f83d0c1bd94e855260408401526060830152608082015260808152610ed760a0826109d6565b51902092611962565b5201610e32565b509295989194979a5092959860405190602082018093519091908d5b818110611022575050509473ffffffffffffffffffffffffffffffffffffffff9794610fcd610bc795610fbf610fe69a9686610f4e610fd598610fdd9d03601f1981018352826109d6565b51902060405194859360208501973393899360a09373ffffffffffffffffffffffffffffffffffffffff939796929760c08701987fddfe073f873bee5d1c9e29281fa37f2d0716a8e75ec88b673b4ec2a7c850ec3f8852602088015260408701526060860152608085015216910152565b03601f1981018352826109d6565b5190206119f3565b923691610a44565b90929192611ae1565b163003610ffa57610ff89293506117a0565b565b6004847f7daadde3000000000000000000000000000000000000000000000000000000008152fd5b8251845260209384019390920191600101610f03565b823567ffffffffffffffff811161110557870160608136031261110557604051906060820182811067ffffffffffffffff8211176110d857604052803573ffffffffffffffffffffffffffffffffffffffff811681036110d457825260208101356020830152604081013567ffffffffffffffff81116110d457916110c4602094928594369101610a7b565b6040820152815201920191610df4565b8c80fd5b60248d7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8a80fd5b8880fd5b9591809795985060149a999a116112ae573560601c93866034116112ae57603486013595605401967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc019736611164908a8a610a44565b8051906020012060405160208101917fc7893c18b7bfea9418ca400815946cd740f303b74b0ff88fb938f83d0c1bd94e83528860408301528960608301526080820152608081526111b660a0826109d6565b51902060405160208101918252602081526111d26040826109d6565b519020604080517fddfe073f873bee5d1c9e29281fa37f2d0716a8e75ec88b673b4ec2a7c850ec3f60208201908152918101929092526060820193909352608081019390935260a08301523360c08084019190915282529061123560e0826109d6565b519020611241906119f3565b91369061124d92610a44565b61125691611976565b61125f91611ae1565b73ffffffffffffffffffffffffffffffffffffffff16300361128657610ff8949550611858565b6004867f7daadde3000000000000000000000000000000000000000000000000000000008152fd5b8980fd5b60248a897fbd2a913c000000000000000000000000000000000000000000000000000000008252600452fd5b7f59d8e20f0000000000000000000000000000000000000000000000000000000060005260046000fd5b9695509650505050503033036103c55760019061132481610c51565b1461133c57610ff89161133691611690565b906117a0565b7f7daadde30000000000000000000000000000000000000000000000000000000060005260046000fd5b7fec3e6d970000000000000000000000000000000000000000000000000000000060005260046000fd5b5087811015610cd9565b96600091610ce8565b7fff000000000000000000000000000000000000000000000000000000000000008116907fffffffff000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000008260081b169160301b169180158015611511575b156114e45750806114b757507f7821000100000000000000000000000000000000000000000000000000000000811480156114af575b15611482577f7f1812750000000000000000000000000000000000000000000000000000000060005260046000fd5b7fb73f9c5a0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b508015611453565b7f23a240850000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fb1be6a960000000000000000000000000000000000000000000000000000000060005260045260246000fd5b507f0100000000000000000000000000000000000000000000000000000000000000811461141d565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b1630146101f557565b600160ff8260081c92161b906000527fb035242b6a1b64fd1e2d869c03a3cc0e80fe7f55db29c2560bab38e489fab70060205260406000208181541880915516156115c057565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b7fffffffffffffffffffff0000000000000000000000000000000000000000000016797821000100000000000000000000000000000000000000000000811461168a577f01000000000078210001000000000000000000000000000000000000000000008114611684577f01000000000000000000000000000000000000000000000000000000000000001461167f57600090565b600390565b50600290565b50600190565b919091602083106116eb578260201161012757803590601f19840182116116eb5760006020830180841161172d57851061172a575081019081359367ffffffffffffffff8511918215611715575b50506116eb576020019190565b7feb0bcc5d0000000000000000000000000000000000000000000000000000000060005260046000fd5b601f199192508560051b9203011038806116de565b80fd5b5080fd5b91908110156117715760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610127570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005b8181106117b057505050565b6117bb818385611731565b359073ffffffffffffffffffffffffffffffffffffffff821682036101275760206117e7828587611731565b0135916117f5828587611731565b6040810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610127570180359067ffffffffffffffff82116101275760200181360381136101275760019461185293611858565b016117a4565b9190913073ffffffffffffffffffffffffffffffffffffffff82161480611957575b80611902575b6118d8578360009384936118cd966040519384928337810185815203925af13d156118d0573d906118b082610a28565b916118be60405193846109d6565b82523d6000602084013e611bae565b50565b606090611bae565b7f37ed32e80000000000000000000000000000000000000000000000000000000060005260046000fd5b5083600411610127577fb70e36f0000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008335161415611880565b50600484101561187a565b80518210156117715760209160051b010190565b81519190604183036119a7576119a092506020820151906060604084015193015160001a90611bef565b9192909190565b505060009160029190565b7f0000000000000000000000000000fb7702036ff9f76044a501ac1aa74cbab16b73ffffffffffffffffffffffffffffffffffffffff8116610a9657503090565b604290467f000000000000000000000000000000000000000000000000000000000000a4b103611a75577fcc042d8ae877a570f339d24ce43fb4c733a240fc6b0b58a9601914707bc871a8905b604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b611a7d6119b2565b60405173ffffffffffffffffffffffffffffffffffffffff60208201927f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218845246604084015216606082015260608152611ad86080826109d6565b51902090611a40565b611aea81610c51565b80611af3575050565b611afc81610c51565b60018103611b2e577ff645eedf0000000000000000000000000000000000000000000000000000000060005260046000fd5b611b3781610c51565b60028103611b6d57507ffce698f70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b600390611b7981610c51565b14611b815750565b7fd78bce0c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b909190610ff85750805115611bc557805190602001fd5b7fd6bda2750000000000000000000000000000000000000000000000000000000060005260046000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611c79579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156102785760005173ffffffffffffffffffffffffffffffffffffffff811615611c6d5790600090600090565b50600090600190600090565b5050506000916003919056fea164736f6c634300081b000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000fb2736c301e53904409f03de06c8467a
-----Decoded View---------------
Arg [0] : killswitchContract (address): 0x00000000FB2736C301E53904409f03De06c8467A
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000fb2736c301e53904409f03de06c8467a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.