HYPE Price: $22.52 (-2.92%)
 

Overview

HYPE Balance

HyperEVM LogoHyperEVM LogoHyperEVM Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Put167670352025-10-17 23:52:0799 days ago1760745127IN
0x00000000...27Fd7Bbf5
0 HYPE0.000153060.5
Put167669162025-10-17 23:50:1099 days ago1760745010IN
0x00000000...27Fd7Bbf5
0 HYPE0.000207630.6563
Put117262842025-08-21 14:16:20156 days ago1755785780IN
0x00000000...27Fd7Bbf5
0 HYPE0.001107493.50080417
Put100843852025-08-02 21:35:19175 days ago1754170519IN
0x00000000...27Fd7Bbf5
0 HYPE0.000029580.1
Put100841252025-08-02 21:31:03175 days ago1754170263IN
0x00000000...27Fd7Bbf5
0 HYPE0.00003510.10638187
Put100840992025-08-02 21:30:38175 days ago1754170238IN
0x00000000...27Fd7Bbf5
0 HYPE0.000033350.1

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
1754212025-02-22 1:55:00337 days ago1740189300  Contract Creation0 HYPE
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Storage

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 20 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;

import {Net} from "../../net/Net.sol";

/// @title Storage
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice Data storage with persistent history using Net
contract Storage {
    event Stored(bytes32 indexed key, address indexed operator);

    struct BulkPutParams {
        bytes32 key;
        string text;
        bytes value;
    }

    struct BulkGetParams {
        bytes32 key;
        address operator;
    }

    struct BulkGetValueAtIndexParams {
        bytes32 key;
        address operator;
        uint256 idx;
    }

    struct BulkGetResult {
        string text;
        bytes value;
    }

    Net internal net = Net(0x00000000B24D62781dB359b07880a105cD0b64e6);

    /// @notice Store value for a given key
    /// @param key key
    /// @param text text
    /// @param value value
    function put(
        bytes32 key,
        string calldata text,
        bytes calldata value
    ) public {
        // Convert key to string
        string memory topic = string(abi.encodePacked(key));

        // Send message on Net
        net.sendMessageViaApp(msg.sender, text, topic, value);

        // Emit event
        emit Stored(key, msg.sender);
    }

    /// @notice Store values for given params
    /// @param params params
    function bulkPut(BulkPutParams[] calldata params) external {
        for (uint256 i; i < params.length; ) {
            put(params[i].key, params[i].text, params[i].value);
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Get value for a particular key and operator
    /// @param key key
    /// @param operator user that stored key
    /// @return (text, data) stored value for the particular key-operator pair
    function get(
        bytes32 key,
        address operator
    ) public view returns (string memory, bytes memory) {
        string memory topic = string(abi.encodePacked(key));
        // Get most recent message for particular key-operator pair
        Net.Message memory message = net.getMessageForAppUserTopic(
            net.getTotalMessagesForAppUserTopicCount(
                address(this),
                operator,
                topic
            ) - 1,
            address(this),
            operator,
            topic
        );
        return (message.text, message.data);
    }

    /// @notice Bulk get values for particular parameters
    /// @param params parameters
    /// @return results for stored values for the particular parameters
    function bulkGet(
        BulkGetParams[] calldata params
    ) public view returns (BulkGetResult[] memory results) {
        results = new BulkGetResult[](params.length);
        for (uint256 i; i < results.length; ) {
            (string memory text, bytes memory data) = get(
                params[i].key,
                params[i].operator
            );
            results[i] = BulkGetResult(text, data);
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Get value at index for a particular key and operator
    /// @param key key
    /// @param operator user that stored key
    /// @param idx index
    /// @return (text, data) stored value at index for the particular key-operator pair
    function getValueAtIndex(
        bytes32 key,
        address operator,
        uint256 idx
    ) public view returns (string memory, bytes memory) {
        Net.Message memory message = net.getMessageForAppUserTopic(
            idx,
            address(this),
            operator,
            string(abi.encodePacked(key))
        );
        return (message.text, message.data);
    }

    /// @notice Bulk get value at index for particular parameters
    /// @param params parameters
    /// @return results for stored values for the particular parameters
    function bulkGetValueAtIndex(
        BulkGetValueAtIndexParams[] calldata params
    ) public view returns (BulkGetResult[] memory results) {
        results = new BulkGetResult[](params.length);
        for (uint256 i; i < results.length; ) {
            (string memory text, bytes memory data) = getValueAtIndex(
                params[i].key,
                params[i].operator,
                params[i].idx
            );
            results[i] = BulkGetResult(text, data);
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Get total number of writes to a particular key for a given operator
    /// @param key key
    /// @param operator user that stored key
    /// @return total total writes count
    function getTotalWrites(
        bytes32 key,
        address operator
    ) public view returns (uint256) {
        return
            net.getTotalMessagesForAppUserTopicCount(
                address(this),
                operator,
                string(abi.encodePacked(key))
            );
    }

    /// @notice Bulk get total writes for particular parameters
    /// @param params parameters
    /// @return results for total writes for the particular parameters
    function bulkGetTotalWrites(
        BulkGetParams[] calldata params
    ) public view returns (uint256[] memory results) {
        results = new uint256[](params.length);
        for (uint256 i; i < results.length; ) {
            results[i] = getTotalWrites(params[i].key, params[i].operator);
            unchecked {
                ++i;
            }
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solmady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev We skip the first byte as it's a STOP opcode,
    /// which ensures the contract can't be called.
    uint256 internal constant DATA_OFFSET = 1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to deploy the storage contract.
    error DeploymentFailed();

    /// @dev The storage contract address is invalid.
    error InvalidPointer();

    /// @dev Attempt to read outside of the storage contract's bytecode bounds.
    error ReadOutOfBounds();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         WRITE LOGIC                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    function write(bytes memory data) internal returns (address pointer) {
        /// @solidity memory-safe-assembly
        assembly {
            let originalDataLength := mload(data)

            // Add 1 to data size since we are prefixing it with a STOP opcode.
            let dataSize := add(originalDataLength, DATA_OFFSET)

            /**
             * ------------------------------------------------------------------------------+
             * Opcode      | Mnemonic        | Stack                   | Memory              |
             * ------------------------------------------------------------------------------|
             * 61 dataSize | PUSH2 dataSize  | dataSize                |                     |
             * 80          | DUP1            | dataSize dataSize       |                     |
             * 60 0xa      | PUSH1 0xa       | 0xa dataSize dataSize   |                     |
             * 3D          | RETURNDATASIZE  | 0 0xa dataSize dataSize |                     |
             * 39          | CODECOPY        | dataSize                | [0..dataSize): code |
             * 3D          | RETURNDATASIZE  | 0 dataSize              | [0..dataSize): code |
             * F3          | RETURN          |                         | [0..dataSize): code |
             * 00          | STOP            |                         |                     |
             * ------------------------------------------------------------------------------+
             * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
             * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
             */
            mstore(
                // Do a out-of-gas revert if `dataSize` is more than 2 bytes.
                // The actual EVM limit may be smaller and may change over time.
                add(data, gt(dataSize, 0xffff)),
                // Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
                or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
            )

            // Deploy a new contract with the generated creation code.
            pointer := create(0, add(data, 0x15), add(dataSize, 0xa))

            // If `pointer` is zero, revert.
            if iszero(pointer) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore original length of the variable size `data`.
            mstore(data, originalDataLength)
        }
    }

    /// @dev Writes `data` into the bytecode of a storage contract with `salt`
    /// and returns its deterministic address.
    function writeDeterministic(bytes memory data, bytes32 salt)
        internal
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let originalDataLength := mload(data)
            let dataSize := add(originalDataLength, DATA_OFFSET)

            mstore(
                // Do a out-of-gas revert if `dataSize` is more than 2 bytes.
                // The actual EVM limit may be smaller and may change over time.
                add(data, gt(dataSize, 0xffff)),
                // Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
                or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
            )

            // Deploy a new contract with the generated creation code.
            pointer := create2(0, add(data, 0x15), add(dataSize, 0xa), salt)

            // If `pointer` is zero, revert.
            if iszero(pointer) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore original length of the variable size `data`.
            mstore(data, originalDataLength)
        }
    }

    /// @dev Returns the initialization code hash of the storage contract for `data`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let originalDataLength := mload(data)
            let dataSize := add(originalDataLength, DATA_OFFSET)

            // Do a out-of-gas revert if `dataSize` is more than 2 bytes.
            // The actual EVM limit may be smaller and may change over time.
            returndatacopy(returndatasize(), returndatasize(), shr(16, dataSize))

            mstore(data, or(0x61000080600a3d393df300, shl(0x40, dataSize)))

            hash := keccak256(add(data, 0x15), add(dataSize, 0xa))

            // Restore original length of the variable size `data`.
            mstore(data, originalDataLength)
        }
    }

    /// @dev Returns the address of the storage contract for `data`
    /// deployed with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddress(bytes memory data, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(data);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, 0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         READ LOGIC                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`.
    function read(address pointer) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Offset all indices by 1 to skip the STOP opcode.
            let size := sub(pointerCodesize, DATA_OFFSET)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), DATA_OFFSET, size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the end of the data stored.
    function read(address pointer, uint256 start) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > start)`, reverts.
            // This also handles the case where `start + DATA_OFFSET` overflows.
            if iszero(gt(pointerCodesize, start)) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(pointerCodesize, add(start, DATA_OFFSET))

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the byte at `end` (exclusive) of the data stored.
    function read(address pointer, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory data)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > end) || (start > end)`, revert.
            // This also handles the cases where
            // `end + DATA_OFFSET` or `start + DATA_OFFSET` overflows.
            if iszero(
                and(
                    gt(pointerCodesize, end), // Within bounds.
                    iszero(gt(start, end)) // Valid range.
                )
            ) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(end, start)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
        }
    }
}

File 3 of 5 : EventsAndErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;

interface EventsAndErrors {
    error MsgEmpty();
    error InvalidRange();
    error InvalidStartIndex();
    error InvalidEndIndex();

    event MessageSent(
        address indexed sender,
        string indexed topic,
        uint256 messageIndex
    );

    event MessageSentViaApp(
        address indexed app,
        address indexed sender,
        string indexed topic,
        uint256 messageIndex
    );
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;

interface INet {
    struct Message {
        address app;
        address sender;
        uint256 timestamp;
        bytes data;
        string text;
        string topic;
    }

    function sendMessageViaApp(
        address sender,
        string calldata text,
        string calldata topic,
        bytes calldata extraData
    ) external;

    function sendMessage(
        string calldata text,
        string calldata topic,
        bytes calldata extraData
    ) external;

    // **************
    // Fetch Messages
    // **************

    // Fetch message indexes

    function getMessageIdxForApp(
        uint256 idx,
        address app
    ) external view returns (uint256);

    function getMessageIdxForAppUser(
        uint256 idx,
        address app,
        address user
    ) external view returns (uint256);

    function getMessageIdxForAppTopic(
        uint256 idx,
        address app,
        string calldata topic
    ) external view returns (uint256);

    function getMessageIdxForAppUserTopic(
        uint256 idx,
        address app,
        address user,
        string calldata topic
    ) external view returns (uint256);

    // Fetch single message

    function getMessage(uint256 idx) external view returns (Message memory);

    function getMessageForApp(
        uint256 idx,
        address app
    ) external view returns (Message memory);

    function getMessageForAppUser(
        uint256 idx,
        address app,
        address user
    ) external view returns (Message memory);

    function getMessageForAppTopic(
        uint256 idx,
        address app,
        string calldata topic
    ) external view returns (Message memory);

    function getMessageForAppUserTopic(
        uint256 idx,
        address app,
        address user,
        string calldata topic
    ) external view returns (Message memory);

    // Fetch multiple messages

    function getMessagesInRange(
        uint256 startIdx,
        uint256 endIdx
    ) external view returns (Message[] memory);

    function getMessagesInRangeForApp(
        uint256 startIdx,
        uint256 endIdx,
        address app
    ) external view returns (Message[] memory);

    function getMessagesInRangeForAppUser(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        address user
    ) external view returns (Message[] memory);

    function getMessagesInRangeForAppTopic(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        string calldata topic
    ) external view returns (Message[] memory);

    function getMessagesInRangeForAppUserTopic(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        address user,
        string calldata topic
    ) external view returns (Message[] memory);

    // **************
    // Message counts
    // **************

    function getTotalMessagesCount() external view returns (uint256);

    function getTotalMessagesForAppCount(
        address app
    ) external view returns (uint256);

    function getTotalMessagesForAppUserCount(
        address app,
        address user
    ) external view returns (uint256);

    function getTotalMessagesForAppTopicCount(
        address app,
        string calldata topic
    ) external view returns (uint256);

    function getTotalMessagesForAppUserTopicCount(
        address app,
        address user,
        string calldata topic
    ) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;

import {EventsAndErrors} from "./EventsAndErrors.sol";
import {INet} from "./INet.sol";
import {SSTORE2} from "@solady/utils/SSTORE2.sol";

/// @title Net
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice Fully decentralized onchain messaging protocol
contract Net is INet, EventsAndErrors {
    // Use a single global mapping to map hashes to message indexes
    mapping(bytes32 hashVal => uint256[] messageIndexes)
        public hashToMessageIndexes;

    address[] public messagePointers;

    bytes32 constant ZERO_HASH = keccak256(abi.encodePacked(address(0)));

    // Empty topic "" will not impact a hash, which could result in collisions
    // between hash values that use topic and don't use topic. For that reason,
    // we prefix the relevant hash topic keys with these values to ensure collisions don't occur
    // Example if this prefix didn't exist:
    // keccak256(abi.encodePacked(address(0))) == keccak256(abi.encodePacked(address(0), "" /* where "" represents topic */)) evaluates to true
    uint256 constant APP_TOPIC_HASH_PREFIX = 1;
    uint256 constant APP_USER_TOPIC_HASH_PREFIX = 2;

    // ************
    // Send message
    // ************

    /// @notice Send message via app
    /// @param sender message sender
    /// @param text message text
    /// @param topic message topic
    /// @param data message data
    function sendMessageViaApp(
        address sender,
        string calldata text,
        string calldata topic,
        bytes calldata data
    ) external {
        // Revert if message length is none to prevent empty messages
        if (bytes(text).length == 0 && bytes(data).length == 0) {
            revert MsgEmpty();
        }

        // Track message index in topic and user mappings
        uint256 messagesLength = messagePointers.length;

        // App messages
        hashToMessageIndexes[keccak256(abi.encodePacked(msg.sender))].push(
            messagesLength
        );

        // App-user messages
        hashToMessageIndexes[keccak256(abi.encodePacked(msg.sender, sender))]
            .push(messagesLength);

        // App-topic messages
        hashToMessageIndexes[
            // msg.sender is the app id
            keccak256(
                abi.encodePacked(APP_TOPIC_HASH_PREFIX, msg.sender, topic)
            )
        ].push(messagesLength);

        // App-user-topic messages
        hashToMessageIndexes[
            keccak256(
                abi.encodePacked(
                    APP_USER_TOPIC_HASH_PREFIX,
                    msg.sender,
                    sender,
                    topic
                )
            )
        ].push(messagesLength);

        // Emit message sent using current messages length as the index
        emit MessageSentViaApp(msg.sender, sender, topic, messagesLength);

        // Store message
        messagePointers.push(
            SSTORE2.write(
                abi.encode(
                    // App
                    msg.sender,
                    // Sender
                    sender,
                    // Timestamp
                    block.timestamp,
                    // Data
                    data,
                    // Text
                    text,
                    // Topic
                    topic
                )
            )
        );
    }

    /// @notice Send message
    /// @param text message text
    /// @param topic message topic
    /// @param data message data
    function sendMessage(
        string calldata text,
        string calldata topic,
        bytes calldata data
    ) external {
        // Revert if message length is none to prevent empty messages
        if (bytes(text).length == 0 && bytes(data).length == 0) {
            revert MsgEmpty();
        }

        // Track message index in topic and user mappings
        uint256 messagesLength = messagePointers.length;

        // address(0) is used to represent messages sent from "no app"
        hashToMessageIndexes[ZERO_HASH].push(messagesLength);
        hashToMessageIndexes[
            keccak256(
                abi.encodePacked(APP_TOPIC_HASH_PREFIX, address(0), topic)
            )
        ].push(messagesLength);
        hashToMessageIndexes[
            keccak256(abi.encodePacked(address(0), msg.sender))
        ].push(messagesLength);
        hashToMessageIndexes[
            keccak256(
                abi.encodePacked(
                    APP_USER_TOPIC_HASH_PREFIX,
                    address(0),
                    msg.sender,
                    topic
                )
            )
        ].push(messagesLength);

        // Emit message sent using current messages length as the index
        emit MessageSent(msg.sender, topic, messagesLength);

        // Store message
        messagePointers.push(
            SSTORE2.write(
                abi.encode(
                    // App
                    address(0),
                    // Sender
                    msg.sender,
                    // Timestamp
                    block.timestamp,
                    // Data
                    data,
                    // Text
                    text,
                    // Topic
                    topic
                )
            )
        );
    }

    // **************
    // Fetch Messages
    // **************

    // Fetch message indexes

    /// @notice Get message pointer index for app
    /// @param idx message index
    /// @param app app
    /// @return index index
    function getMessageIdxForApp(
        uint256 idx,
        address app
    ) external view returns (uint256) {
        return hashToMessageIndexes[keccak256(abi.encodePacked(app))][idx];
    }

    /// @notice Get message pointer index for app user
    /// @param idx message index
    /// @param app app
    /// @param user user
    /// @return index index
    function getMessageIdxForAppUser(
        uint256 idx,
        address app,
        address user
    ) external view returns (uint256) {
        return
            hashToMessageIndexes[keccak256(abi.encodePacked(app, user))][idx];
    }

    /// @notice Get message pointer index for app topic
    /// @param idx message index
    /// @param app app
    /// @param topic topic
    /// @return index index
    function getMessageIdxForAppTopic(
        uint256 idx,
        address app,
        string calldata topic
    ) external view returns (uint256) {
        return
            hashToMessageIndexes[
                keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic))
            ][idx];
    }

    /// @notice Get message pointer index for app user topic
    /// @param idx message index
    /// @param app app
    /// @param user user
    /// @param topic topic
    /// @return index index
    function getMessageIdxForAppUserTopic(
        uint256 idx,
        address app,
        address user,
        string calldata topic
    ) external view returns (uint256) {
        return
            hashToMessageIndexes[
                keccak256(
                    abi.encodePacked(
                        APP_USER_TOPIC_HASH_PREFIX,
                        app,
                        user,
                        topic
                    )
                )
            ][idx];
    }

    // Fetch single message

    /// @notice Decode encoded message
    /// @param encodedMessage encoded message
    /// @return decodedMessage decoded message
    function decodeMessage(
        bytes memory encodedMessage
    ) public pure returns (Message memory) {
        Message memory message;
        (
            message.app,
            message.sender,
            message.timestamp,
            message.data,
            message.text,
            message.topic
        ) = abi.decode(
            encodedMessage,
            (
                // App
                address,
                // Sender
                address,
                // Timestamp
                uint256,
                // Data
                bytes,
                // Text
                string,
                // Topic
                string
            )
        );
        return message;
    }

    /// @notice Decode message at index in message pointers
    /// @param idx index
    /// @return decodedMessage decoded message
    function decodeMessageAtIndex(
        uint256 idx
    ) public view returns (Message memory) {
        return decodeMessage(SSTORE2.read(messagePointers[idx]));
    }

    /// @notice Get message
    /// @param idx index
    /// @return message message
    function getMessage(uint256 idx) external view returns (Message memory) {
        return decodeMessageAtIndex(idx);
    }

    /// @notice Get message for app
    /// @param idx index
    /// @param app app
    /// @return message message
    function getMessageForApp(
        uint256 idx,
        address app
    ) external view returns (Message memory) {
        return
            decodeMessageAtIndex(
                hashToMessageIndexes[keccak256(abi.encodePacked(app))][idx]
            );
    }

    /// @notice Get message for app user
    /// @param idx index
    /// @param app app
    /// @param user user
    /// @return message message
    function getMessageForAppUser(
        uint256 idx,
        address app,
        address user
    ) external view returns (Message memory) {
        return
            decodeMessageAtIndex(
                hashToMessageIndexes[keccak256(abi.encodePacked(app, user))][
                    idx
                ]
            );
    }

    /// @notice Get message for app topic
    /// @param idx index
    /// @param app app
    /// @param topic topic
    /// @return message message
    function getMessageForAppTopic(
        uint256 idx,
        address app,
        string calldata topic
    ) external view returns (Message memory) {
        return
            decodeMessageAtIndex(
                hashToMessageIndexes[
                    keccak256(
                        abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic)
                    )
                ][idx]
            );
    }

    /// @notice Get message for app user topic
    /// @param idx index
    /// @param app app
    /// @param user user
    /// @param topic topic
    /// @return message message
    function getMessageForAppUserTopic(
        uint256 idx,
        address app,
        address user,
        string calldata topic
    ) external view returns (Message memory) {
        return
            decodeMessageAtIndex(
                hashToMessageIndexes[
                    keccak256(
                        abi.encodePacked(
                            APP_USER_TOPIC_HASH_PREFIX,
                            app,
                            user,
                            topic
                        )
                    )
                ][idx]
            );
    }

    // Fetch multiple messages

    /// @notice Get messages in range
    /// @param startIdx start index
    /// @param endIdx end index
    /// @return messages list of messages
    function getMessagesInRange(
        uint256 startIdx,
        uint256 endIdx
    ) external view returns (Message[] memory) {
        if (startIdx >= endIdx) {
            revert InvalidRange();
        }
        uint256 querySetLength = messagePointers.length;
        if (startIdx + 1 > querySetLength) {
            revert InvalidStartIndex();
        }
        if (endIdx > querySetLength) {
            revert InvalidEndIndex();
        }

        Message[] memory messagesSlice = new Message[](endIdx - startIdx);
        uint256 idxInMessages = startIdx;
        unchecked {
            for (; idxInMessages < endIdx; ) {
                messagesSlice[idxInMessages - startIdx] = decodeMessageAtIndex(
                    idxInMessages
                );
                ++idxInMessages;
            }
        }

        return messagesSlice;
    }

    /// @notice Get messages in range for hash
    /// @param startIdx start index
    /// @param endIdx end index
    /// @param hashVal hash
    /// @return messages list of messages
    function getMessagesInRangeForHash(
        uint256 startIdx,
        uint256 endIdx,
        bytes32 hashVal
    ) public view returns (Message[] memory) {
        if (startIdx >= endIdx) {
            revert InvalidRange();
        }
        uint256 querySetLength = hashToMessageIndexes[hashVal].length;
        if (startIdx + 1 > querySetLength) {
            revert InvalidStartIndex();
        }
        if (endIdx > querySetLength) {
            revert InvalidEndIndex();
        }

        Message[] memory messagesSlice = new Message[](endIdx - startIdx);
        uint256 idxInMessages = startIdx;
        unchecked {
            for (; idxInMessages < endIdx; ) {
                messagesSlice[idxInMessages - startIdx] = decodeMessageAtIndex(
                    hashToMessageIndexes[hashVal][idxInMessages]
                );
                ++idxInMessages;
            }
        }

        return messagesSlice;
    }

    /// @notice Get messages in range for app
    /// @param startIdx start index
    /// @param endIdx end index
    /// @param app app
    /// @return messages list of messages
    function getMessagesInRangeForApp(
        uint256 startIdx,
        uint256 endIdx,
        address app
    ) external view returns (Message[] memory) {
        return
            getMessagesInRangeForHash(
                startIdx,
                endIdx,
                keccak256(abi.encodePacked(app))
            );
    }

    /// @notice Get messages in range for app user
    /// @param startIdx start index
    /// @param endIdx end index
    /// @param app app
    /// @param user user
    /// @return messages list of messages
    function getMessagesInRangeForAppUser(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        address user
    ) external view returns (Message[] memory) {
        return
            getMessagesInRangeForHash(
                startIdx,
                endIdx,
                keccak256(abi.encodePacked(app, user))
            );
    }

    /// @notice Get messages in range for app topic
    /// @param startIdx start index
    /// @param endIdx end index
    /// @param app app
    /// @param topic topic
    /// @return messages list of messages
    function getMessagesInRangeForAppTopic(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        string calldata topic
    ) external view returns (Message[] memory) {
        return
            getMessagesInRangeForHash(
                startIdx,
                endIdx,
                keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic))
            );
    }

    /// @notice Get messages in range for app user topic
    /// @param startIdx start index
    /// @param endIdx end index
    /// @param app app
    /// @param user user
    /// @param topic topic
    /// @return messages list of messages
    function getMessagesInRangeForAppUserTopic(
        uint256 startIdx,
        uint256 endIdx,
        address app,
        address user,
        string calldata topic
    ) external view returns (Message[] memory) {
        return
            getMessagesInRangeForHash(
                startIdx,
                endIdx,
                keccak256(
                    abi.encodePacked(
                        APP_USER_TOPIC_HASH_PREFIX,
                        app,
                        user,
                        topic
                    )
                )
            );
    }

    // **************
    // Message counts
    // **************

    /// @notice Get total messages count
    /// @return count count
    function getTotalMessagesCount() external view returns (uint256) {
        return messagePointers.length;
    }

    /// @notice Get total messages for hash count
    /// @param hashVal hash
    /// @return count count
    function getTotalMessagesForHashCount(
        bytes32 hashVal
    ) public view returns (uint256) {
        return hashToMessageIndexes[hashVal].length;
    }

    /// @notice Get total messages for app count
    /// @param app app
    /// @return count count
    function getTotalMessagesForAppCount(
        address app
    ) external view returns (uint256) {
        return getTotalMessagesForHashCount(keccak256(abi.encodePacked(app)));
    }

    /// @notice Get total messages for app user count
    /// @param app app
    /// @param user user
    /// @return count count
    function getTotalMessagesForAppUserCount(
        address app,
        address user
    ) external view returns (uint256) {
        return
            getTotalMessagesForHashCount(
                keccak256(abi.encodePacked(app, user))
            );
    }

    /// @notice Get total messages for app topic count
    /// @param app app
    /// @param topic topic
    /// @return count count
    function getTotalMessagesForAppTopicCount(
        address app,
        string calldata topic
    ) external view returns (uint256) {
        return
            getTotalMessagesForHashCount(
                keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic))
            );
    }

    /// @notice Get total messages for app user topic count
    /// @param app app
    /// @param user user
    /// @param topic topic
    /// @return count count
    function getTotalMessagesForAppUserTopicCount(
        address app,
        address user,
        string calldata topic
    ) external view returns (uint256) {
        return
            getTotalMessagesForHashCount(
                keccak256(
                    abi.encodePacked(
                        APP_USER_TOPIC_HASH_PREFIX,
                        app,
                        user,
                        topic
                    )
                )
            );
    }
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "appendCBOR": false,
    "bytecodeHash": "none",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 20
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "@prb/test/=lib/prb-test/src/",
    "forge-std/=lib/forge-std/src/",
    "src/=src/",
    "@erc721a/=lib/ERC721A/contracts/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "@solady/=lib/solady/src/",
    "solmate/=lib/solady/lib/solmate/src/",
    "utility-contracts/=lib/utility-contracts/src/",
    "@seaport-types/=lib/seaport-types/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ERC721A/=lib/ERC721A/contracts/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "prb-math/=lib/prb-math/src/",
    "prb-test/=lib/prb-test/src/",
    "seaport-types/=lib/seaport-types/src/",
    "solady/=lib/solady/src/"
  ],
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"Stored","type":"event"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"}],"internalType":"struct Storage.BulkGetParams[]","name":"params","type":"tuple[]"}],"name":"bulkGet","outputs":[{"components":[{"internalType":"string","name":"text","type":"string"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct Storage.BulkGetResult[]","name":"results","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"}],"internalType":"struct Storage.BulkGetParams[]","name":"params","type":"tuple[]"}],"name":"bulkGetTotalWrites","outputs":[{"internalType":"uint256[]","name":"results","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"idx","type":"uint256"}],"internalType":"struct Storage.BulkGetValueAtIndexParams[]","name":"params","type":"tuple[]"}],"name":"bulkGetValueAtIndex","outputs":[{"components":[{"internalType":"string","name":"text","type":"string"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct Storage.BulkGetResult[]","name":"results","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"string","name":"text","type":"string"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct Storage.BulkPutParams[]","name":"params","type":"tuple[]"}],"name":"bulkPut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"}],"name":"get","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"}],"name":"getTotalWrites","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"getValueAtIndex","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"string","name":"text","type":"string"},{"internalType":"bytes","name":"value","type":"bytes"}],"name":"put","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600080546001600160a01b0319166fb24d62781db359b07880a105cd0b64e617905534801561003257600080fd5b50610f5c806100426000396000f3fe608060405234801561001057600080fd5b50600436106100785760003560e01c80630b768bbf1461007d57806320c027b8146100a657806347a21327146100c75780639456185a146100e8578063a71d51c814610108578063b13dcd481461011b578063f372437714610130578063f9ed11d914610143575b600080fd5b61009061008b366004610834565b610156565b60405161009d91906108f8565b60405180910390f35b6100b96100b4366004610995565b61024b565b60405161009d9291906109c5565b6100da6100d5366004610995565b610381565b60405190815260200161009d565b6100fb6100f6366004610834565b610419565b60405161009d91906109f3565b610090610116366004610a37565b6104d9565b61012e610129366004610a99565b6105e8565b005b6100b961013e366004610afb565b61068c565b61012e610151366004610b74565b610755565b6060816001600160401b0381111561017057610170610bed565b6040519080825280602002602001820160405280156101a957816020015b61019661081a565b81526020019060019003908161018e5790505b50905060005b8151811015610244576000806102048686858181106101d0576101d0610c03565b905060400201600001358787868181106101ec576101ec610c03565b90506040020160200160208101906100b49190610c19565b9150915060405180604001604052808381526020018281525084848151811061022f5761022f610c03565b602090810291909101015250506001016101af565b5092915050565b60608060008460405160200161026391815260200190565b60408051601f19818403018152908290526000805463e976718d60e01b8452919350916001600160a01b039091169063176b710c90600190839063e976718d906102b59030908c908a90600401610c3d565b602060405180830381865afa1580156102d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f69190610c69565b6103009190610c82565b3088866040518563ffffffff1660e01b81526004016103229493929190610ca3565b600060405180830381865afa15801561033f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103679190810190610d94565b9050806080015181606001519350935050505b9250929050565b60008054604080516020808201879052825180830390910181528183019283905263e976718d60e01b9092526001600160a01b039092169163e976718d916103cf9130918791604401610c3d565b602060405180830381865afa1580156103ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104109190610c69565b90505b92915050565b6060816001600160401b0381111561043357610433610bed565b60405190808252806020026020018201604052801561045c578160200160208202803683370190505b50905060005b8151811015610244576104b484848381811061048057610480610c03565b9050604002016000013585858481811061049c5761049c610c03565b90506040020160200160208101906100d59190610c19565b8282815181106104c6576104c6610c03565b6020908102919091010152600101610462565b6060816001600160401b038111156104f3576104f3610bed565b60405190808252806020026020018201604052801561052c57816020015b61051961081a565b8152602001906001900390816105115790505b50905060005b8151811015610244576000806105a886868581811061055357610553610c03565b9050606002016000013587878681811061056f5761056f610c03565b90506060020160200160208101906105879190610c19565b88888781811061059957610599610c03565b9050606002016040013561068c565b915091506040518060400160405280838152602001828152508484815181106105d3576105d3610c03565b60209081029190910101525050600101610532565b60005b818110156106875761067f83838381811061060857610608610c03565b905060200281019061061a9190610e74565b3584848481811061062d5761062d610c03565b905060200281019061063f9190610e74565b61064d906020810190610e94565b86868681811061065f5761065f610c03565b90506020028101906106719190610e74565b610151906040810190610e94565b6001016105eb565b505050565b60608060008060009054906101000a90046001600160a01b03166001600160a01b031663176b710c8530888a6040516020016106ca91815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b81526004016106f89493929190610ca3565b600060405180830381865afa158015610715573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261073d9190810190610d94565b60808101516060909101519097909650945050505050565b60008560405160200161076a91815260200190565b60408051601f19818403018152908290526000546308521f2760e21b83529092506001600160a01b0316906321487c9c906107b39033908990899087908a908a90600401610f03565b600060405180830381600087803b1580156107cd57600080fd5b505af11580156107e1573d6000803e3d6000fd5b50506040513392508891507f5c07bbc009a8b5cd591fb836e410b19010c5600d44b836b4d44ab5be178bba3d90600090a3505050505050565b604051806040016040528060608152602001606081525090565b6000806020838503121561084757600080fd5b82356001600160401b038082111561085e57600080fd5b818501915085601f83011261087257600080fd5b81358181111561088157600080fd5b8660208260061b850101111561089657600080fd5b60209290920196919550909350505050565b60005b838110156108c35781810151838201526020016108ab565b50506000910152565b600081518084526108e48160208601602086016108a8565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561096f57888303603f1901855281518051878552610943888601826108cc565b91890151858303868b015291905061095b81836108cc565b96890196945050509086019060010161091f565b509098975050505050505050565b6001600160a01b038116811461099257600080fd5b50565b600080604083850312156109a857600080fd5b8235915060208301356109ba8161097d565b809150509250929050565b6040815260006109d860408301856108cc565b82810360208401526109ea81856108cc565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015610a2b57835183529284019291840191600101610a0f565b50909695505050505050565b60008060208385031215610a4a57600080fd5b82356001600160401b0380821115610a6157600080fd5b818501915085601f830112610a7557600080fd5b813581811115610a8457600080fd5b86602060608302850101111561089657600080fd5b60008060208385031215610aac57600080fd5b82356001600160401b0380821115610ac357600080fd5b818501915085601f830112610ad757600080fd5b813581811115610ae657600080fd5b8660208260051b850101111561089657600080fd5b600080600060608486031215610b1057600080fd5b833592506020840135610b228161097d565b929592945050506040919091013590565b60008083601f840112610b4557600080fd5b5081356001600160401b03811115610b5c57600080fd5b60208301915083602082850101111561037a57600080fd5b600080600080600060608688031215610b8c57600080fd5b8535945060208601356001600160401b0380821115610baa57600080fd5b610bb689838a01610b33565b90965094506040880135915080821115610bcf57600080fd5b50610bdc88828901610b33565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215610c2b57600080fd5b8135610c368161097d565b9392505050565b6001600160a01b038481168252831660208201526060604082018190526000906109ea908301846108cc565b600060208284031215610c7b57600080fd5b5051919050565b8181038181111561041357634e487b7160e01b600052601160045260246000fd5b8481526001600160a01b03848116602083015283166040820152608060608201819052600090610cd5908301846108cc565b9695505050505050565b60405160c081016001600160401b0381118282101715610d0157610d01610bed565b60405290565b8051610d128161097d565b919050565b600082601f830112610d2857600080fd5b81516001600160401b0380821115610d4257610d42610bed565b604051601f8301601f19908116603f01168101908282118183101715610d6a57610d6a610bed565b81604052838152866020858801011115610d8357600080fd5b610cd58460208301602089016108a8565b600060208284031215610da657600080fd5b81516001600160401b0380821115610dbd57600080fd5b9083019060c08286031215610dd157600080fd5b610dd9610cdf565b610de283610d07565b8152610df060208401610d07565b602082015260408301516040820152606083015182811115610e1157600080fd5b610e1d87828601610d17565b606083015250608083015182811115610e3557600080fd5b610e4187828601610d17565b60808301525060a083015182811115610e5957600080fd5b610e6587828601610d17565b60a08301525095945050505050565b60008235605e19833603018112610e8a57600080fd5b9190910192915050565b6000808335601e19843603018112610eab57600080fd5b8301803591506001600160401b03821115610ec557600080fd5b60200191503681900382131561037a57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0387168152608060208201819052600090610f289083018789610eda565b8281036040840152610f3a81876108cc565b90508281036060840152610f4f818587610eda565b999850505050505050505056

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100785760003560e01c80630b768bbf1461007d57806320c027b8146100a657806347a21327146100c75780639456185a146100e8578063a71d51c814610108578063b13dcd481461011b578063f372437714610130578063f9ed11d914610143575b600080fd5b61009061008b366004610834565b610156565b60405161009d91906108f8565b60405180910390f35b6100b96100b4366004610995565b61024b565b60405161009d9291906109c5565b6100da6100d5366004610995565b610381565b60405190815260200161009d565b6100fb6100f6366004610834565b610419565b60405161009d91906109f3565b610090610116366004610a37565b6104d9565b61012e610129366004610a99565b6105e8565b005b6100b961013e366004610afb565b61068c565b61012e610151366004610b74565b610755565b6060816001600160401b0381111561017057610170610bed565b6040519080825280602002602001820160405280156101a957816020015b61019661081a565b81526020019060019003908161018e5790505b50905060005b8151811015610244576000806102048686858181106101d0576101d0610c03565b905060400201600001358787868181106101ec576101ec610c03565b90506040020160200160208101906100b49190610c19565b9150915060405180604001604052808381526020018281525084848151811061022f5761022f610c03565b602090810291909101015250506001016101af565b5092915050565b60608060008460405160200161026391815260200190565b60408051601f19818403018152908290526000805463e976718d60e01b8452919350916001600160a01b039091169063176b710c90600190839063e976718d906102b59030908c908a90600401610c3d565b602060405180830381865afa1580156102d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f69190610c69565b6103009190610c82565b3088866040518563ffffffff1660e01b81526004016103229493929190610ca3565b600060405180830381865afa15801561033f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103679190810190610d94565b9050806080015181606001519350935050505b9250929050565b60008054604080516020808201879052825180830390910181528183019283905263e976718d60e01b9092526001600160a01b039092169163e976718d916103cf9130918791604401610c3d565b602060405180830381865afa1580156103ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104109190610c69565b90505b92915050565b6060816001600160401b0381111561043357610433610bed565b60405190808252806020026020018201604052801561045c578160200160208202803683370190505b50905060005b8151811015610244576104b484848381811061048057610480610c03565b9050604002016000013585858481811061049c5761049c610c03565b90506040020160200160208101906100d59190610c19565b8282815181106104c6576104c6610c03565b6020908102919091010152600101610462565b6060816001600160401b038111156104f3576104f3610bed565b60405190808252806020026020018201604052801561052c57816020015b61051961081a565b8152602001906001900390816105115790505b50905060005b8151811015610244576000806105a886868581811061055357610553610c03565b9050606002016000013587878681811061056f5761056f610c03565b90506060020160200160208101906105879190610c19565b88888781811061059957610599610c03565b9050606002016040013561068c565b915091506040518060400160405280838152602001828152508484815181106105d3576105d3610c03565b60209081029190910101525050600101610532565b60005b818110156106875761067f83838381811061060857610608610c03565b905060200281019061061a9190610e74565b3584848481811061062d5761062d610c03565b905060200281019061063f9190610e74565b61064d906020810190610e94565b86868681811061065f5761065f610c03565b90506020028101906106719190610e74565b610151906040810190610e94565b6001016105eb565b505050565b60608060008060009054906101000a90046001600160a01b03166001600160a01b031663176b710c8530888a6040516020016106ca91815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b81526004016106f89493929190610ca3565b600060405180830381865afa158015610715573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261073d9190810190610d94565b60808101516060909101519097909650945050505050565b60008560405160200161076a91815260200190565b60408051601f19818403018152908290526000546308521f2760e21b83529092506001600160a01b0316906321487c9c906107b39033908990899087908a908a90600401610f03565b600060405180830381600087803b1580156107cd57600080fd5b505af11580156107e1573d6000803e3d6000fd5b50506040513392508891507f5c07bbc009a8b5cd591fb836e410b19010c5600d44b836b4d44ab5be178bba3d90600090a3505050505050565b604051806040016040528060608152602001606081525090565b6000806020838503121561084757600080fd5b82356001600160401b038082111561085e57600080fd5b818501915085601f83011261087257600080fd5b81358181111561088157600080fd5b8660208260061b850101111561089657600080fd5b60209290920196919550909350505050565b60005b838110156108c35781810151838201526020016108ab565b50506000910152565b600081518084526108e48160208601602086016108a8565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561096f57888303603f1901855281518051878552610943888601826108cc565b91890151858303868b015291905061095b81836108cc565b96890196945050509086019060010161091f565b509098975050505050505050565b6001600160a01b038116811461099257600080fd5b50565b600080604083850312156109a857600080fd5b8235915060208301356109ba8161097d565b809150509250929050565b6040815260006109d860408301856108cc565b82810360208401526109ea81856108cc565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015610a2b57835183529284019291840191600101610a0f565b50909695505050505050565b60008060208385031215610a4a57600080fd5b82356001600160401b0380821115610a6157600080fd5b818501915085601f830112610a7557600080fd5b813581811115610a8457600080fd5b86602060608302850101111561089657600080fd5b60008060208385031215610aac57600080fd5b82356001600160401b0380821115610ac357600080fd5b818501915085601f830112610ad757600080fd5b813581811115610ae657600080fd5b8660208260051b850101111561089657600080fd5b600080600060608486031215610b1057600080fd5b833592506020840135610b228161097d565b929592945050506040919091013590565b60008083601f840112610b4557600080fd5b5081356001600160401b03811115610b5c57600080fd5b60208301915083602082850101111561037a57600080fd5b600080600080600060608688031215610b8c57600080fd5b8535945060208601356001600160401b0380821115610baa57600080fd5b610bb689838a01610b33565b90965094506040880135915080821115610bcf57600080fd5b50610bdc88828901610b33565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215610c2b57600080fd5b8135610c368161097d565b9392505050565b6001600160a01b038481168252831660208201526060604082018190526000906109ea908301846108cc565b600060208284031215610c7b57600080fd5b5051919050565b8181038181111561041357634e487b7160e01b600052601160045260246000fd5b8481526001600160a01b03848116602083015283166040820152608060608201819052600090610cd5908301846108cc565b9695505050505050565b60405160c081016001600160401b0381118282101715610d0157610d01610bed565b60405290565b8051610d128161097d565b919050565b600082601f830112610d2857600080fd5b81516001600160401b0380821115610d4257610d42610bed565b604051601f8301601f19908116603f01168101908282118183101715610d6a57610d6a610bed565b81604052838152866020858801011115610d8357600080fd5b610cd58460208301602089016108a8565b600060208284031215610da657600080fd5b81516001600160401b0380821115610dbd57600080fd5b9083019060c08286031215610dd157600080fd5b610dd9610cdf565b610de283610d07565b8152610df060208401610d07565b602082015260408301516040820152606083015182811115610e1157600080fd5b610e1d87828601610d17565b606083015250608083015182811115610e3557600080fd5b610e4187828601610d17565b60808301525060a083015182811115610e5957600080fd5b610e6587828601610d17565b60a08301525095945050505050565b60008235605e19833603018112610e8a57600080fd5b9190910192915050565b6000808335601e19843603018112610eab57600080fd5b8301803591506001600160401b03821115610ec557600080fd5b60200191503681900382131561037a57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0387168152608060208201819052600090610f289083018789610eda565b8281036040840152610f3a81876108cc565b90508281036060840152610f4f818587610eda565b999850505050505050505056

Block Transaction Gas Used Reward
view all blocks ##produced##

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