DataVerificationHub

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/operator/DataVerificationHub.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./interface/IDataVerificationHub.sol";
import "./interface/IOperatorManager.sol";

contract DataVerificationHub is IDataVerificationHub, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
    bytes32 public constant BUSINESS_ROLE = keccak256("BUSINESS_ROLE");

    // State variables
    mapping(uint256 => PeginData) private peginDataStorage;
    IOperatorManager public operatorManager;

    // Operator PeginId Mapping
    mapping(uint256 => address) private peginIdOperatorMap;
    // OperatorSlashing Flag
    mapping(address => bool) private operatorSlashFlag;

    // Constants
    uint256 public constant BLOB_HASHES_PER_UNHAPPY_PATH = 4;
    uint256 public constant MAX_BLOB_NUMBER = 6;
    uint256 public constant MAX_WINTERNITZ_BATCH_SIZE = 13;

    // Winternitz signature constants
    uint8 private constant SIG_LEN = 20; // 20 bytes for signature

    // Custom errors
    error InvalidAddress();
    error InvalidPeginId();
    error InvalidBlobHashes();
    error InvalidSignature();
    error InvalidMessageLength();
    error InvalidSignatureLength();
    error InvalidMsgData();
    error InvalidWinternitzSignature();
    error PeginAlreadyStored();
    error BlobHashMismatch();
    error VersionedHashMismatch();
    error CommitmentNotAllowed();
    error ArrayLengthMismatch();
    error BatchSizeTooLarge();
    error NoPublicKeysFound();
    error InvalidKZGProof();
    error InvalidKZGDataLength();
    error InvalidClaimProof();
    error TargetChunkHashMismatch();

    error OperatorNotActive();
    error OperatorManagerNotSet();
    error InvalidMerkleRoot();

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address _admin) external initializer {
        __AccessControl_init();
        __ReentrancyGuard_init();

        // Grant all roles to the admin initially
        _grantRole(DEFAULT_ADMIN_ROLE, _admin);
        _grantRole(BUSINESS_ROLE, _admin);
    }

    // ===== CORE FUNCTIONS =====

    function verifyChunkData(ChunkVerificationParams calldata params) external nonReentrant onlyRole(BUSINESS_ROLE) {
        if (params.peginId == 0) revert InvalidPeginId();

        if (peginDataStorage[params.peginId].chunkDataStored) revert PeginAlreadyStored();

        // Check if operator manager is set
        if (address(operatorManager) == address(0)) revert OperatorManagerNotSet(); // TODO: implement

        // Verify KZG data length first
        // kzgData: 192 bytes: [versioned_hash(32)][z(32)][y(32)][commitment(48)][proof(48)]
        if (params.kzgData.length != 192) revert InvalidKZGDataLength();

        // Verify target chunk hash
        bytes32 targetChunkHash = abi.decode(params.kzgData[64:96], (bytes32));
        bytes32 inputmsghash = _computeMessagesHash(params.chunkVerificationData)
            & 0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

        if (targetChunkHash != inputmsghash) revert TargetChunkHashMismatch();

        // Extract versioned hash from first 32 bytes of kzgData
        bytes32 blobVersionedHash = abi.decode(params.kzgData[0:32], (bytes32));
        bytes32[] memory storedBlobHashes = peginDataStorage[params.peginId].blobHashes;
        bool versionedHashFound = false;

        for (uint256 i = 0; i < storedBlobHashes.length; i++) {
            if (blobVersionedHash == storedBlobHashes[i]) {
                versionedHashFound = true;
                break;
            }
        }
        if (!versionedHashFound) revert VersionedHashMismatch();

        // Verify KZG proof using pre-packed 192-byte data
        bool isValid = _verifyKZG(params.kzgData);
        if (!isValid) revert InvalidKZGProof();

        // Verify Winternitz signatures
        bytes32 computeChunkHash = _getAllPkHash(params.chunkVerificationData);
        // Get operator's pkroot
        bytes32 pkRoot = operatorManager.getPublicKeyRoot(params.operator);

        bytes32 merkleRoot = _getMerkleRoot(computeChunkHash, params.pkIndex, params.merkleproof);
        if (merkleRoot != pkRoot) revert InvalidMerkleRoot();

        peginDataStorage[params.peginId].chunkVerificationData = params.chunkVerificationData;
        peginDataStorage[params.peginId].chunkDataStored = true;

        emit VerifyAndProcessSingle(params.peginId);
    }

    function postClaimProofAndPostChunkBlobHash(ClaimProofDataAndBlobHashData calldata params)
        external
        nonReentrant
        onlyRole(BUSINESS_ROLE)
    {
        if (params.peginId == 0) revert InvalidPeginId();

        // Check if operator manager is set
        if (address(operatorManager) == address(0)) revert OperatorManagerNotSet();

        // Verify operator is active
        if (operatorManager.getOperatorStatus(params.operator) != IOperatorManager.OperatorStatus.Active) {
            revert OperatorNotActive();
        }

        // Verify signature
        bytes32 messageHash = keccak256(
            abi.encode(
                params.peginId,
                params.operator,
                params.claimProofParams._publicInputHash0,
                params.claimProofParams._publicInputHash1,
                params.claimProofParams.proof,
                params.claimProofParams.nativeInputs,
                params.blobStoreParams.blobHashes
            )
        );

        address recoveredSigner = ECDSA.recover(messageHash, params.signature);
        if (recoveredSigner != params.operator) {
            revert InvalidSignature();
        }

        // Verify pegin data is stored
        _postClaimProof(params.claimProofParams, params.peginId);
        // Verify blob hashes
        _storeBlobHashes(params.blobStoreParams, params.peginId);

        peginIdOperatorMap[params.peginId] = params.operator;

        emit ClaimProofAndBlobHashPosted(params.peginId);
    }

    // ===== MANAGEMENT FUNCTIONS =====
    function setOperatorManager(address _operatorManager) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_operatorManager == address(0)) revert InvalidAddress();
        operatorManager = IOperatorManager(_operatorManager);
    }

    // ===== QUERY FUNCTIONS =====

    function isPeginDataComplete(uint256 peginId) external view returns (bool) {
        PeginData memory data = peginDataStorage[peginId];
        return data.allChunkDataStored && data.chunkDataStored && data.claimProofStored;
    }

    function isPeginDataStored(uint256 peginId) external view returns (bool) {
        return peginDataStorage[peginId].chunkDataStored;
    }

    function isPeginProcessed(uint256 peginId) external view returns (bool) {
        return peginDataStorage[peginId].claimProofStored;
    }

    function getBlobHashes(uint256 peginId) external view returns (bytes32[] memory) {
        return peginDataStorage[peginId].blobHashes;
    }

    function getPeginData(uint256 peginId) external view returns (PeginData memory) {
        return peginDataStorage[peginId];
    }

    // ===== INTERNAL FUNCTIONS =====

    function _getAllCurrentBlobHashes() internal view returns (bytes32[] memory) {
        bytes32[] memory allBlobHashes = new bytes32[](MAX_BLOB_NUMBER);

        for (uint256 i = 0; i < MAX_BLOB_NUMBER; i++) {
            bytes32 blobHash;
            assembly {
                blobHash := blobhash(i)
            }
            allBlobHashes[i] = blobHash;
        }

        return allBlobHashes;
    }

    /// @notice Verifies a KZG proof for a blob data point using EIP-4844 precompile (0x0A)
    /// @param kzgData 192-byte packed data: [versioned_hash(32)][z(32)][y(32)][commitment(48)][proof(48)]
    /// @return isValid True if the proof is valid, false otherwise
    function _verifyKZG(bytes calldata kzgData) internal view returns (bool isValid) {
        // Call precompile at address 0x0A (10) directly with the packed data
        (bool success, bytes memory result) = address(0x0A).staticcall(kzgData);

        // KZG precompile returns 64 bytes on success, reverts on failure
        // Expected format: 64 bytes with specific structure (see go-ethereum PR #28383)
        isValid = success && result.length == 64;
    }

    function _getAllPkHash(ChunkVerificationData calldata chunkVerificationData) internal pure returns (bytes32) {
        // Calculate total length to initialize pks_hash array
        uint256 totalLength = chunkVerificationData.chunkData.length;

        bytes32[] memory pks_hash = new bytes32[](totalLength);
        uint256 currentIndex = 0;

        for (uint256 i = 0; i < chunkVerificationData.chunkData.length; i++) {
            bytes32 pk_hash = chunkVerificationData.chunkData[i].pkHash;
            pks_hash[currentIndex++] = pk_hash;
        }

        bytes32 computedPk = sha256(abi.encodePacked(pks_hash));
        return computedPk;
    }

    function winternitzSigChallenger(uint256 peginId, uint256 challengeIndex, bool wz_params_u8_type)
        external
        nonReentrant
        onlyRole(BUSINESS_ROLE)
    {
        PeginData memory peginData = peginDataStorage[peginId];
        WinternitzSg memory chunkSingleWzData = peginData.chunkVerificationData.chunkData[challengeIndex];

        bool challengerRes = _verifyWinternitzSignature(
            chunkSingleWzData.msgDigit, chunkSingleWzData.sig, wz_params_u8_type, chunkSingleWzData.pkHash
        );

        address operator = peginIdOperatorMap[peginId];

        operatorSlashFlag[operator] = challengerRes;

        emit WinternitzSigChallenger(peginId);
    }

    // msg: [u8;35]
    // sig: [[u8:20];35]
    function _verifyWinternitzSignature(
        uint8[] memory message,
        bytes20[] memory sigComponents,
        bool wz_params_u8_type,
        bytes32 expectHash
    ) internal pure returns (bool) {
        // default: u256 wz.checksig
        uint32 L = 35;
        uint32 L1 = 32;
        uint32 L2 = 3;
        uint8 WMAX = 255;

        // u8 wz.checksig
        if (wz_params_u8_type) {
            L1 = 1;
            L2 = 2;
            L = 3;
        }

        if (message.length != L) revert InvalidMessageLength();
        if (sigComponents.length != L) revert InvalidSignatureLength();
        // Calculate checksum
        uint32 sum = 0;
        for (uint8 i = 0; i < L1; i++) {
            sum += message[i];
        }

        uint32 checksum = 0;
        for (uint8 i = 0; i < L2; i++) {
            checksum += (uint32(message[L1 + i]) << ((L2 - 1 - i) * 8));
        }

        uint32 expect_sum = WMAX * L1;
        uint32 compute_sum = checksum + sum;

        if (compute_sum != expect_sum) revert InvalidMsgData();

        // Calculate public key components using Bitcoin's OP_HASH160
        bytes32[] memory pkComponents = new bytes32[](L);

        // Process message chunks
        for (uint8 i = 0; i < L1; i++) {
            uint8 iter = WMAX - message[i];
            pkComponents[i] = sigComponents[i];
            for (uint8 j = 0; j < iter; j++) {
                pkComponents[i] = sha256(abi.encodePacked(pkComponents[i]));
            }
        }

        // Process checksum chunks
        for (uint8 i = 0; i < L2; i++) {
            uint8 iter = WMAX - message[L1 + i];
            pkComponents[L1 + i] = sigComponents[L1 + i];
            for (uint8 j = 0; j < iter; j++) {
                pkComponents[L1 + i] = sha256(abi.encodePacked(pkComponents[L1 + i]));
            }
        }

        // Combine public key components
        bytes memory concatenated = "";
        for (uint256 i = 0; i < pkComponents.length; i++) {
            concatenated = abi.encodePacked(concatenated, pkComponents[i]);
        }
        return sha256(concatenated) == expectHash;
    }

    function _storeBlobHashes(BlobStoreParams calldata params, uint256 peginId) internal {
        if (params.blobHashes.length == 0 || params.blobHashes.length != BLOB_HASHES_PER_UNHAPPY_PATH) {
            revert InvalidBlobHashes();
        }
        if (peginDataStorage[peginId].allChunkDataStored) revert PeginAlreadyStored();

        // Verify blob hashes against current block's blobs
        bytes32[] memory currentBlobHashes = _getAllCurrentBlobHashes();
        for (uint256 i = 0; i < BLOB_HASHES_PER_UNHAPPY_PATH; i++) {
            bool found = false;
            for (uint256 j = 0; j < MAX_BLOB_NUMBER; j++) {
                if (currentBlobHashes[j] == params.blobHashes[i]) {
                    found = true;
                    break;
                }
            }
            if (!found) revert BlobHashMismatch();
        }

        // Store blob hashes
        peginDataStorage[peginId].blobHashes = params.blobHashes;
        peginDataStorage[peginId].allChunkDataStored = true;
        peginDataStorage[peginId].timestamp = block.timestamp;
    }

    function _postClaimProof(ClaimProofParams calldata params, uint256 peginId) internal {
        peginDataStorage[peginId].claimProofParams = params;
        peginDataStorage[peginId].claimProofStored = true;
    }

    function _computeMessagesHash(ChunkVerificationData calldata data) internal pure returns (bytes32) {
        bytes memory allMessages;

        // Process chunkData
        for (uint256 i = 0; i < data.chunkData.length; i++) {
            WinternitzSg memory chunkSingleData = data.chunkData[i];
            if (chunkSingleData.sig.length == 35) {
                for (uint256 j = 0; j < chunkSingleData.msgDigit.length - 3; j++) {
                    allMessages = abi.encodePacked(allMessages, chunkSingleData.msgDigit[j]);
                }
            } else {
                for (uint256 j = 0; j < chunkSingleData.msgDigit.length - 2; j++) {
                    allMessages = abi.encodePacked(allMessages, chunkSingleData.msgDigit[j]);
                }
            }
        }

        return sha256(allMessages);
    }

    function _getMerkleRoot(bytes32 leaf, uint256 index, bytes calldata siblings) internal pure returns (bytes32) {
        bytes32 ret = leaf;
        uint256 len = siblings.length / 32;
        for (uint256 i = 0; i < len; i++) {
            bytes32 s = bytes32(uint256(bytes32(siblings[i * 32:(i + 1) * 32])));
            if (index & 1 == 0) {
                ret = doubleSha(abi.encodePacked(ret, s));
            } else {
                ret = doubleSha(abi.encodePacked(s, ret));
            }
            index = index >> 1;
        }
        return ret;
    }

    function doubleSha(bytes memory buf) internal pure returns (bytes32) {
        return sha256(abi.encodePacked(sha256(buf)));
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Variant of {tryRecover} that takes a signature in calldata
     */
    function tryRecoverCalldata(
        bytes32 hash,
        bytes calldata signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, calldata slices would work here, but are
            // significantly more expensive (length check) than using calldataload in assembly.
            assembly ("memory-safe") {
                r := calldataload(signature.offset)
                s := calldataload(add(signature.offset, 0x20))
                v := byte(0, calldataload(add(signature.offset, 0x40)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Variant of {recover} that takes a signature in calldata
     */
    function recoverCalldata(bytes32 hash, bytes calldata signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecoverCalldata(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}
"
    },
    "src/operator/interface/IDataVerificationHub.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IDataVerificationHub {
    struct PeginData {
        bool allChunkDataStored;
        bool chunkDataStored;
        bool claimProofStored;
        bytes32[] blobHashes;
        ClaimProofParams claimProofParams;
        ChunkVerificationData chunkVerificationData;
        uint256 timestamp;
    }

    struct Groth16Proof {
        uint256[2] a;
        uint256[2][2] b;
        uint256[2] c;
    }

    /// @notice Struct to store native inputs for claim verification
    struct NativeInputs {
        bytes32 constanthash; // Pegin ID
        bytes32 burnTxHash; // Burn transaction hash
        bytes32 happyTakeTxHash; // Happy take transaction hash
    }

    struct ClaimProofDataAndBlobHashData {
        ClaimProofParams claimProofParams;
        BlobStoreParams blobStoreParams;
        uint256 peginId;
        address operator;
        bytes signature;
    }

    struct BlobStoreParams {
        bytes32[] blobHashes;
    }

    struct WinternitzSg {
        uint8[] msgDigit;
        bytes20[] sig;
        bytes32 pkHash;
    }

    struct ChunkVerificationData {
        WinternitzSg[] chunkData;
    }

    struct ChunkVerificationParams {
        uint256 peginId;
        address operator;
        ChunkVerificationData chunkVerificationData;
        bytes merkleproof; // pk_merkle_proof
        uint256 pkIndex;
        uint256 leafIndex; // z
        bytes kzgData; // 192 bytes: [versioned_hash(32)][z(32)][y(32)][commitment(48)][proof(48)]
    }

    struct ClaimProofParams {
        bytes32 _publicInputHash0;
        bytes32 _publicInputHash1;
        Groth16Proof proof;
        NativeInputs nativeInputs;
    }
    // Events

    event AllChunkDataBlobHashStored(uint256 indexed peginId);
    event VerifyAndProcessSingle(uint256 indexed peginId);
    event ClaimProofPosted(uint256 indexed peginId);
    event ClaimProofAndBlobHashPosted(uint256 indexed peginId);
    event WinternitzSigChallenger(uint256 indexed peginId);
    // Core functions

    function verifyChunkData(ChunkVerificationParams calldata params) external;
    function postClaimProofAndPostChunkBlobHash(ClaimProofDataAndBlobHashData calldata params) external;

    // Query functions
    function isPeginDataComplete(uint256 peginId) external view returns (bool);
    function isPeginDataStored(uint256 peginId) external view returns (bool);
    function isPeginProcessed(uint256 peginId) external view returns (bool);
    function getBlobHashes(uint256 peginId) external view returns (bytes32[] memory);
    function getPeginData(uint256 peginId) external view returns (PeginData memory);
}
"
    },
    "src/operator/interface/IOperatorManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@btc-light-client/packages/contracts/src/interfaces/BtcTxProof.sol";

interface IOperatorManager {
    enum OperatorStatus {
        Unregistered, // 0: Operator is not registered
        Active, // 1: Operator has staked tokens and is active
        PendingSlashed, // 2: Operator has been marked to be slashed
        Slashed // 3: Operator has been slashed

    }

    struct OperatorInfo {
        OperatorStatus status;
        uint256 stakedAmount;
        bytes32 pkRoot;
        uint256 registrationTime;
    }

    struct VerificationParams {
        uint256 peginId;
        uint256 minConfirmations;
        uint256 blockHeight;
        bytes assertTxHashSignature;
        TxInclusionProof txProof;
        address operator;
    }

    struct SlashParams {
        address operator;
        string secret;
        bytes secretHashSignature;
    }

    // Events
    event OperatorStaked(address indexed operator, uint256 amount);
    event OperatorUnstaked(address indexed operator, address receiver, uint256 amount);
    event OperatorSlashed(address indexed operator, uint256 slashedAmount);
    event PublicKeyRootSet(address indexed operator, bytes32 pkRoot);
    event OperatorStakedAmountUpdated(address indexed operator, uint256 newAmount);
    event RequiredStakingAmountUpdated(uint256 newAmount);
    event BridgeCommitteeUpdated(address indexed newCommittee);
    event OperatorPendingSlashed(address indexed operator);
    event DataVerificationHubUpdated(address indexed newDataVerificationHub);
    event BtcLightClientUpdated(address indexed newBtcLightClient);

    // Core functions
    function setDataVerificationHub(address _dataVerificationHub) external;
    function setBtcLightClient(address _btcLightClient) external;
    function stakeOperator(uint256 amount, bytes32 pkRoot) external;
    function unstakeOperator(address operator, address receiver) external;
    function slashOperator(SlashParams calldata params) external;
    function checkOperatorCompliance(VerificationParams calldata params) external;

    // Management functions
    function setPublicKeyRoot(address operator, bytes32 pkRoot) external;
    function updateBridgeCommittee(address newBridgeCommittee) external;
    function updateRequiredStakingAmount(uint256 newAmount) external;
    function resetOperatorStakedAmount(address operator) external;

    // View functions
    function getOperatorInfo(address operator) external view returns (OperatorInfo memory);
    function getOperatorStatus(address operator) external view returns (OperatorStatus);
    function getOperatorStakedAmount(address operator) external view returns (uint256);
    function getPublicKeyRoot(address operator) external view returns (bytes32);
    function getBridgeCommittee() external view returns (address);
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)

pragma solidity >=0.8.4;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted to signal this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

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

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}
"
    },
    "lib/btc-light-client/packages/contracts/src/interfaces/BtcTxProof.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
 * @notice Proof that a transaction (rawTx) is in a given block.
 */
struct BtcTxProof {
    /**
     * @notice 80-byte block header.
     */
    bytes blockHeader;
    /**
     * @notice Bitcoin transaction ID, equal to SHA256(SHA256(rawTx))
     */
    // This is not gas-optimized--we could omit it and compute from rawTx. But
    //s the cost is minimal, and keeping it allows better revert messages.
    bytes32 txId;
    /**
     * @notice Index of transaction within the block.
     */
    uint256 txIndex;
    /**
     * @notice Merkle proof. Concatenated sibling hashes, 32*n bytes.
     */
    bytes txMerkleProof;
    /**
     * @notice Raw transaction, HASH-SERIALIZED, no witnesses.
     */
    bytes rawTx;
}

/**
 * @notice Proof that a transaction (rawTx) is in a given block.
 */
struct TxInclusionProof {
    /**
     * @notice 80-byte block header.
     */
    bytes blockHeader;
    /**
     * @notice Index of transaction within the block.
     */
    uint256 txIndex;
    /**
     * @notice Merkle proof. Concatenated sibling hashes, 32*n bytes.
     */
    bytes txMerkleProof;
    /**
     * @notice Raw transaction, HASH-SERIALIZED, no witnesses.
     */
    bytes rawTx;
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
      "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
      "@btc-light-client/packages/contracts/=lib/btc-light-client/packages/contracts/",
      "@openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/",
      "@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/",
      "@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
      "@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/",
      "@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/",
      "solidity-bytes-utils/=lib/solidity-bytes-utils/",
      "LayerZero-v2/=lib/LayerZero-v2/",
      "btc-light-client/=lib/btc-light-client/",
      "devtools/=lib/devtools/packages/toolbox-foundry/src/",
      "ds-test/=lib/solidity-bytes-utils/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true
  }
}}

Tags:
ERC165, Proxy, Upgradeable, Factory|addr:0x328c96c1399bdfd6e22691de6eb67457ce1c5865|verified:true|block:23601876|tx:0x5686dc6205501e1f8d48917a9266f06367963642174697dd42090505c30d9edc|first_check:1760776691

Submitted on: 2025-10-18 10:38:13

Comments

Log in to comment.

No comments yet.