xDAI Price: $0.99954 (+0.01%)

Contract

0x0e4e1a2D851663462523bF38Ca56259aceCCBc76

Overview

XDAI Balance

Gnosis Chain LogoGnosis Chain LogoGnosis Chain Logo0 XDAI

XDAI Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Register Safe By...443097652026-01-23 15:37:5026 hrs ago1769182670IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200002
Register Safe By...443097642026-01-23 15:37:4526 hrs ago1769182665IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200001
Register Safe By...443097602026-01-23 15:37:2526 hrs ago1769182645IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200001
Register Safe By...443097572026-01-23 15:37:1026 hrs ago1769182630IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200001
Register Safe By...443097572026-01-23 15:37:1026 hrs ago1769182630IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200001
Register Safe By...442924062026-01-22 14:14:302 days ago1769091270IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200004
Register Safe By...442899102026-01-22 10:36:152 days ago1769078175IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200004
Register Safe By...442760502026-01-21 14:03:453 days ago1769004225IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200032
Register Safe By...442760402026-01-21 14:02:553 days ago1769004175IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200047
Register Safe By...442631982026-01-20 18:41:203 days ago1768934480IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200002
Register Safe By...442631892026-01-20 18:40:353 days ago1768934435IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200002
Register Safe By...442615452026-01-20 16:17:304 days ago1768925850IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200004
Register Safe By...442606162026-01-20 14:56:054 days ago1768920965IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200026
Register Safe By...442558942026-01-20 8:00:354 days ago1768896035IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200004
Register Safe By...442550612026-01-20 6:46:554 days ago1768891615IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200035
Register Safe By...442550592026-01-20 6:46:454 days ago1768891605IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200032
Register Safe By...442550522026-01-20 6:46:054 days ago1768891565IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200021
Register Safe By...442444762026-01-19 15:02:455 days ago1768834965IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200002
Register Safe By...442444682026-01-19 15:02:005 days ago1768834920IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200002
Register Safe By...442425352026-01-19 12:12:305 days ago1768824750IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200001
Register Safe By...442425322026-01-19 12:12:155 days ago1768824735IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200001
Register Safe By...442425252026-01-19 12:11:355 days ago1768824695IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200001
Register Safe By...442424772026-01-19 12:07:205 days ago1768824440IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200001
Register Safe By...442424672026-01-19 12:06:305 days ago1768824390IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000090.00200001
Register Safe By...442131622026-01-17 16:43:507 days ago1768668230IN
0x0e4e1a2D...aceCCBc76
0 XDAI0.000000040.00200002
View all transactions

View more zero value Internal Transactions in Advanced View mode

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x7b8E16AD...bbB6b1b5C
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
HoprNodeSafeRegistry

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 200 runs

Other Settings:
prague EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import { ECDSA } from "openzeppelin-contracts-5.4.0/utils/cryptography/ECDSA.sol";
import { EfficientHashLib } from "solady-0.1.24/utils/EfficientHashLib.sol";

abstract contract HoprNodeSafeRegistryEvents {
    /**
     * Emitted once a safe and node pair gets registered
     */
    event RegisteredNodeSafe(address indexed safeAddress, address indexed nodeAddress);
    /**
     * Emitted once a safe and node pair gets deregistered
     */
    event DeregisteredNodeSafe(address indexed safeAddress, address indexed nodeAddress);
    /**
     * Emitted once the domain separator is updated.
     */
    event DomainSeparatorUpdated(bytes32 indexed domainSeparator);
}

/**
 *    &&&&
 *    &&&&
 *    &&&&
 *    &&&&  &&&&&&&&&       &&&&&&&&&&&&          &&&&&&&&&&/   &&&&.&&&&&&&&&
 *    &&&&&&&&&   &&&&&   &&&&&&     &&&&&,     &&&&&    &&&&&  &&&&&&&&   &&&&
 *     &&&&&&      &&&&  &&&&#         &&&&   &&&&&       &&&&& &&&&&&     &&&&&
 *     &&&&&       &&&&/ &&&&           &&&& #&&&&        &&&&  &&&&&
 *     &&&&         &&&& &&&&&         &&&&  &&&&        &&&&&  &&&&&
 *     %%%%        /%%%%   %%%%%%   %%%%%%   %%%%  %%%%%%%%%    %%%%%
 *    %%%%%        %%%%      %%%%%%%%%%%    %%%%   %%%%%%       %%%%
 *                                          %%%%
 *                                          %%%%
 *                                          %%%%
 *
 * @title HoprNodeSafeRegistry
 * @dev Node safe must prove that the Safe is the only authorized controller of
 * the CHAIN_KEY address. This link between the Safe and node's chain-key address
 * should be registered upon successful verification
 *
 * The CHAIN_KEY address should not be a contract
 * The Safe addres should be a contract
 * This implies that Safe and CHAIN_KEY address cannot be the same.
 *
 * This contract is meant to be deployed as a standalone contract
 */
contract HoprNodeSafeRegistry is HoprNodeSafeRegistryEvents {
    // Node already has mapped to Safe
    error NodeHasSafe();

    // Not a valid Safe address;
    error NotValidSafe();

    // Not a valid signature from node;
    error NotValidSignatureFromNode();

    // Safe address is zero
    error SafeAddressZero();

    // Node address is zero
    error NodeAddressZero();

    // Node address is a contract
    error NodeIsContract();

    // Provided address is not a member of an enabled NodeManagementModule
    error NodeNotModuleMember();

    // Structure to store the mapping between nodes and their associated Safe contracts
    struct NodeSafeRecord {
        address safeAddress;
        uint96 nodeSigNonce;
    }

    // Structure to represent a node-safe pair with a nonce
    struct NodeSafeNonce {
        address safeAddress;
        address nodeChainKeyAddress;
        uint256 nodeSigNonce;
    }

    // Currently deployed version, starting with 1.0.0
    string public constant VERSION = "1.0.0";

    bytes32 public domainSeparator;
    mapping(address => NodeSafeRecord) _nodeToSafe;
    // NodeSafeNonce struct type hash.
    // keccak256("NodeSafeNonce(address safeAddress,address nodeChainKeyAddress,uint256 nodeSigNonce)");
    bytes32 public constant NODE_SAFE_TYPEHASH = hex"a8ac7aed128d1a2da0773fecc80b6265d15f7e62bf4401eb23bd46c3fcf5d2f8";
    // start and end point for linked list of modules
    address private constant SENTINEL_MODULES = address(0x1);
    // page size of querying modules
    uint256 private constant PAGE_SIZE = 100;

    /**
     * @dev Constructor function to initialize the contract state.
     * Computes the domain separator for EIP-712 verification.
     */
    constructor() {
        // compute the domain separator on deployment
        updateDomainSeparator();
    }

    /**
     * @dev Returns the Safe address associated with a specific node address.
     * @param nodeAddress The address of the Hopr node.
     * @return safeAddress The associated Safe address.
     */
    function nodeToSafe(address nodeAddress) external view returns (address) {
        return _nodeToSafe[nodeAddress].safeAddress;
    }

    /**
     * @dev Returns the nonce of the signature for a specific node address.
     * @param nodeAddress The address of the Hopr node.
     * @return nodeSigNonce The nonce of the node's signature.
     */
    function nodeSigNonce(address nodeAddress) external view returns (uint256) {
        return _nodeToSafe[nodeAddress].nodeSigNonce;
    }

    /**
     * @dev Checks whether a specific node-safe combination is registered.
     * @param safeAddress Address of safe
     * @param nodeChainKeyAddress Address of node
     * @return registered Whether the node-safe combination is registered.
     */
    function isNodeSafeRegistered(address safeAddress, address nodeChainKeyAddress) external view returns (bool) {
        // If node is not registered to any safe, return false
        if (_nodeToSafe[nodeChainKeyAddress].safeAddress == address(0)) {
            return false;
        }

        return _nodeToSafe[nodeChainKeyAddress].safeAddress == safeAddress;
    }

    /**
     * @dev Register the Safe with a signature from the node.
     * This function can be called by any party.
     * @param safeAddress Address of safe
     * @param nodeChainKeyAddress Address of node
     * @param sig The signature provided by the node.
     */
    function registerSafeWithNodeSig(address safeAddress, address nodeChainKeyAddress, bytes calldata sig) external {
        // check adminKeyAddress has added HOPR tokens to the staking contract.

        // Compute the hash of the struct according to EIP712 guidelines
        // using assembly for gas optimization (-95 gas)
        bytes32 hashStruct = EfficientHashLib.hash(
            uint256(NODE_SAFE_TYPEHASH),
            uint256(uint160(safeAddress)),
            uint256(uint160(nodeChainKeyAddress)),
            uint256(_nodeToSafe[nodeChainKeyAddress].nodeSigNonce)
        );

        // Build the typed digest for signature verification
        /// forge-lint: disable-next-line(asm-keccak256)
        bytes32 registerHash = keccak256(abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator, hashStruct));

        // Verify that the signature is from nodeChainKeyAddress
        (address recovered, ECDSA.RecoverError error,) = ECDSA.tryRecover(registerHash, sig);
        if (error != ECDSA.RecoverError.NoError || recovered != nodeChainKeyAddress) {
            revert NotValidSignatureFromNode();
        }

        // store those state, emit events etc.
        addNodeSafe(safeAddress, nodeChainKeyAddress);
    }

    /**
     * @dev Deregisters a Hopr node from its associated Safe and emits relevant events.
     * This function can only be called by the associated Safe.
     * @notice This function does not perform additional checks on whether the node is
     * registered in the active node management module.
     * @param nodeAddr The address of the Hopr node to be deregistered.
     */
    function deregisterNodeBySafe(address nodeAddr) external {
        // check this node was registered to the caller
        if (_nodeToSafe[nodeAddr].safeAddress != msg.sender) {
            revert NotValidSafe();
        }

        // Update the state and emit the event
        _nodeToSafe[nodeAddr].safeAddress = address(0);
        emit DeregisteredNodeSafe(msg.sender, nodeAddr);
    }

    /**
     * @dev Registers a Safe by the node through a direct function call.
     * This function is meant to be called by the Hopr node itself.
     * @param safeAddr The address of the Safe to be registered.
     */
    function registerSafeByNode(address safeAddr) external {
        addNodeSafe(safeAddr, msg.sender);
    }

    /**
     * @dev Recomputes the domain separator in case of a network fork or update.
     * This function should be called by anyone when required.
     * An event is emitted when the domain separator is updated
     */
    function updateDomainSeparator() public {
        // following encoding guidelines of EIP712, using assembly for gas optimization (-60 gas)
        bytes32 newDomainSeparator = EfficientHashLib.hash(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256(bytes("NodeSafeRegistry")),
            keccak256(bytes(VERSION)),
            bytes32(block.chainid),
            bytes32(uint256(uint160(address(this))))
        );

        if (newDomainSeparator != domainSeparator) {
            domainSeparator = newDomainSeparator;
            emit DomainSeparatorUpdated(domainSeparator);
        }
    }

    /**
     * @dev Internal function to store a node-safe pair and emit relevant events.
     * @notice This function does not perform additional checks on whether the node is
     * registered in the active node management module.
     * @param safeAddress Address of safe
     * @param nodeChainKeyAddress Address of node
     */
    function addNodeSafe(address safeAddress, address nodeChainKeyAddress) internal {
        // Safe address cannot be zero
        if (safeAddress == address(0)) {
            revert SafeAddressZero();
        }
        // Safe address cannot be zero
        if (nodeChainKeyAddress == address(0)) {
            revert NodeAddressZero();
        }

        // Ensure that the node address is not a contract address
        if (nodeChainKeyAddress.code.length > 0) {
            revert NodeIsContract();
        }

        // check this node hasn't been registered ower
        if (_nodeToSafe[nodeChainKeyAddress].safeAddress != address(0)) {
            revert NodeHasSafe();
        }

        NodeSafeRecord storage record = _nodeToSafe[nodeChainKeyAddress];

        // update record
        record.safeAddress = safeAddress;
        record.nodeSigNonce++; // as of Solidity 0.8, this reverts on overflows

        // update and emit event
        emit RegisteredNodeSafe(safeAddress, nodeChainKeyAddress);
    }
}

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

File 3 of 3 : EfficientHashLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               MALLOC-LESS HASHING OPERATIONS               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(bytes32 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(uint256 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12,
        bytes32 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12,
        uint256 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*             BYTES32 BUFFER HASHING OPERATIONS              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
    function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
        }
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, bytes32 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, uint256 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
    function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
        /// @solidity memory-safe-assembly
        assembly {
            buffer := mload(0x40)
            mstore(buffer, n)
            mstore(0x40, add(shl(5, add(1, n)), buffer))
        }
    }

    /// @dev Frees memory that has been allocated for `buffer`.
    /// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
    function free(bytes32[] memory buffer) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(buffer)
            mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      EQUALITY CHECKS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `a == abi.decode(b, (bytes32))`.
    function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
        }
    }

    /// @dev Returns `abi.decode(a, (bytes32)) == a`.
    function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               BYTE SLICE HASHING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hash(bytes memory b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hash(bytes memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(b, 0x20), mload(b))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hashCalldata(bytes calldata b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := keccak256(mload(0x40), b.length)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      SHA2-256 HELPERS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
    function sha2(bytes32 b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, b)
            result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2(bytes memory b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(end, start), sub(end, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(n, start), sub(n, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2(bytes memory b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }
}

Settings
{
  "remappings": [
    "forge-std/=../../vendor/solidity/forge-std-1.10.0/src/",
    "openzeppelin-contracts-4.4.2/=../../vendor/solidity/openzeppelin-contracts-4.4.2/contracts/",
    "openzeppelin-contracts-5.4.0/=../../vendor/solidity/openzeppelin-contracts-upgradeable-5.4.0/lib/openzeppelin-contracts/contracts/",
    "safe-contracts-1.4.1/=../../vendor/solidity/safe-contracts-1.4.1/contracts/",
    "safe-contracts-1.5.0/=../../vendor/solidity/safe-contracts-1.5.0/contracts/",
    "openzeppelin-contracts-upgradeable-5.4.0/=../../vendor/solidity/openzeppelin-contracts-upgradeable-5.4.0/contracts/",
    "solcrypto/=../../vendor/solidity/solcrypto/contracts/",
    "solady-0.1.24/=../../vendor/solidity/solady-v0.1.24/src/",
    "@openzeppelin/=../../vendor/solidity/openzeppelin-contracts-upgradeable-5.4.0/lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "prague",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NodeAddressZero","type":"error"},{"inputs":[],"name":"NodeHasSafe","type":"error"},{"inputs":[],"name":"NodeIsContract","type":"error"},{"inputs":[],"name":"NodeNotModuleMember","type":"error"},{"inputs":[],"name":"NotValidSafe","type":"error"},{"inputs":[],"name":"NotValidSignatureFromNode","type":"error"},{"inputs":[],"name":"SafeAddressZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safeAddress","type":"address"},{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"}],"name":"DeregisteredNodeSafe","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"}],"name":"DomainSeparatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safeAddress","type":"address"},{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"}],"name":"RegisteredNodeSafe","type":"event"},{"inputs":[],"name":"NODE_SAFE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddr","type":"address"}],"name":"deregisterNodeBySafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"safeAddress","type":"address"},{"internalType":"address","name":"nodeChainKeyAddress","type":"address"}],"name":"isNodeSafeRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"name":"nodeSigNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"name":"nodeToSafe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"safeAddr","type":"address"}],"name":"registerSafeByNode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"safeAddress","type":"address"},{"internalType":"address","name":"nodeChainKeyAddress","type":"address"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"registerSafeWithNodeSig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"}]

0x608060405234801561000f575f5ffd5b5061001861001d565b610119565b604080518082018252601081526f4e6f646553616665526567697374727960801b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f447fbad4d46bbc04590cba6c2c058e72910ea40398cd34085373b98ea4daa0e8918101919091527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9181019190915246606082015230608082015260a090205f548114610116575f81815560405182917f771f5240ae5fd8a7640d3fb82fa70aab2fb1dbf35f2ef464f8509946717664c591a25b50565b61094f806101265f395ff3fe608060405234801561000f575f5ffd5b506004361061009b575f3560e01c806389ccfe891161006357806389ccfe891461016757806391607c4c1461016f578063aa90f2a514610182578063f698da25146101ba578063ffa1ad74146101c2575f5ffd5b806337480abd1461009f57806349d215e1146100c75780637f935931146100dc57806384b0dec2146100ef57806389978c4014610124575b5f5ffd5b6100b26100ad3660046107bf565b6101f3565b60405190151581526020015b60405180910390f35b6100da6100d53660046107f0565b610241565b005b6100da6100ea36600461087a565b6103a0565b6101167fa8ac7aed128d1a2da0773fecc80b6265d15f7e62bf4401eb23bd46c3fcf5d2f881565b6040519081526020016100be565b61014f61013236600461087a565b6001600160a01b039081165f908152600160205260409020541690565b6040516001600160a01b0390911681526020016100be565b6100da6103ad565b6100da61017d36600461087a565b6104a8565b61011661019036600461087a565b6001600160a01b03165f90815260016020526040902054600160a01b90046001600160601b031690565b6101165f5481565b6101e6604051806040016040528060058152602001640312e302e360dc1b81525081565b6040516100be919061089a565b6001600160a01b038181165f9081526001602052604081205490911661021a57505f61023b565b506001600160a01b038181165f908152600160205260409020548116908316145b92915050565b6001600160a01b038381165f8181526001602090815260408083205481517fa8ac7aed128d1a2da0773fecc80b6265d15f7e62bf4401eb23bd46c3fcf5d2f88152958a1692860192909252840192909252600160a01b9091046001600160601b0316606083015260809091205f8054604051601960f81b6020820152600160f81b6021820152602281019190915260428101839052919250906062016040516020818303038152906040528051906020012090505f5f6103368387878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061053092505050565b5090925090505f81600381111561034f5761034f6108cf565b14158061036e5750866001600160a01b0316826001600160a01b031614155b1561038c5760405163b4c91ffb60e01b815260040160405180910390fd5b6103968888610579565b5050505050505050565b6103aa8133610579565b50565b604080518082018252601081526f4e6f646553616665526567697374727960801b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f447fbad4d46bbc04590cba6c2c058e72910ea40398cd34085373b98ea4daa0e8918101919091527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9181019190915246606082015230608082015260a090205f5481146103aa575f81815560405182917f771f5240ae5fd8a7640d3fb82fa70aab2fb1dbf35f2ef464f8509946717664c591a250565b6001600160a01b038181165f908152600160205260409020541633146104e1576040516315bfa15560e21b815260040160405180910390fd5b6001600160a01b0381165f8181526001602052604080822080546001600160a01b03191690555133917f1eb3e9b31552ebe06015df6569e31abbec0e73a88c3ccdd9fead65c4378b4e5091a350565b5f5f5f8351604103610567576020840151604085015160608601515f1a610559888285856106dc565b955095509550505050610572565b505081515f91506002905b9250925092565b6001600160a01b0382166105a0576040516314e7922160e01b815260040160405180910390fd5b6001600160a01b0381166105c757604051633e876a9360e11b815260040160405180910390fd5b6001600160a01b0381163b156105f057604051631f829f0360e21b815260040160405180910390fd5b6001600160a01b038181165f908152600160205260409020541615610628576040516367dc300160e01b815260040160405180910390fd5b6001600160a01b038181165f90815260016020526040902080546001600160a01b03191691841691909117808255600160a01b90046001600160601b0316816014610672836108e3565b91906101000a8154816001600160601b0302191690836001600160601b0316021790555050816001600160a01b0316836001600160a01b03167f776da40cbf2c223552661bd48502ceb72409b3362bb0c66d8989bd7e20e4497d60405160405180910390a3505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561071557505f9150600390508261079a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610766573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811661079157505f92506001915082905061079a565b92505f91508190505b9450945094915050565b80356001600160a01b03811681146107ba575f5ffd5b919050565b5f5f604083850312156107d0575f5ffd5b6107d9836107a4565b91506107e7602084016107a4565b90509250929050565b5f5f5f5f60608587031215610803575f5ffd5b61080c856107a4565b935061081a602086016107a4565b9250604085013567ffffffffffffffff811115610835575f5ffd5b8501601f81018713610845575f5ffd5b803567ffffffffffffffff81111561085b575f5ffd5b87602082840101111561086c575f5ffd5b949793965060200194505050565b5f6020828403121561088a575f5ffd5b610893826107a4565b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b5f6001600160601b0382166001600160601b03810361091057634e487b7160e01b5f52601160045260245ffd5b6001019291505056fea26469706673582212204696231eca19ccb446bc664ab9e925c9ca98961ba31abff9cbdba0b301bb69ea64736f6c634300081e0033

Deployed Bytecode

0x608060405234801561000f575f5ffd5b506004361061009b575f3560e01c806389ccfe891161006357806389ccfe891461016757806391607c4c1461016f578063aa90f2a514610182578063f698da25146101ba578063ffa1ad74146101c2575f5ffd5b806337480abd1461009f57806349d215e1146100c75780637f935931146100dc57806384b0dec2146100ef57806389978c4014610124575b5f5ffd5b6100b26100ad3660046107bf565b6101f3565b60405190151581526020015b60405180910390f35b6100da6100d53660046107f0565b610241565b005b6100da6100ea36600461087a565b6103a0565b6101167fa8ac7aed128d1a2da0773fecc80b6265d15f7e62bf4401eb23bd46c3fcf5d2f881565b6040519081526020016100be565b61014f61013236600461087a565b6001600160a01b039081165f908152600160205260409020541690565b6040516001600160a01b0390911681526020016100be565b6100da6103ad565b6100da61017d36600461087a565b6104a8565b61011661019036600461087a565b6001600160a01b03165f90815260016020526040902054600160a01b90046001600160601b031690565b6101165f5481565b6101e6604051806040016040528060058152602001640312e302e360dc1b81525081565b6040516100be919061089a565b6001600160a01b038181165f9081526001602052604081205490911661021a57505f61023b565b506001600160a01b038181165f908152600160205260409020548116908316145b92915050565b6001600160a01b038381165f8181526001602090815260408083205481517fa8ac7aed128d1a2da0773fecc80b6265d15f7e62bf4401eb23bd46c3fcf5d2f88152958a1692860192909252840192909252600160a01b9091046001600160601b0316606083015260809091205f8054604051601960f81b6020820152600160f81b6021820152602281019190915260428101839052919250906062016040516020818303038152906040528051906020012090505f5f6103368387878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061053092505050565b5090925090505f81600381111561034f5761034f6108cf565b14158061036e5750866001600160a01b0316826001600160a01b031614155b1561038c5760405163b4c91ffb60e01b815260040160405180910390fd5b6103968888610579565b5050505050505050565b6103aa8133610579565b50565b604080518082018252601081526f4e6f646553616665526567697374727960801b6020918201528151808301835260058152640312e302e360dc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f447fbad4d46bbc04590cba6c2c058e72910ea40398cd34085373b98ea4daa0e8918101919091527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9181019190915246606082015230608082015260a090205f5481146103aa575f81815560405182917f771f5240ae5fd8a7640d3fb82fa70aab2fb1dbf35f2ef464f8509946717664c591a250565b6001600160a01b038181165f908152600160205260409020541633146104e1576040516315bfa15560e21b815260040160405180910390fd5b6001600160a01b0381165f8181526001602052604080822080546001600160a01b03191690555133917f1eb3e9b31552ebe06015df6569e31abbec0e73a88c3ccdd9fead65c4378b4e5091a350565b5f5f5f8351604103610567576020840151604085015160608601515f1a610559888285856106dc565b955095509550505050610572565b505081515f91506002905b9250925092565b6001600160a01b0382166105a0576040516314e7922160e01b815260040160405180910390fd5b6001600160a01b0381166105c757604051633e876a9360e11b815260040160405180910390fd5b6001600160a01b0381163b156105f057604051631f829f0360e21b815260040160405180910390fd5b6001600160a01b038181165f908152600160205260409020541615610628576040516367dc300160e01b815260040160405180910390fd5b6001600160a01b038181165f90815260016020526040902080546001600160a01b03191691841691909117808255600160a01b90046001600160601b0316816014610672836108e3565b91906101000a8154816001600160601b0302191690836001600160601b0316021790555050816001600160a01b0316836001600160a01b03167f776da40cbf2c223552661bd48502ceb72409b3362bb0c66d8989bd7e20e4497d60405160405180910390a3505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561071557505f9150600390508261079a565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610766573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811661079157505f92506001915082905061079a565b92505f91508190505b9450945094915050565b80356001600160a01b03811681146107ba575f5ffd5b919050565b5f5f604083850312156107d0575f5ffd5b6107d9836107a4565b91506107e7602084016107a4565b90509250929050565b5f5f5f5f60608587031215610803575f5ffd5b61080c856107a4565b935061081a602086016107a4565b9250604085013567ffffffffffffffff811115610835575f5ffd5b8501601f81018713610845575f5ffd5b803567ffffffffffffffff81111561085b575f5ffd5b87602082840101111561086c575f5ffd5b949793965060200194505050565b5f6020828403121561088a575f5ffd5b610893826107a4565b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b5f6001600160601b0382166001600160601b03810361091057634e487b7160e01b5f52601160045260245ffd5b6001019291505056fea26469706673582212204696231eca19ccb446bc664ab9e925c9ca98961ba31abff9cbdba0b301bb69ea64736f6c634300081e0033

Block Transaction Gas Used Reward
view all blocks validated

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.