ETH Price: $2,941.63 (-0.55%)

Contract

0x1871c138cEaB2bB36c5dBcAED0AB4BC88271feE7

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
205557672025-10-14 13:06:13102 days ago1760447173
0x1871c138...88271feE7
0.00005249 ETH
205557672025-10-14 13:06:13102 days ago1760447173
0x1871c138...88271feE7
0.00005249 ETH
203989652025-10-10 21:59:29106 days ago1760133569
0x1871c138...88271feE7
0.00004299 ETH
203989652025-10-10 21:59:29106 days ago1760133569
0x1871c138...88271feE7
0.00004299 ETH
203988672025-10-10 21:56:13106 days ago1760133373
0x1871c138...88271feE7
0.00004299 ETH
203988672025-10-10 21:56:13106 days ago1760133373
0x1871c138...88271feE7
0.00004299 ETH
203880512025-10-10 15:55:41106 days ago1760111741
0x1871c138...88271feE7
0.00004299 ETH
203880512025-10-10 15:55:41106 days ago1760111741
0x1871c138...88271feE7
0.00004299 ETH
203331212025-10-09 9:24:41108 days ago1760001881
0x1871c138...88271feE7
0.00004299 ETH
203331212025-10-09 9:24:41108 days ago1760001881
0x1871c138...88271feE7
0.00004299 ETH
197943122025-09-26 22:04:23120 days ago1758924263
0x1871c138...88271feE7
0.00004977 ETH
197943122025-09-26 22:04:23120 days ago1758924263
0x1871c138...88271feE7
0.00004977 ETH
197549042025-09-26 0:10:47121 days ago1758845447
0x1871c138...88271feE7
0.00004977 ETH
197549042025-09-26 0:10:47121 days ago1758845447
0x1871c138...88271feE7
0.00004977 ETH
196173392025-09-22 19:45:17124 days ago1758570317
0x1871c138...88271feE7
0.00004513 ETH
196173392025-09-22 19:45:17124 days ago1758570317
0x1871c138...88271feE7
0.00004513 ETH
195932772025-09-22 6:23:13125 days ago1758522193
0x1871c138...88271feE7
0.00004513 ETH
195932772025-09-22 6:23:13125 days ago1758522193
0x1871c138...88271feE7
0.00004513 ETH
195220832025-09-20 14:50:05126 days ago1758379805
0x1871c138...88271feE7
0.00004513 ETH
195220832025-09-20 14:50:05126 days ago1758379805
0x1871c138...88271feE7
0.00004513 ETH
194983412025-09-20 1:38:41127 days ago1758332321
0x1871c138...88271feE7
0.00004513 ETH
194983412025-09-20 1:38:41127 days ago1758332321
0x1871c138...88271feE7
0.00004513 ETH
194658712025-09-19 7:36:21128 days ago1758267381
0x1871c138...88271feE7
0.00004513 ETH
194658712025-09-19 7:36:21128 days ago1758267381
0x1871c138...88271feE7
0.00004513 ETH
193757592025-09-17 5:32:37130 days ago1758087157
0x1871c138...88271feE7
0.00004513 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

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

Contract Name:
HyperProver

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import {IMessageRecipient} from "@hyperlane-xyz/core/contracts/interfaces/IMessageRecipient.sol";
import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol";
import {MessageBridgeProver} from "./MessageBridgeProver.sol";
import {Semver} from "../libs/Semver.sol";
import {IMailbox, IPostDispatchHook} from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

/**
 * @title HyperProver
 * @notice Prover implementation using Hyperlane's cross-chain messaging system
 * @notice the terms "source" and "destination" are used in reference to a given intent: created on source chain, fulfilled on destination chain
 * @dev Processes proof messages from Hyperlane mailbox and records proven intents
 */
contract HyperProver is IMessageRecipient, MessageBridgeProver, Semver {
    using TypeCasts for bytes32;
    using SafeCast for uint256;

    /**
     * @notice Struct for unpacked data from _data parameter
     * @dev Only contains fields decoded from the _data parameter
     */
    struct UnpackedData {
        bytes32 sourceChainProver; // Address of prover on source chain
        bytes metadata; // Metadata for Hyperlane message
        address hookAddr; // Address of post-dispatch hook
    }

    // Rarichain uses a different domain ID than its chain ID, representing an edge case
    uint32 public constant RARICHAIN_CHAIN_ID = 1380012617;
    uint32 public constant RARICHAIN_DOMAIN_ID = 1000012617;

    /**
     * @notice Constant indicating this contract uses Hyperlane for proving
     */
    string public constant PROOF_TYPE = "Hyperlane";

    /**
     * @notice Address of local Hyperlane mailbox
     */
    address public immutable MAILBOX;

    /**
     * @param _mailbox Address of local Hyperlane mailbox
     * @param _inbox Address of Inbox contract
     * @param _provers Array of trusted prover addresses
     */
    constructor(
        address _mailbox,
        address _inbox,
        address[] memory _provers
    ) MessageBridgeProver(_inbox, _provers, 0) {
        if (_mailbox == address(0)) revert MailboxCannotBeZeroAddress();
        MAILBOX = _mailbox;
    }

    /**
     * @notice Handles incoming Hyperlane messages containing proof data
     * @dev called by the Hyperlane mailbox on the source chain
     * @dev Processes batch updates to proven intents from valid sources
     * @param _origin DomainID of the destination chain
     * @param _sender Address that dispatched the message on destination chain
     * @param _messageBody Encoded array of intent hashes and claimants
     */
    function handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _messageBody
    ) public payable {
        // Verify message is from authorized mailbox
        _validateMessageSender(msg.sender, MAILBOX);

        // Verify _origin and _sender are valid
        if (_origin == 0) revert InvalidOriginChainId();

        // Convert bytes32 sender to address and delegate to shared handler
        address sender = _sender.bytes32ToAddress();
        if (sender == address(0)) revert SenderCannotBeZeroAddress();

        if (_origin == RARICHAIN_DOMAIN_ID) {
            _handleCrossChainMessage(RARICHAIN_CHAIN_ID, sender, _messageBody);
        } else {
            _handleCrossChainMessage(_origin, sender, _messageBody);
        }
    }

    /**
     * @notice Initiates proving of intents via Hyperlane
     * @dev Sends message to source chain prover with intent data
     * @dev called by the Inbox contract on the destination chain
     * @param _sender Address that initiated the proving request
     * @param _sourceChainId Chain ID of the source chain
     * @param _intentHashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param _data Additional data for message formatting
     */
    function prove(
        address _sender,
        uint256 _sourceChainId,
        bytes32[] calldata _intentHashes,
        address[] calldata _claimants,
        bytes calldata _data
    ) external payable override {
        // Validate the request is from Inbox
        _validateProvingRequest(msg.sender);

        // Parse incoming data into a structured format for processing
        UnpackedData memory unpacked = _unpackData(_data);

        // Calculate fee
        uint256 fee = _fetchFee(
            _sourceChainId,
            _intentHashes,
            _claimants,
            unpacked
        );

        // Check if enough fee was provided
        if (msg.value < fee) {
            revert InsufficientFee(fee);
        }

        // Calculate refund amount if overpaid
        uint256 _refundAmount = 0;
        if (msg.value > fee) {
            _refundAmount = msg.value - fee;
        }

        emit BatchSent(_intentHashes, _sourceChainId);

        // Declare dispatch parameters for cross-chain message delivery
        uint32 sourceChainDomain;
        bytes32 recipientAddress;
        bytes memory messageBody;
        bytes memory metadata;
        IPostDispatchHook hook;

        // Prepare parameters for cross-chain message dispatch
        (
            sourceChainDomain,
            recipientAddress,
            messageBody,
            metadata,
            hook
        ) = _formatHyperlaneMessage(
            _sourceChainId,
            _intentHashes,
            _claimants,
            unpacked
        );

        // Send the message through Hyperlane mailbox using local variables
        // Note: Some Hyperlane versions have different dispatch signatures.
        // This matches the expected signature for testing.
        IMailbox(MAILBOX).dispatch{value: fee}(
            sourceChainDomain,
            recipientAddress,
            messageBody,
            metadata,
            hook
        );

        // Send refund if needed
        _sendRefund(_sender, _refundAmount);
    }

    /**
     * @notice Calculates the fee required for Hyperlane message dispatch
     * @dev Queries the Mailbox contract for accurate fee estimation
     * @param _sourceChainId Chain ID of the source chain
     * @param _intentHashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param _data Additional data for message formatting
     * @return Fee amount required for message dispatch
     */
    function fetchFee(
        uint256 _sourceChainId,
        bytes32[] calldata _intentHashes,
        address[] calldata _claimants,
        bytes calldata _data
    ) public view override returns (uint256) {
        // Decode structured data from the raw input
        UnpackedData memory unpacked = _unpackData(_data);

        // Process fee calculation using the decoded struct
        // This architecture separates decoding from core business logic
        return _fetchFee(_sourceChainId, _intentHashes, _claimants, unpacked);
    }

    /**
     * @notice Decodes the raw cross-chain message data into a structured format
     * @dev Parses ABI-encoded parameters into the UnpackedData struct
     * @param _data Raw message data containing source chain information
     * @return unpacked Structured representation of the decoded parameters
     */
    function _unpackData(
        bytes calldata _data
    ) internal pure returns (UnpackedData memory unpacked) {
        (unpacked.sourceChainProver, unpacked.metadata, unpacked.hookAddr) = abi
            .decode(_data, (bytes32, bytes, address));

        return unpacked;
    }

    /**
     * @notice Internal function to calculate the fee with pre-decoded data
     * @param _sourceChainID Chain ID of the source chain
     * @param _intentHashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param unpacked Struct containing decoded data from _data parameter
     * @return Fee amount required for message dispatch
     */
    function _fetchFee(
        uint256 _sourceChainID,
        bytes32[] calldata _intentHashes,
        address[] calldata _claimants,
        UnpackedData memory unpacked
    ) internal view returns (uint256) {
        // Format and prepare message parameters for dispatch
        (
            uint32 sourceChainDomain,
            bytes32 recipientAddress,
            bytes memory messageBody,
            bytes memory metadata,
            IPostDispatchHook hook
        ) = _formatHyperlaneMessage(
                _sourceChainID,
                _intentHashes,
                _claimants,
                unpacked
            );

        // Query Hyperlane mailbox for accurate fee estimate
        return
            IMailbox(MAILBOX).quoteDispatch(
                sourceChainDomain,
                recipientAddress,
                messageBody,
                metadata,
                hook
            );
    }

    /**
     * @notice Returns the proof type used by this prover
     * @return ProofType indicating Hyperlane proving mechanism
     */
    function getProofType() external pure override returns (string memory) {
        return PROOF_TYPE;
    }

    /**
     * @notice Formats data for Hyperlane message dispatch with pre-decoded values
     * @dev Prepares all parameters needed for the Mailbox dispatch call
     * @param _sourceChainID Chain ID of the source chain
     * @param _hashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param _unpacked Struct containing decoded data from _data parameter
     * @return domain Hyperlane domain ID
     * @return recipient Recipient address encoded as bytes32
     * @return message Encoded message body with intent hashes and claimants
     * @return metadata Additional metadata for the message
     * @return hook Post-dispatch hook contract
     */
    function _formatHyperlaneMessage(
        uint256 _sourceChainID,
        bytes32[] calldata _hashes,
        address[] calldata _claimants,
        UnpackedData memory _unpacked
    )
        internal
        view
        returns (
            uint32 domain,
            bytes32 recipient,
            bytes memory message,
            bytes memory metadata,
            IPostDispatchHook hook
        )
    {
        // Centralized validation ensures arrays match exactly once in the call flow
        // This prevents security issues where hashes and claimants could be mismatched
        if (_hashes.length != _claimants.length) {
            revert ArrayLengthMismatch();
        }
        // Convert chain ID to domain
        domain = _convertChainID(_sourceChainID);

        // Use the source chain prover address as the message recipient
        recipient = _unpacked.sourceChainProver;

        // Pack intent hashes and claimant addresses together as the message payload
        message = abi.encode(_hashes, _claimants);

        // Pass through metadata as provided
        metadata = _unpacked.metadata;

        // Default to mailbox's hook if none provided, following Hyperlane best practices
        hook = (_unpacked.hookAddr == address(0))
            ? IMailbox(MAILBOX).defaultHook()
            : IPostDispatchHook(_unpacked.hookAddr);
    }

    function _convertChainID(uint256 _chainID) internal pure returns (uint32) {
        if (_chainID == RARICHAIN_CHAIN_ID) {
            return RARICHAIN_DOMAIN_ID;
        }
        return _chainID.toUint32();
    }
}

File 2 of 17 : IMessageRecipient.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

interface IMessageRecipient {
    function handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) external payable;
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

library TypeCasts {
    // alignment preserving cast
    function addressToBytes32(address _addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_addr)));
    }

    // alignment preserving cast
    function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {
        return address(uint160(uint256(_buf)));
    }
}

/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {BaseProver} from "./BaseProver.sol";
import {IMessageBridgeProver} from "../interfaces/IMessageBridgeProver.sol";
import {Whitelist} from "../tools/Whitelist.sol";
import {Intent} from "../types/Intent.sol";

/**
 * @title MessageBridgeProver
 * @notice Abstract contract for cross-chain message-based proving mechanisms
 * @notice the terms "source" and "destination" are used in reference to a given intent: created on source chain, fulfilled on destination chain
 * @dev Extends BaseProver with functionality for message bridge provers like Hyperlane and Metalayer
 */
abstract contract MessageBridgeProver is
    BaseProver,
    IMessageBridgeProver,
    Whitelist
{
    /**
     * @notice Default gas limit for cross-chain message dispatch
     * @dev Set at deployment and cannot be changed afterward
     */
    uint256 public immutable DEFAULT_GAS_LIMIT;

    /**
     * @notice Initializes the MessageBridgeProver contract
     * @param _inbox Address of the Inbox contract
     * @param _provers Array of trusted prover addresses
     * @param _defaultGasLimit Default gas limit for cross-chain messages (200k if not specified)
     */
    constructor(
        address _inbox,
        address[] memory _provers,
        uint256 _defaultGasLimit
    ) BaseProver(_inbox) Whitelist(_provers) {
        if (_inbox == address(0)) revert InboxCannotBeZeroAddress();

        DEFAULT_GAS_LIMIT = _defaultGasLimit > 0 ? _defaultGasLimit : 200_000;
    }

    /**
     * @notice Challenges a recorded proof
     * @param _intent Intent to challenge
     * @dev Clears the proof if the destination chain ID in the intent does not match the one in the proof
     * @dev even if not challenged, an incorrect proof cannot be used to claim rewards.
     * @dev does nothing if chainID is correct.
     */
    function challengeIntentProof(Intent calldata _intent) public {
        bytes32 intentHash = keccak256(
            abi.encodePacked(
                keccak256(abi.encode(_intent.route)),
                keccak256(abi.encode(_intent.reward))
            )
        );
        uint96 trueDestinationChainID = uint96(_intent.route.destination);

        ProofData storage proofData = _provenIntents[intentHash];

        if (trueDestinationChainID != proofData.destinationChainID) {
            if (proofData.destinationChainID != 0) {
                proofData.claimant = address(0);
                emit BadProofCleared(intentHash);
            }

            proofData.destinationChainID = trueDestinationChainID;
        }
    }

    /**
     * @notice Validates that the message sender is authorized
     * @dev Template method for authorization check
     * @param _messageSender Address attempting to call handle()
     * @param _expectedSender Address that should be authorized
     */
    function _validateMessageSender(
        address _messageSender,
        address _expectedSender
    ) internal pure {
        if (_expectedSender != _messageSender) {
            revert UnauthorizedHandle(_messageSender);
        }
    }

    /**
     * @notice Validates that the proving request is authorized
     * @param _sender Address that sent the proving request
     */
    function _validateProvingRequest(address _sender) internal view {
        if (_sender != INBOX) {
            revert UnauthorizedProve(_sender);
        }
    }

    /**
     * @notice Send refund to the user if they've overpaid
     * @param _recipient Address to send the refund to
     * @param _amount Amount to refund
     */
    function _sendRefund(address _recipient, uint256 _amount) internal {
        if (_amount > 0 && _recipient != address(0)) {
            (bool success, ) = payable(_recipient).call{
                value: _amount,
                gas: 3000
            }("");
            if (!success) {
                revert NativeTransferFailed();
            }
        }
    }

    /**
     * @notice Handles cross-chain messages containing proof data
     * @dev Common implementation to validate and process cross-chain messages
     * @param _destinationDomainID Domain ID of the destination chain
     * @param _messageSender Address that dispatched the message on destination chain
     * @param _message Encoded array of intent hashes and claimants
     */
    function _handleCrossChainMessage(
        uint32 _destinationDomainID,
        address _messageSender,
        bytes calldata _message
    ) internal {
        // Verify dispatch originated from a whitelisted prover address
        if (!isWhitelisted(_messageSender)) {
            revert UnauthorizedIncomingProof(_messageSender);
        }

        uint96 destinationChainID = uint96(_destinationDomainID);
        // Decode message containing intent hashes and claimants
        (bytes32[] memory hashes, address[] memory claimants) = abi.decode(
            _message,
            (bytes32[], address[])
        );

        // Process the intent proofs using shared implementation - array validation happens there
        _processIntentProofs(destinationChainID, hashes, claimants);
    }
}

File 5 of 17 : Semver.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import {ISemver} from "../interfaces/ISemver.sol";

/**
 * @title Semver
 * @notice Implements semantic versioning for contracts
 * @dev Abstract contract that provides a standard way to access version information
 *
 * NOTE: Contract versions are manually managed here and are NOT automatically updated
 * by the semantic-release process. This ensures explicit control over on-chain version
 * reporting and prevents automated changes from affecting deployed contracts.
 *
 * When updating the version:
 * 1. Update the return value in the version() function below
 * 2. Keep this version in sync with major package releases
 * 3. Document the change in release notes
 */
abstract contract Semver is ISemver {
    /**
     * @notice Returns the semantic version of the contract
     * @dev Implementation of ISemver interface
     * @return Current version string in semantic format
     */
    function version() external pure returns (string memory) {
        return "2.6";
    }
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

import {IInterchainSecurityModule} from "./IInterchainSecurityModule.sol";
import {IPostDispatchHook} from "./hooks/IPostDispatchHook.sol";

interface IMailbox {
    // ============ Events ============
    /**
     * @notice Emitted when a new message is dispatched via Hyperlane
     * @param sender The address that dispatched the message
     * @param destination The destination domain of the message
     * @param recipient The message recipient address on `destination`
     * @param message Raw bytes of message
     */
    event Dispatch(
        address indexed sender,
        uint32 indexed destination,
        bytes32 indexed recipient,
        bytes message
    );

    /**
     * @notice Emitted when a new message is dispatched via Hyperlane
     * @param messageId The unique message identifier
     */
    event DispatchId(bytes32 indexed messageId);

    /**
     * @notice Emitted when a Hyperlane message is processed
     * @param messageId The unique message identifier
     */
    event ProcessId(bytes32 indexed messageId);

    /**
     * @notice Emitted when a Hyperlane message is delivered
     * @param origin The origin domain of the message
     * @param sender The message sender address on `origin`
     * @param recipient The address that handled the message
     */
    event Process(
        uint32 indexed origin,
        bytes32 indexed sender,
        address indexed recipient
    );

    function localDomain() external view returns (uint32);

    function delivered(bytes32 messageId) external view returns (bool);

    function defaultIsm() external view returns (IInterchainSecurityModule);

    function defaultHook() external view returns (IPostDispatchHook);

    function requiredHook() external view returns (IPostDispatchHook);

    function latestDispatchedId() external view returns (bytes32);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody
    ) external view returns (uint256 fee);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata body,
        bytes calldata defaultHookMetadata
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody,
        bytes calldata defaultHookMetadata
    ) external view returns (uint256 fee);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata body,
        bytes calldata customHookMetadata,
        IPostDispatchHook customHook
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody,
        bytes calldata customHookMetadata,
        IPostDispatchHook customHook
    ) external view returns (uint256 fee);

    function process(
        bytes calldata metadata,
        bytes calldata message
    ) external payable;

    function recipientIsm(
        address recipient
    ) external view returns (IInterchainSecurityModule module);
}

File 7 of 17 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

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

import {IProver} from "../interfaces/IProver.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @title BaseProver
 * @notice Base implementation for intent proving contracts
 * @dev Provides core storage and functionality for tracking proven intents
 * and their claimants
 */
abstract contract BaseProver is IProver, ERC165 {
    /**
     * @notice Address of the Inbox contract
     * @dev Immutable to prevent unauthorized changes
     */
    address public immutable INBOX;

    /**
     * @notice Mapping from intent hash to address eligible to claim rewards
     * @dev Zero claimant address indicates intent hasn't been proven
     */
    mapping(bytes32 => ProofData) internal _provenIntents;

    /**
     * @notice Initializes the BaseProver contract
     * @param _inbox Address of the Inbox contract
     */
    constructor(address _inbox) {
        INBOX = _inbox;
    }

    /**
     * @notice Fetches a ProofData from the provenIntents mapping
     * @param _intentHash the hash of the intent whose proof data is being queried
     * @return ProofData struct containing the destination chain ID and claimant address
     */
    function provenIntents(
        bytes32 _intentHash
    ) public view returns (ProofData memory) {
        return _provenIntents[_intentHash];
    }

    /**
     * @notice Process intent proofs from a cross-chain message
     * @param _destinationChainID ID of the destination chain
     * @param _hashes Array of intent hashes
     * @param _claimants Array of claimant addresses
     */
    function _processIntentProofs(
        uint96 _destinationChainID,
        bytes32[] memory _hashes,
        address[] memory _claimants
    ) internal {
        // If arrays are empty, just return early
        if (_hashes.length == 0) return;

        // Require matching array lengths for security
        if (_hashes.length != _claimants.length) {
            revert ArrayLengthMismatch();
        }

        for (uint256 i = 0; i < _hashes.length; i++) {
            bytes32 intentHash = _hashes[i];
            address claimant = _claimants[i];

            // Validate claimant is not zero address
            if (claimant == address(0)) {
                continue; // Skip invalid claimants
            }

            // covers an edge case in the event of an attack
            uint96 currentDestinationChainID = provenIntents(intentHash)
                .destinationChainID;
            if (
                _destinationChainID != currentDestinationChainID &&
                currentDestinationChainID != 0
            ) {
                revert BadDestinationChainID(
                    intentHash,
                    currentDestinationChainID,
                    _destinationChainID
                );
            }
            // Skip rather than revert for already proven intents
            ProofData storage proofData = _provenIntents[intentHash];
            if (proofData.claimant != address(0)) {
                emit IntentAlreadyProven(intentHash);
            } else {
                proofData.claimant = claimant;
                proofData.destinationChainID = _destinationChainID;
                emit IntentProven(intentHash, claimant);
            }
        }
    }

    /**
     * @notice Checks if this contract supports a given interface
     * @dev Implements ERC165 interface detection
     * @param interfaceId Interface identifier to check
     * @return True if the interface is supported
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view override returns (bool) {
        return
            interfaceId == type(IProver).interfaceId ||
            super.supportsInterface(interfaceId);
    }
}

File 9 of 17 : IMessageBridgeProver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {IProver} from "./IProver.sol";
import {Intent} from "../types/Intent.sol";

/**
 * @title IMessageBridgeProver
 * @notice Interface for message-bridge based provers
 * @dev Defines common functionality and events for cross-chain message bridge provers
 */
interface IMessageBridgeProver is IProver {
    /**
     * @notice Insufficient fee provided for cross-chain message dispatch
     * @param _requiredFee Amount of fee required
     */
    error InsufficientFee(uint256 _requiredFee);

    /**
     * @notice Native token transfer failed
     */
    error NativeTransferFailed();

    /**
     * @notice Unauthorized call to handle() detected
     * @param _sender Address that attempted the call
     */
    error UnauthorizedHandle(address _sender);

    /**
     * @notice Unauthorized call to initiate proving
     * @param _sender Address that initiated
     */
    error UnauthorizedProve(address _sender);

    /**
     * @notice Unauthorized incoming proof from source chain
     * @param _sender Address that initiated the proof
     */
    error UnauthorizedIncomingProof(address _sender);

    /**
     * @notice Mailbox address cannot be zero
     */
    error MailboxCannotBeZeroAddress();

    /**
     * @notice Router address cannot be zero
     */
    error RouterCannotBeZeroAddress();

    /**
     * @notice Inbox address cannot be zero
     */
    error InboxCannotBeZeroAddress();

    /**
     * @notice Invalid chain ID for the origin
     */
    error InvalidOriginChainId();

    /**
     * @notice Sender address cannot be zero
     */
    error SenderCannotBeZeroAddress();

    /**
     * @notice Emitted when a batch of fulfilled intents is sent to be relayed to the source chain
     * @param _hashes Intent hashes sent in the batch
     * @param _sourceChainID ID of the source chain
     */
    event BatchSent(bytes32[] indexed _hashes, uint256 indexed _sourceChainID);

    /**
     * @notice Emitted when an intentProof is successfully challenged
     * @param _intentHash Hash of the intent whose proof was challenged
     */
    event BadProofCleared(bytes32 indexed _intentHash);

    /**
     * @notice Calculates the fee required for message dispatch
     * @param _sourceChainID Chain ID of source chain
     * @param _intentHashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param _data Additional data for message formatting.
     *        Specific format varies by implementation:
     *        - HyperProver: (bytes32 sourceChainProver, bytes metadata, address hookAddr, [uint256 gasLimitOverride])
     *        - MetaProver: (bytes32 sourceChainProver, [uint256 gasLimitOverride])
     * @return Fee amount required for message dispatch
     */
    function fetchFee(
        uint256 _sourceChainID,
        bytes32[] calldata _intentHashes,
        address[] calldata _claimants,
        bytes calldata _data
    ) external view returns (uint256);
}

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

/**
 * @title Whitelist
 * @notice Abstract contract providing immutable whitelist functionality
 * @dev Uses immutable arrays to store up to 20 whitelisted addresses
 *
 * This contract provides a gas-efficient, immutable approach to whitelisting:
 * - The whitelist is configured ONCE at construction time
 * - After deployment, the whitelist CANNOT be modified (addresses cannot be added or removed)
 * - Maximum of 20 addresses can be whitelisted
 * - Uses immutable slots for each whitelisted address (lower gas cost than storage)
 * - Optimized for early exit when checking whitelist membership
 */
abstract contract Whitelist {
    /**
     * @notice Error thrown when an address is not whitelisted
     * @param addr The address that was not found in the whitelist
     */
    error AddressNotWhitelisted(address addr);

    /// @dev Maximum number of addresses that can be whitelisted
    uint256 private constant MAX_WHITELIST_SIZE = 20;

    /// @dev Number of addresses actually in the whitelist
    uint256 private immutable WHITELIST_SIZE;

    /// @dev Immutable storage for whitelisted addresses (up to 20)
    address private immutable ADDRESS_1;
    address private immutable ADDRESS_2;
    address private immutable ADDRESS_3;
    address private immutable ADDRESS_4;
    address private immutable ADDRESS_5;
    address private immutable ADDRESS_6;
    address private immutable ADDRESS_7;
    address private immutable ADDRESS_8;
    address private immutable ADDRESS_9;
    address private immutable ADDRESS_10;
    address private immutable ADDRESS_11;
    address private immutable ADDRESS_12;
    address private immutable ADDRESS_13;
    address private immutable ADDRESS_14;
    address private immutable ADDRESS_15;
    address private immutable ADDRESS_16;
    address private immutable ADDRESS_17;
    address private immutable ADDRESS_18;
    address private immutable ADDRESS_19;
    address private immutable ADDRESS_20;

    /**
     * @notice Initializes the whitelist with a set of addresses
     * @param addresses Array of addresses to whitelist
     */
    constructor(address[] memory addresses) {
        require(addresses.length <= MAX_WHITELIST_SIZE);

        // Store whitelist size
        WHITELIST_SIZE = addresses.length;

        // Initialize all addresses to zero address
        ADDRESS_1 = addresses.length > 0 ? addresses[0] : address(0);
        ADDRESS_2 = addresses.length > 1 ? addresses[1] : address(0);
        ADDRESS_3 = addresses.length > 2 ? addresses[2] : address(0);
        ADDRESS_4 = addresses.length > 3 ? addresses[3] : address(0);
        ADDRESS_5 = addresses.length > 4 ? addresses[4] : address(0);
        ADDRESS_6 = addresses.length > 5 ? addresses[5] : address(0);
        ADDRESS_7 = addresses.length > 6 ? addresses[6] : address(0);
        ADDRESS_8 = addresses.length > 7 ? addresses[7] : address(0);
        ADDRESS_9 = addresses.length > 8 ? addresses[8] : address(0);
        ADDRESS_10 = addresses.length > 9 ? addresses[9] : address(0);
        ADDRESS_11 = addresses.length > 10 ? addresses[10] : address(0);
        ADDRESS_12 = addresses.length > 11 ? addresses[11] : address(0);
        ADDRESS_13 = addresses.length > 12 ? addresses[12] : address(0);
        ADDRESS_14 = addresses.length > 13 ? addresses[13] : address(0);
        ADDRESS_15 = addresses.length > 14 ? addresses[14] : address(0);
        ADDRESS_16 = addresses.length > 15 ? addresses[15] : address(0);
        ADDRESS_17 = addresses.length > 16 ? addresses[16] : address(0);
        ADDRESS_18 = addresses.length > 17 ? addresses[17] : address(0);
        ADDRESS_19 = addresses.length > 18 ? addresses[18] : address(0);
        ADDRESS_20 = addresses.length > 19 ? addresses[19] : address(0);
    }

    /**
     * @notice Checks if an address is whitelisted
     * @param addr Address to check
     * @return True if the address is whitelisted, false otherwise
     */
    function isWhitelisted(address addr) public view returns (bool) {
        // Short circuit check for empty whitelist
        if (WHITELIST_SIZE == 0) return false;

        // Short circuit check for zero address
        if (addr == address(0)) return false;

        if (ADDRESS_1 == addr) return true;
        if (WHITELIST_SIZE <= 1) return false;

        if (ADDRESS_2 == addr) return true;
        if (WHITELIST_SIZE <= 2) return false;

        if (ADDRESS_3 == addr) return true;
        if (WHITELIST_SIZE <= 3) return false;

        if (ADDRESS_4 == addr) return true;
        if (WHITELIST_SIZE <= 4) return false;

        if (ADDRESS_5 == addr) return true;
        if (WHITELIST_SIZE <= 5) return false;

        if (ADDRESS_6 == addr) return true;
        if (WHITELIST_SIZE <= 6) return false;

        if (ADDRESS_7 == addr) return true;
        if (WHITELIST_SIZE <= 7) return false;

        if (ADDRESS_8 == addr) return true;
        if (WHITELIST_SIZE <= 8) return false;

        if (ADDRESS_9 == addr) return true;
        if (WHITELIST_SIZE <= 9) return false;

        if (ADDRESS_10 == addr) return true;
        if (WHITELIST_SIZE <= 10) return false;

        if (ADDRESS_11 == addr) return true;
        if (WHITELIST_SIZE <= 11) return false;

        if (ADDRESS_12 == addr) return true;
        if (WHITELIST_SIZE <= 12) return false;

        if (ADDRESS_13 == addr) return true;
        if (WHITELIST_SIZE <= 13) return false;

        if (ADDRESS_14 == addr) return true;
        if (WHITELIST_SIZE <= 14) return false;

        if (ADDRESS_15 == addr) return true;
        if (WHITELIST_SIZE <= 15) return false;

        if (ADDRESS_16 == addr) return true;
        if (WHITELIST_SIZE <= 16) return false;

        if (ADDRESS_17 == addr) return true;
        if (WHITELIST_SIZE <= 17) return false;

        if (ADDRESS_18 == addr) return true;
        if (WHITELIST_SIZE <= 18) return false;

        if (ADDRESS_19 == addr) return true;
        if (WHITELIST_SIZE <= 19) return false;

        return ADDRESS_20 == addr;
    }

    /**
     * @notice Validates that an address is whitelisted, reverting if not
     * @param addr Address to validate
     */
    function validateWhitelisted(address addr) internal view {
        if (!isWhitelisted(addr)) {
            revert AddressNotWhitelisted(addr);
        }
    }

    /**
     * @notice Returns the list of whitelisted addresses
     * @return whitelist Array of whitelisted addresses
     */
    function getWhitelist() public view returns (address[] memory) {
        address[] memory whitelist = new address[](WHITELIST_SIZE);

        if (WHITELIST_SIZE > 0) whitelist[0] = ADDRESS_1;
        if (WHITELIST_SIZE > 1) whitelist[1] = ADDRESS_2;
        if (WHITELIST_SIZE > 2) whitelist[2] = ADDRESS_3;
        if (WHITELIST_SIZE > 3) whitelist[3] = ADDRESS_4;
        if (WHITELIST_SIZE > 4) whitelist[4] = ADDRESS_5;
        if (WHITELIST_SIZE > 5) whitelist[5] = ADDRESS_6;
        if (WHITELIST_SIZE > 6) whitelist[6] = ADDRESS_7;
        if (WHITELIST_SIZE > 7) whitelist[7] = ADDRESS_8;
        if (WHITELIST_SIZE > 8) whitelist[8] = ADDRESS_9;
        if (WHITELIST_SIZE > 9) whitelist[9] = ADDRESS_10;
        if (WHITELIST_SIZE > 10) whitelist[10] = ADDRESS_11;
        if (WHITELIST_SIZE > 11) whitelist[11] = ADDRESS_12;
        if (WHITELIST_SIZE > 12) whitelist[12] = ADDRESS_13;
        if (WHITELIST_SIZE > 13) whitelist[13] = ADDRESS_14;
        if (WHITELIST_SIZE > 14) whitelist[14] = ADDRESS_15;
        if (WHITELIST_SIZE > 15) whitelist[15] = ADDRESS_16;
        if (WHITELIST_SIZE > 16) whitelist[16] = ADDRESS_17;
        if (WHITELIST_SIZE > 17) whitelist[17] = ADDRESS_18;
        if (WHITELIST_SIZE > 18) whitelist[18] = ADDRESS_19;
        if (WHITELIST_SIZE > 19) whitelist[19] = ADDRESS_20;

        return whitelist;
    }

    /**
     * @notice Returns the number of whitelisted addresses
     * @return Number of addresses in the whitelist
     */
    function getWhitelistSize() public view returns (uint256) {
        return WHITELIST_SIZE;
    }
}

File 11 of 17 : Intent.sol
/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/**
 * @notice Represents a single contract call with encoded function data
 * @dev Used to execute arbitrary function calls on the destination chain
 * @param target The contract address to call
 * @param data ABI-encoded function call data
 * @param value Amount of native tokens to send with the call
 */
struct Call {
    address target;
    bytes data;
    uint256 value;
}

/**
 * @notice Represents a token amount pair
 * @dev Used to specify token rewards and transfers
 * @param token Address of the ERC20 token contract
 * @param amount Amount of tokens in the token's smallest unit
 */
struct TokenAmount {
    address token;
    uint256 amount;
}

/**
 * @notice Defines the routing and execution instructions for cross-chain messages
 * @dev Contains all necessary information to route and execute a message on the destination chain
 * @param salt Unique identifier provided by the intent creator, used to prevent duplicates
 * @param source Chain ID where the intent originated
 * @param destination Target chain ID where the calls should be executed
 * @param inbox Address of the inbox contract on the destination chain that receives messages
 * @param tokens Array of tokens required for execution of calls on destination chain
 * @param calls Array of contract calls to execute on the destination chain in sequence
 */
struct Route {
    bytes32 salt;
    uint256 source;
    uint256 destination;
    address inbox;
    TokenAmount[] tokens;
    Call[] calls;
}

/**
 * @notice Defines the reward and validation parameters for cross-chain execution
 * @dev Specifies who can execute the intent and what rewards they receive
 * @param creator Address that created the intent and has authority to modify/cancel
 * @param prover Address of the prover contract that must approve execution
 * @param deadline Timestamp after which the intent can no longer be executed
 * @param nativeValue Amount of native tokens offered as reward
 * @param tokens Array of ERC20 tokens and amounts offered as additional rewards
 */
struct Reward {
    address creator;
    address prover;
    uint256 deadline;
    uint256 nativeValue;
    TokenAmount[] tokens;
}

/**
 * @notice Complete cross-chain intent combining routing and reward information
 * @dev Main structure used to process and execute cross-chain messages
 * @param route Routing and execution instructions
 * @param reward Reward and validation parameters
 */
struct Intent {
    Route route;
    Reward reward;
}

File 12 of 17 : ISemver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/**
 * @title Semver Interface
 * @dev An interface for a contract that has a version
 */
interface ISemver {
    function version() external pure returns (string memory);
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

interface IInterchainSecurityModule {
    enum Types {
        UNUSED,
        ROUTING,
        AGGREGATION,
        LEGACY_MULTISIG,
        MERKLE_ROOT_MULTISIG,
        MESSAGE_ID_MULTISIG,
        NULL, // used with relayer carrying no metadata
        CCIP_READ,
        ARB_L2_TO_L1,
        WEIGHT_MERKLE_ROOT_MULTISIG,
        WEIGHT_MESSAGE_ID_MULTISIG,
        OP_L2_TO_L1
    }

    /**
     * @notice Returns an enum that represents the type of security model
     * encoded by this ISM.
     * @dev Relayers infer how to fetch and format metadata.
     */
    function moduleType() external view returns (uint8);

    /**
     * @notice Defines a security model responsible for verifying interchain
     * messages based on the provided metadata.
     * @param _metadata Off-chain metadata provided by a relayer, specific to
     * the security model encoded by the module (e.g. validator signatures)
     * @param _message Hyperlane encoded interchain message
     * @return True if the message was verified
     */
    function verify(
        bytes calldata _metadata,
        bytes calldata _message
    ) external returns (bool);
}

interface ISpecifiesInterchainSecurityModule {
    function interchainSecurityModule()
        external
        view
        returns (IInterchainSecurityModule);
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
     @@@@@  HYPERLANE  @@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
@@@@@@@@@       @@@@@@@@*/

interface IPostDispatchHook {
    enum Types {
        UNUSED,
        ROUTING,
        AGGREGATION,
        MERKLE_TREE,
        INTERCHAIN_GAS_PAYMASTER,
        FALLBACK_ROUTING,
        ID_AUTH_ISM,
        PAUSABLE,
        PROTOCOL_FEE,
        LAYER_ZERO_V1,
        RATE_LIMITED,
        ARB_L2_TO_L1,
        OP_L2_TO_L1
    }

    /**
     * @notice Returns an enum that represents the type of hook
     */
    function hookType() external view returns (uint8);

    /**
     * @notice Returns whether the hook supports metadata
     * @param metadata metadata
     * @return Whether the hook supports metadata
     */
    function supportsMetadata(
        bytes calldata metadata
    ) external view returns (bool);

    /**
     * @notice Post action after a message is dispatched via the Mailbox
     * @param metadata The metadata required for the hook
     * @param message The message passed from the Mailbox.dispatch() call
     */
    function postDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) external payable;

    /**
     * @notice Compute the payment required by the postDispatch call
     * @param metadata The metadata required for the hook
     * @param message The message passed from the Mailbox.dispatch() call
     * @return Quoted payment for the postDispatch call
     */
    function quoteDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) external view returns (uint256);
}

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

import {ISemver} from "./ISemver.sol";
import {Intent} from "../types/Intent.sol";

/**
 * @title IProver
 * @notice Interface for proving intent fulfillment
 * @dev Defines required functionality for proving intent execution with different
 * proof mechanisms (storage or Hyperlane)
 */
interface IProver is ISemver {
    struct ProofData {
        uint96 destinationChainID;
        address claimant;
    }

    /**
     * @notice Arrays of intent hashes and claimants must have the same length
     */
    error ArrayLengthMismatch();

    /**
     * @notice Destination chain ID associated with intent does not match that in proof.
     * @param _hash Hash of the intent
     * @param _expectedDestinationChainID Expected destination chain ID for the intent
     * @param _actualDestinationChainID Actual destination chain ID for the intent
     */
    error BadDestinationChainID(
        bytes32 _hash,
        uint96 _expectedDestinationChainID,
        uint96 _actualDestinationChainID
    );

    /**
     * @notice Emitted when an intent is successfully proven
     * @param _hash Hash of the proven intent
     * @param _claimant Address eligible to claim the intent's rewards
     */
    event IntentProven(bytes32 indexed _hash, address indexed _claimant);

    /**
     * @notice Emitted when attempting to prove an already-proven intent
     * @dev Event instead of error to allow batch processing to continue
     * @param _intentHash Hash of the already proven intent
     */
    event IntentAlreadyProven(bytes32 _intentHash);

    /**
     * @notice Fetches a ProofData from the provenIntents mapping
     * @param _intentHash the hash of the intent whose proof data is being queried
     * @return ProofData struct containing the destination chain ID and claimant address
     */
    function provenIntents(
        bytes32 _intentHash
    ) external view returns (ProofData memory);

    /**
     * @notice Gets the proof mechanism type used by this prover
     * @return string indicating the prover's mechanism
     */
    function getProofType() external pure returns (string memory);

    /**
     * @notice Initiates the proving process for intents from the destination chain
     * @dev Implemented by specific prover mechanisms (storage, Hyperlane, Metalayer)
     * @param _sender Address of the original transaction sender
     * @param _sourceChainId Chain ID of the source chain
     * @param _intentHashes Array of intent hashes to prove
     * @param _claimants Array of claimant addresses
     * @param _data Additional data specific to the proving implementation
     */
    function prove(
        address _sender,
        uint256 _sourceChainId,
        bytes32[] calldata _intentHashes,
        address[] calldata _claimants,
        bytes calldata _data
    ) external payable;

    /**
     * @notice Challenges a recorded proof
     * @param _intent Intent to challenge
     * @dev Clears the proof if the destination chain ID in the intent does not match the one in the proof
     * @dev even if not challenged, an incorrect proof cannot be used to claim rewards.
     * @dev does nothing if chainID is correct
     */
    function challengeIntentProof(Intent calldata _intent) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
    "@hyperlane-xyz/core/=node_modules/@hyperlane-xyz/core/",
    "@eth-optimism/contracts-bedrock/=node_modules/@eth-optimism/contracts-bedrock/",
    "@metalayer/contracts/=node_modules/@metalayer/contracts/",
    "createx/=lib/createx/src/",
    "ds-test/=lib/createx/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/",
    "solady/=lib/createx/lib/solady/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_mailbox","type":"address"},{"internalType":"address","name":"_inbox","type":"address"},{"internalType":"address[]","name":"_provers","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"AddressNotWhitelisted","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"uint96","name":"_expectedDestinationChainID","type":"uint96"},{"internalType":"uint96","name":"_actualDestinationChainID","type":"uint96"}],"name":"BadDestinationChainID","type":"error"},{"inputs":[],"name":"InboxCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requiredFee","type":"uint256"}],"name":"InsufficientFee","type":"error"},{"inputs":[],"name":"InvalidOriginChainId","type":"error"},{"inputs":[],"name":"MailboxCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"RouterCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"SenderCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"UnauthorizedHandle","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"UnauthorizedIncomingProof","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"UnauthorizedProve","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_intentHash","type":"bytes32"}],"name":"BadProofCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32[]","name":"_hashes","type":"bytes32[]"},{"indexed":true,"internalType":"uint256","name":"_sourceChainID","type":"uint256"}],"name":"BatchSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_intentHash","type":"bytes32"}],"name":"IntentAlreadyProven","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_claimant","type":"address"}],"name":"IntentProven","type":"event"},{"inputs":[],"name":"DEFAULT_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INBOX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAILBOX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROOF_TYPE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RARICHAIN_CHAIN_ID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RARICHAIN_DOMAIN_ID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"_intent","type":"tuple"}],"name":"challengeIntentProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sourceChainId","type":"uint256"},{"internalType":"bytes32[]","name":"_intentHashes","type":"bytes32[]"},{"internalType":"address[]","name":"_claimants","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"fetchFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProofType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getWhitelist","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_origin","type":"uint32"},{"internalType":"bytes32","name":"_sender","type":"bytes32"},{"internalType":"bytes","name":"_messageBody","type":"bytes"}],"name":"handle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint256","name":"_sourceChainId","type":"uint256"},{"internalType":"bytes32[]","name":"_intentHashes","type":"bytes32[]"},{"internalType":"address[]","name":"_claimants","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"prove","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_intentHash","type":"bytes32"}],"name":"provenIntents","outputs":[{"components":[{"internalType":"uint96","name":"destinationChainID","type":"uint96"},{"internalType":"address","name":"claimant","type":"address"}],"internalType":"struct IProver.ProofData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

0x61038060405234610664576125348038038061001a81610694565b92833981019060608183031261066457610033816106b9565b91610040602083016106b9565b604083015190926001600160401b038211610664570181601f82011215610664578051916001600160401b038311610680578260051b916020610084818501610694565b8095815201906020829482010192831161066457602001905b82821061066857505050826080528151601481116106645760a05281511561065d578151156105d657516001600160a01b03165b60c05260018151115f14610657578051600110156105d65760408101516001600160a01b03165b60e05260028151115f14610651578051600210156105d65760608101516001600160a01b03165b6101005260038151115f1461064b578051600310156105d65760808101516001600160a01b03165b6101205260048151115f14610645578051600410156105d65760a08101516001600160a01b03165b6101405260058151115f1461063f578051600510156105d65760c08101516001600160a01b03165b6101605260068151115f14610639578051600610156105d65760e08101516001600160a01b03165b6101805260078151115f14610633578051600710156105d6576101008101516001600160a01b03165b6101a05260088151115f1461062d578051600810156105d6576101208101516001600160a01b03165b6101c05260098151115f14610627578051600910156105d6576101408101516001600160a01b03165b6101e052600a8151115f14610621578051600a10156105d6576101608101516001600160a01b03165b61020052600b8151115f1461061b578051600b10156105d6576101808101516001600160a01b03165b61022052600c8151115f14610615578051600c10156105d6576101a08101516001600160a01b03165b61024052600d8151115f1461060f578051600d10156105d6576101c08101516001600160a01b03165b61026052600e8151115f14610609578051600e10156105d6576101e08101516001600160a01b03165b61028052600f8151115f14610603578051600f10156105d6576102008101516001600160a01b03165b6102a05260108151115f146105fd578051601010156105d6576102208101516001600160a01b03165b6102c05260118151115f146105f7578051601110156105d6576102408101516001600160a01b03165b6102e05260128151115f146105f1578051601210156105d6576102608101516001600160a01b03165b6103005260138151115f146105ea578051601310156105d65761028001516001600160a01b03165b610320526001600160a01b0316156105c75762030d40610340526001600160a01b038116156105b85761036052604051611e6690816106ce8239608051818181610b090152610d58015260a05181818161044f01528181610dbc0152611410015260c051818181610a5e0152611448015260e051818181610a2301526114810152610100518181816109e501526114ba0152610120518181816109a701526114f3015261014051818181610969015261152c01526101605181818161092b01526115650152610180518181816108ed015261159e01526101a0518181816108ae01526115d701526101c05181818161086f015261161001526101e05181818161083001526116490152610200518181816107f101526116820152610220518181816107b201526116bb01526102405181818161077301526116f4015261026051818181610734015261172d0152610280518181816106f5015261176601526102a0518181816106b6015261179f01526102c05181818161067701526117d801526102e05181818161063801526118110152610300518181816105f9015261184a0152610320518181816105a601526118820152610340518161041a015261036051818181610bdb01528181610e3901528181610ec701528181611afa0152611c190152f35b6385405fbf60e01b5f5260045ffd5b63384c34c960e21b5f5260045ffd5b634e487b7160e01b5f52603260045260245ffd5b505f6103d3565b5f6103ab565b5f610382565b5f610359565b5f610330565b5f610307565b5f6102de565b5f6102b5565b5f61028c565b5f610263565b5f61023a565b5f610211565b5f6101e8565b5f6101bf565b5f610197565b5f61016f565b5f610147565b5f61011f565b5f6100f8565b505f6100d1565b5f80fd5b60208091610675846106b9565b81520191019061009d565b634e487b7160e01b5f52604160045260245ffd5b6040519190601f01601f191682016001600160401b0381118382101761068057604052565b51906001600160a01b03821682036106645756fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461127e5750806321ec34a0146111ed5780633af32abf146111c057806354fd4d501461117b57806356d5d47514610e86578063740a4cfd14610e685780637dc2b8fb14610e2457806399d145b214610ddf57806399db89b514610da55780639bcd850f14610d10578063ae1a61ca14610d87578063b701069714610d43578063bc8c7df214610d10578063c87adc8c14610a8d578063d01f63f51461043d578063d6be695a146104035763e9cd2bdd146100d7575f80fd5b3461034b57602036600319011261034b576004356001600160401b03811161034b578060040190803603604060031982011261034b57610117838061197a565b60405160208101916020835280356040830152602081013560608301526040810135608083015260018060a01b0361015160608301611344565b1660a0830152610178610167608083018361198f565b60c0808601526101008501916119c3565b9060a0810135601e198236030181121561034b570190813560208301926001600160401b03821161034b578160051b90813603851361034b57603f198685030160e087015282845285936020928101830193928101915f91607e193683900301905b85841061034f575050505050506101fa925003601f1981018352826113ab565b5190209160248101359160a2190182121561034b576001600160601b03926040926102cf92016102876102a6600483016102988751938492608460208501976020895260018060a01b0361024d84611344565b16868d01526001600160a01b0361026660248301611344565b16606087015260448101356080870152606481013560a0870152019061198f565b60a060c085015260e08401916119c3565b03601f1981018352826113ab565b51902083519060208201928352848201528381526102c56060826113ab565b519020938061197a565b01351690805f525f60205260405f20916001600160601b03835416918282036102f457005b6001600160601b039261031b575b5082546bffffffffffffffffffffffff19169116179055005b8284541684557f3dd9cba269724793ff11df09fbd9cad1bc22ee8ae462171482c6c1a3e44de5335f80a25f610302565b5f80fd5b9193959092949650601f1982820301865287358381121561034b5784016001600160a01b0361038060208301611344565b1682526040810135603e19368390030181121561034b5781602091010190602082359201906001600160401b03831161034b57823603821361034b57838360606080936020968796838860019b01528184870152868601375f85848601015201356040830152601f801991011601019901960194019188969493919795976101da565b3461034b575f36600319011261034b5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461034b575f36600319011261034b577f00000000000000000000000000000000000000000000000000000000000000006104778161194f565b9061048560405192836113ab565b8082526104918161194f565b602083019190601f190136833780610a55575b60018111610a17575b600281116109d9575b6003811161099b575b6004811161095d575b6005811161091f575b600681116108e1575b600781116108a2575b60088111610863575b60098111610824575b600a81116107e5575b600b81116107a6575b600c8111610767575b600d8111610728575b600e81116106e9575b600f81116106aa575b6010811161066b575b6011811161062c575b601281116105ed575b60131061059a575b90604051918291602083019060208452518091526040830191905f5b818110610578575050500390f35b82516001600160a01b031684528594506020938401939092019160010161056a565b8151601310156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661028083015261054e565b634e487b7160e01b5f52603260045260245ffd5b8251601210156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610260840152610546565b8251601110156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661024084015261053d565b8251601010156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610220840152610534565b8251600f10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661020084015261052b565b8251600e10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101e0840152610522565b8251600d10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101c0840152610519565b8251600c10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101a0840152610510565b8251600b10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610180840152610507565b8251600a10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101608401526104fe565b8251600910156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101408401526104f5565b8251600810156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101208401526104ec565b8251600710156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101008401526104e3565b8251600610156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660e08401526104da565b8251600510156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660c08401526104d1565b8251600410156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660a08401526104c8565b8251600310156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660808401526104bf565b8251600210156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660608401526104b6565b8251600110156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660408401526104ad565b8251156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682526104a4565b60a036600319011261034b57610aa161132e565b602435906044356001600160401b03811161034b57610ac49036906004016112d1565b92906064356001600160401b03811161034b57610ae59036906004016112d1565b9290946084356001600160401b03811161034b57610b07903690600401611301565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610cfd57610b4091611a0c565b610b4e818689858888611ac1565b94853410610cea575f97863411610cc4575b604051936001600160fb1b03811161034b5760209686610bd79787610bb5988560051b8086833781010390207fd6383b4658ff90fe5c7fb8d1fe7a0b6cc87b7ecaf49d2305c1fed682f39548325f80a3611b64565b6040516242e0f760e61b81529788969095879586959294929160048701611903565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610cb957610c8a575b5081151580610c78575b610c2057005b5f918291829182916001600160a01b0316610bb8f13d15610c73573d610c45816113cc565b90610c5360405192836113ab565b81525f60203d92013e5b15610c6457005b633d2cec6f60e21b5f5260045ffd5b610c5d565b506001600160a01b0381161515610c1a565b6020813d602011610cb1575b81610ca3602093836113ab565b8101031261034b5751610c10565b3d9150610c96565b6040513d5f823e3d90fd5b9750853403348111610cd65797610b60565b634e487b7160e01b5f52601160045260245ffd5b8563131398d760e21b5f5260045260245ffd5b63cc44a19b60e01b5f523360045260245ffd5b3461034b575f36600319011261034b57610d3f610d2b6113e7565b604051918291602083526020830190611358565b0390f35b3461034b575f36600319011261034b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461034b575f36600319011261034b576020604051633b9afb498152f35b3461034b575f36600319011261034b5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461034b57602036600319011261034b576040610dfd6004356118c0565b815181516001600160601b031681526020918201516001600160a01b031691810191909152f35b3461034b575f36600319011261034b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461034b575f36600319011261034b57602060405163524152498152f35b606036600319011261034b5760043563ffffffff811680910361034b576044356001600160401b03811161034b57610ec2903690600401611301565b9091337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603611168578015611159576024356001600160a01b031690811561114a57633b9afb49810361103d5750610f228161140e565b1561102b575081019060408183031261034b5780356001600160401b03811161034b5781019082601f8301121561034b57813591610f5f8361194f565b92610f6d60405194856113ab565b80845260208085019160051b8301019185831161034b57602001905b82821061101b575050506020810135906001600160401b03821161034b57019082601f8301121561034b57813592610fc08461194f565b92610fce60405194856113ab565b84845260208085019560051b82010191821161034b57602001935b81851061100357505061100192506352415249611cd5565b005b6020809161101087611344565b815201940193610fe9565b8135815260209182019101610f89565b6301195a3f60e11b5f5260045260245ffd5b91906110488161140e565b1561102b575082019160408184031261034b5780356001600160401b03811161034b5781019083601f8301121561034b578135916110858361194f565b9261109360405194856113ab565b80845260208085019160051b8301019186831161034b57602001905b82821061113a575050506020810135906001600160401b03821161034b57019183601f8401121561034b578235936110e68561194f565b936110f460405195866113ab565b85855260208086019660051b82010191821161034b57602001945b8186106111225750506110019350611cd5565b6020809161112f88611344565b81520195019461110f565b81358152602091820191016110af565b635d336e1d60e11b5f5260045ffd5b63c5ac559960e01b5f5260045ffd5b63188c4f9b60e01b5f523360045260245ffd5b3461034b575f36600319011261034b57610d3f60405161119c6040826113ab565b600381526219171b60e91b6020820152604051918291602083526020830190611358565b3461034b57602036600319011261034b5760206111e36111de61132e565b61140e565b6040519015158152f35b3461034b57608036600319011261034b576024356001600160401b03811161034b5761121d9036906004016112d1565b906044356001600160401b03811161034b5761123d9036906004016112d1565b60643592916001600160401b03841161034b5760209461126d611267611276963690600401611301565b90611a0c565b93600435611ac1565b604051908152f35b3461034b57602036600319011261034b576004359063ffffffff60e01b821680920361034b576020916308eacdfb60e21b81149081156112c0575b5015158152f35b6301ffc9a760e01b149050836112b9565b9181601f8401121561034b578235916001600160401b03831161034b576020808501948460051b01011161034b57565b9181601f8401121561034b578235916001600160401b03831161034b576020838186019501011161034b57565b600435906001600160a01b038216820361034b57565b35906001600160a01b038216820361034b57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b604081019081106001600160401b0382111761139757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761139757604052565b6001600160401b03811161139757601f01601f191660200190565b604051906113f66040836113ab565b600982526848797065726c616e6560b81b6020830152565b7f00000000000000000000000000000000000000000000000000000000000000009081156118ba576001600160a01b03169081156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760018111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760028111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760038111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760048111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760058111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760068111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760078111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760088111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760098111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600a8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600b8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600c8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600d8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600e8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600f8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760108111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760118111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760128111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357601310156118ae577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161490565b505f90565b5050600190565b50505f90565b5f60206040516118cf8161137c565b82815201525f525f60205260405f20604051906118eb8261137c565b546001600160601b038116825260601c602082015290565b939060809361193f9363ffffffff61193193999899168752602087015260a0604087015260a0860190611358565b908482036060860152611358565b6001600160a01b03909416910152565b6001600160401b0381116113975760051b60200190565b80518210156105d95760209160051b010190565b90359060be198136030182121561034b570190565b9035601e198236030181121561034b5701602081359101916001600160401b03821161034b578160061b3603831361034b57565b916020908281520191905f5b8181106119dc5750505090565b909192604080600192838060a01b036119f488611344565b168152602087810135908201520194019291016119cf565b60405191606083018381106001600160401b03821117611397576040525f8352602083016060815260408401915f835283019160608484031261034b5760208401356001600160401b03811161034b57840183601f8201121561034b57803590611a75826113cc565b94611a8360405196876113ab565b8286526020838301011161034b57815f926020809301838801378501015260408401356001600160a01b038116919082900361034b57525235815290565b92611af6959260209592611ad495611b64565b6040516381d2ea9560e01b815296879586959194929392919060048701611903565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610cb9575f91611b35575090565b90506020813d602011611b5c575b81611b50602093836113ab565b8101031261034b575190565b3d9150611b43565b9593959492909194868603611cc657611b7c90611e27565b95835195604051936040602086015281606086015260018060fb1b03821161034b5760a0908593949260051b8091608086013783018460808201601f19608087850301016040870152520190925f5b818110611c96575050611be7925003601f1981018352826113ab565b60208201516040909201519092906001600160a01b031680611c935750604051633d1250b760e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610cb9575f91611c54575090565b90506020813d602011611c8b575b81611c6f602093836113ab565b8101031261034b57516001600160a01b038116810361034b5790565b3d9150611c62565b90565b9092509060019060209081906001600160a01b03611cb388611344565b1681520194019101918492939193611bcb565b63512509d360e11b5f5260045ffd5b92919080518015611e2057825103611cc6579291905f935b8051851015611e1957611d008582611966565b5194611d0c8184611966565b51956001600160a01b038716908115611e0a576001600160601b03611d30826118c0565b5116976001600160601b03881698808a141580611e01575b611de6575060019495969798825f525f60205260405f2091825460601c15155f14611da8575050507fc86ca07015d7e87a46a98098d36c9fc68bc3120761e5c7a2023fc6c6869e56119150602090604051908152a15b0193929190611ced565b60601b6bffffffffffffffffffffffff19161790557f2b45193f790d995b36e39c4104dd1b49df6fc851b6f6ae60f2072724735b5b435f80a3611d9e565b89908363058a3b9d60e41b5f5260045260245260445260645ffd5b50801515611d48565b50506001919293949550611d9e565b5050915050565b5050509050565b63524152498114611e5d5763ffffffff8111611e465763ffffffff1690565b6306dfcc6560e41b5f52602060045260245260445ffd5b50633b9afb4990560000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7000000000000000000000000c06f962a412c7af34e44d324aabf340365f29a55000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f124aa8f92f47302fcba08b7349aefee853ed8d0000000000000000000000001871c138ceab2bb36c5dbcaed0ab4bc88271fee7

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461127e5750806321ec34a0146111ed5780633af32abf146111c057806354fd4d501461117b57806356d5d47514610e86578063740a4cfd14610e685780637dc2b8fb14610e2457806399d145b214610ddf57806399db89b514610da55780639bcd850f14610d10578063ae1a61ca14610d87578063b701069714610d43578063bc8c7df214610d10578063c87adc8c14610a8d578063d01f63f51461043d578063d6be695a146104035763e9cd2bdd146100d7575f80fd5b3461034b57602036600319011261034b576004356001600160401b03811161034b578060040190803603604060031982011261034b57610117838061197a565b60405160208101916020835280356040830152602081013560608301526040810135608083015260018060a01b0361015160608301611344565b1660a0830152610178610167608083018361198f565b60c0808601526101008501916119c3565b9060a0810135601e198236030181121561034b570190813560208301926001600160401b03821161034b578160051b90813603851361034b57603f198685030160e087015282845285936020928101830193928101915f91607e193683900301905b85841061034f575050505050506101fa925003601f1981018352826113ab565b5190209160248101359160a2190182121561034b576001600160601b03926040926102cf92016102876102a6600483016102988751938492608460208501976020895260018060a01b0361024d84611344565b16868d01526001600160a01b0361026660248301611344565b16606087015260448101356080870152606481013560a0870152019061198f565b60a060c085015260e08401916119c3565b03601f1981018352826113ab565b51902083519060208201928352848201528381526102c56060826113ab565b519020938061197a565b01351690805f525f60205260405f20916001600160601b03835416918282036102f457005b6001600160601b039261031b575b5082546bffffffffffffffffffffffff19169116179055005b8284541684557f3dd9cba269724793ff11df09fbd9cad1bc22ee8ae462171482c6c1a3e44de5335f80a25f610302565b5f80fd5b9193959092949650601f1982820301865287358381121561034b5784016001600160a01b0361038060208301611344565b1682526040810135603e19368390030181121561034b5781602091010190602082359201906001600160401b03831161034b57823603821361034b57838360606080936020968796838860019b01528184870152868601375f85848601015201356040830152601f801991011601019901960194019188969493919795976101da565b3461034b575f36600319011261034b5760206040517f0000000000000000000000000000000000000000000000000000000000030d408152f35b3461034b575f36600319011261034b577f00000000000000000000000000000000000000000000000000000000000000026104778161194f565b9061048560405192836113ab565b8082526104918161194f565b602083019190601f190136833780610a55575b60018111610a17575b600281116109d9575b6003811161099b575b6004811161095d575b6005811161091f575b600681116108e1575b600781116108a2575b60088111610863575b60098111610824575b600a81116107e5575b600b81116107a6575b600c8111610767575b600d8111610728575b600e81116106e9575b600f81116106aa575b6010811161066b575b6011811161062c575b601281116105ed575b60131061059a575b90604051918291602083019060208452518091526040830191905f5b818110610578575050500390f35b82516001600160a01b031684528594506020938401939092019160010161056a565b8151601310156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661028083015261054e565b634e487b7160e01b5f52603260045260245ffd5b8251601210156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610260840152610546565b8251601110156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661024084015261053d565b8251601010156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610220840152610534565b8251600f10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661020084015261052b565b8251600e10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101e0840152610522565b8251600d10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101c0840152610519565b8251600c10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101a0840152610510565b8251600b10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610180840152610507565b8251600a10156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101608401526104fe565b8251600910156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101408401526104f5565b8251600810156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101208401526104ec565b8251600710156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101008401526104e3565b8251600610156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660e08401526104da565b8251600510156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660c08401526104d1565b8251600410156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660a08401526104c8565b8251600310156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660808401526104bf565b8251600210156105d9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660608401526104b6565b8251600110156105d9577f0000000000000000000000001871c138ceab2bb36c5dbcaed0ab4bc88271fee76001600160a01b031660408401526104ad565b8251156105d9577f0000000000000000000000000f124aa8f92f47302fcba08b7349aefee853ed8d6001600160a01b031682526104a4565b60a036600319011261034b57610aa161132e565b602435906044356001600160401b03811161034b57610ac49036906004016112d1565b92906064356001600160401b03811161034b57610ae59036906004016112d1565b9290946084356001600160401b03811161034b57610b07903690600401611301565b7f000000000000000000000000c06f962a412c7af34e44d324aabf340365f29a556001600160a01b03163303610cfd57610b4091611a0c565b610b4e818689858888611ac1565b94853410610cea575f97863411610cc4575b604051936001600160fb1b03811161034b5760209686610bd79787610bb5988560051b8086833781010390207fd6383b4658ff90fe5c7fb8d1fe7a0b6cc87b7ecaf49d2305c1fed682f39548325f80a3611b64565b6040516242e0f760e61b81529788969095879586959294929160048701611903565b03917f0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a76001600160a01b03165af18015610cb957610c8a575b5081151580610c78575b610c2057005b5f918291829182916001600160a01b0316610bb8f13d15610c73573d610c45816113cc565b90610c5360405192836113ab565b81525f60203d92013e5b15610c6457005b633d2cec6f60e21b5f5260045ffd5b610c5d565b506001600160a01b0381161515610c1a565b6020813d602011610cb1575b81610ca3602093836113ab565b8101031261034b5751610c10565b3d9150610c96565b6040513d5f823e3d90fd5b9750853403348111610cd65797610b60565b634e487b7160e01b5f52601160045260245ffd5b8563131398d760e21b5f5260045260245ffd5b63cc44a19b60e01b5f523360045260245ffd5b3461034b575f36600319011261034b57610d3f610d2b6113e7565b604051918291602083526020830190611358565b0390f35b3461034b575f36600319011261034b576040517f000000000000000000000000c06f962a412c7af34e44d324aabf340365f29a556001600160a01b03168152602090f35b3461034b575f36600319011261034b576020604051633b9afb498152f35b3461034b575f36600319011261034b5760206040517f00000000000000000000000000000000000000000000000000000000000000028152f35b3461034b57602036600319011261034b576040610dfd6004356118c0565b815181516001600160601b031681526020918201516001600160a01b031691810191909152f35b3461034b575f36600319011261034b576040517f0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a76001600160a01b03168152602090f35b3461034b575f36600319011261034b57602060405163524152498152f35b606036600319011261034b5760043563ffffffff811680910361034b576044356001600160401b03811161034b57610ec2903690600401611301565b9091337f0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a76001600160a01b031603611168578015611159576024356001600160a01b031690811561114a57633b9afb49810361103d5750610f228161140e565b1561102b575081019060408183031261034b5780356001600160401b03811161034b5781019082601f8301121561034b57813591610f5f8361194f565b92610f6d60405194856113ab565b80845260208085019160051b8301019185831161034b57602001905b82821061101b575050506020810135906001600160401b03821161034b57019082601f8301121561034b57813592610fc08461194f565b92610fce60405194856113ab565b84845260208085019560051b82010191821161034b57602001935b81851061100357505061100192506352415249611cd5565b005b6020809161101087611344565b815201940193610fe9565b8135815260209182019101610f89565b6301195a3f60e11b5f5260045260245ffd5b91906110488161140e565b1561102b575082019160408184031261034b5780356001600160401b03811161034b5781019083601f8301121561034b578135916110858361194f565b9261109360405194856113ab565b80845260208085019160051b8301019186831161034b57602001905b82821061113a575050506020810135906001600160401b03821161034b57019183601f8401121561034b578235936110e68561194f565b936110f460405195866113ab565b85855260208086019660051b82010191821161034b57602001945b8186106111225750506110019350611cd5565b6020809161112f88611344565b81520195019461110f565b81358152602091820191016110af565b635d336e1d60e11b5f5260045ffd5b63c5ac559960e01b5f5260045ffd5b63188c4f9b60e01b5f523360045260245ffd5b3461034b575f36600319011261034b57610d3f60405161119c6040826113ab565b600381526219171b60e91b6020820152604051918291602083526020830190611358565b3461034b57602036600319011261034b5760206111e36111de61132e565b61140e565b6040519015158152f35b3461034b57608036600319011261034b576024356001600160401b03811161034b5761121d9036906004016112d1565b906044356001600160401b03811161034b5761123d9036906004016112d1565b60643592916001600160401b03841161034b5760209461126d611267611276963690600401611301565b90611a0c565b93600435611ac1565b604051908152f35b3461034b57602036600319011261034b576004359063ffffffff60e01b821680920361034b576020916308eacdfb60e21b81149081156112c0575b5015158152f35b6301ffc9a760e01b149050836112b9565b9181601f8401121561034b578235916001600160401b03831161034b576020808501948460051b01011161034b57565b9181601f8401121561034b578235916001600160401b03831161034b576020838186019501011161034b57565b600435906001600160a01b038216820361034b57565b35906001600160a01b038216820361034b57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b604081019081106001600160401b0382111761139757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761139757604052565b6001600160401b03811161139757601f01601f191660200190565b604051906113f66040836113ab565b600982526848797065726c616e6560b81b6020830152565b7f00000000000000000000000000000000000000000000000000000000000000029081156118ba576001600160a01b03169081156118ba577f0000000000000000000000000f124aa8f92f47302fcba08b7349aefee853ed8d6001600160a01b031682146118b35760018111156118ba577f0000000000000000000000001871c138ceab2bb36c5dbcaed0ab4bc88271fee76001600160a01b031682146118b35760028111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760038111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760048111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760058111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760068111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760078111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760088111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760098111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600a8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600b8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600c8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600d8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600e8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357600f8111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760108111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760118111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b35760128111156118ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682146118b357601310156118ae577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161490565b505f90565b5050600190565b50505f90565b5f60206040516118cf8161137c565b82815201525f525f60205260405f20604051906118eb8261137c565b546001600160601b038116825260601c602082015290565b939060809361193f9363ffffffff61193193999899168752602087015260a0604087015260a0860190611358565b908482036060860152611358565b6001600160a01b03909416910152565b6001600160401b0381116113975760051b60200190565b80518210156105d95760209160051b010190565b90359060be198136030182121561034b570190565b9035601e198236030181121561034b5701602081359101916001600160401b03821161034b578160061b3603831361034b57565b916020908281520191905f5b8181106119dc5750505090565b909192604080600192838060a01b036119f488611344565b168152602087810135908201520194019291016119cf565b60405191606083018381106001600160401b03821117611397576040525f8352602083016060815260408401915f835283019160608484031261034b5760208401356001600160401b03811161034b57840183601f8201121561034b57803590611a75826113cc565b94611a8360405196876113ab565b8286526020838301011161034b57815f926020809301838801378501015260408401356001600160a01b038116919082900361034b57525235815290565b92611af6959260209592611ad495611b64565b6040516381d2ea9560e01b815296879586959194929392919060048701611903565b03817f0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a76001600160a01b03165afa908115610cb9575f91611b35575090565b90506020813d602011611b5c575b81611b50602093836113ab565b8101031261034b575190565b3d9150611b43565b9593959492909194868603611cc657611b7c90611e27565b95835195604051936040602086015281606086015260018060fb1b03821161034b5760a0908593949260051b8091608086013783018460808201601f19608087850301016040870152520190925f5b818110611c96575050611be7925003601f1981018352826113ab565b60208201516040909201519092906001600160a01b031680611c935750604051633d1250b760e01b81526020816004817f0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a76001600160a01b03165afa908115610cb9575f91611c54575090565b90506020813d602011611c8b575b81611c6f602093836113ab565b8101031261034b57516001600160a01b038116810361034b5790565b3d9150611c62565b90565b9092509060019060209081906001600160a01b03611cb388611344565b1681520194019101918492939193611bcb565b63512509d360e11b5f5260045ffd5b92919080518015611e2057825103611cc6579291905f935b8051851015611e1957611d008582611966565b5194611d0c8184611966565b51956001600160a01b038716908115611e0a576001600160601b03611d30826118c0565b5116976001600160601b03881698808a141580611e01575b611de6575060019495969798825f525f60205260405f2091825460601c15155f14611da8575050507fc86ca07015d7e87a46a98098d36c9fc68bc3120761e5c7a2023fc6c6869e56119150602090604051908152a15b0193929190611ced565b60601b6bffffffffffffffffffffffff19161790557f2b45193f790d995b36e39c4104dd1b49df6fc851b6f6ae60f2072724735b5b435f80a3611d9e565b89908363058a3b9d60e41b5f5260045260245260445260645ffd5b50801515611d48565b50506001919293949550611d9e565b5050915050565b5050509050565b63524152498114611e5d5763ffffffff8111611e465763ffffffff1690565b6306dfcc6560e41b5f52602060045260245260445ffd5b50633b9afb499056

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.