BridgeController

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

// Import necessary interfaces and contracts
import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
import {
  MessagingFee,
  MessagingReceipt
} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { OAppOptionsType3 } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol";
import { ReadCodecV1, EVMCallRequestV1 } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/ReadCodecV1.sol";
import { OAppRead } from "@layerzerolabs/oapp-evm/contracts/oapp/OAppRead.sol";
import { OAppCore } from "@layerzerolabs/oapp-evm/contracts/oapp/OAppCore.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

import { IBridge } from "./interfaces/IBridge.sol";
import { IController } from "./interfaces/IController.sol";

import { IMessageLibManager } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";
import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";

/**
 * @title BridgeController
 * @notice Manages the bridge to enable a immutable peering on LayerZero, while allowing for potential expansion of the
 * bridge to other chains.
 */
contract BridgeController is IController, OAppRead, OAppOptionsType3 {
  uint32 public constant DEFAULT_GAS_LIMIT = 200_000;
  uint32 private constant READ_TIME_DELAY = 6 minutes;
  uint32 private constant TIMEOUT_OFFSET = 10 minutes;
  uint8 public constant MAX_RETRY_PEER = 3;

  uint16 public constant READ_TYPE = 1;

  address public immutable BRIDGE_ADDRESS;

  /// @notice LayerZero read channel ID.
  uint32 public READ_CHANNEL;

  mapping(uint64 chainId => PeerStatus) internal peerStatusList;
  mapping(uint32 lzEID => uint64 chainId) public layerZeroToChainId;
  mapping(bytes32 guid => uint32 chainId) public messageToTargetChainId;

  constructor(address _endpoint, address _owner, address _bridgeAddress, uint32 _readChannel)
    OAppRead(_endpoint, _owner)
    Ownable(_owner)
  {
    READ_CHANNEL = _readChannel;
    BRIDGE_ADDRESS = _bridgeAddress;

    _setPeer(_readChannel, AddressCast.toBytes32(address(this)));
  }

  function setBridgePeer(
    uint64 _targetChainId,
    uint32 _eid,
    bytes32 _peer,
    address _libReceiver,
    address _libSender,
    SetConfigParam[] calldata _configRead,
    SetConfigParam[] calldata _configWrite
  ) external onlyOwner {
    PeerStatus storage status = peerStatusList[_targetChainId];

    if (status.requestTimeout != 0) {
      require(!status.succeed, PeerAlreadyExists());
      require(status.requestTimeout <= block.timestamp, PeerAlreadyExists());
      require(status.failures >= MAX_RETRY_PEER, PeerAlreadyExists());
    }

    peerStatusList[_targetChainId] = PeerStatus(_targetChainId, _eid, _peer, 1, 0, false);

    status = peerStatusList[_targetChainId];
    layerZeroToChainId[_eid] = _targetChainId;

    OAppCore(BRIDGE_ADDRESS).setPeer(_eid, _peer);

    IMessageLibManager(endpoint).setConfig(BRIDGE_ADDRESS, _libReceiver, _configRead);
    IMessageLibManager(endpoint).setConfig(BRIDGE_ADDRESS, _libSender, _configRead);
    IMessageLibManager(endpoint).setConfig(BRIDGE_ADDRESS, _libSender, _configWrite);
  }

  function validatePeer(uint32 _targetChainId, uint32 _gasLimit, bytes calldata _extraOptions)
    external
    payable
    onlyOwner
  {
    PeerStatus storage status = peerStatusList[_targetChainId];

    require(status.requestTimeout == 1, "Validation already sent");

    (uint256 callingFee, uint256 readingFee) = getLzFees(_targetChainId, _gasLimit, _extraOptions);
    require(msg.value == callingFee + readingFee, "Not enough native fee");

    IBridge(BRIDGE_ADDRESS).sendMessageAsController{ value: callingFee }(status.lzEndpointId, _gasLimit, msg.sender);
    MessagingReceipt memory receipt = this.readBridgeConnection{ value: readingFee }(
      _peerToAddress(status.peer), status.lzEndpointId, READ_TIME_DELAY, _extraOptions
    );

    messageToTargetChainId[receipt.guid] = _targetChainId;

    status.requestTimeout = uint32(block.timestamp + READ_TIME_DELAY + TIMEOUT_OFFSET);
  }

  function retryBridgePeering(uint32 _targetChainId, uint32 _gasLimit, bytes calldata _extraOptions) external payable {
    PeerStatus storage status = peerStatusList[_targetChainId];

    require(status.lzEndpointId != 0, "Peer not set");
    require(!status.succeed, "Peer already succeed");
    require(status.requestTimeout < block.timestamp, "Request still ongoing");
    require(status.failures < MAX_RETRY_PEER, "Max retry reached");

    status.failures++;
    status.requestTimeout = uint32(block.timestamp + TIMEOUT_OFFSET);

    (, uint256 readingFee) = getLzFees(_targetChainId, _gasLimit, _extraOptions);
    require(msg.value == readingFee, "Not enough native fee");

    MessagingReceipt memory receipt =
      this.readBridgeConnection{ value: readingFee }(_peerToAddress(status.peer), status.lzEndpointId, 0, _extraOptions);

    messageToTargetChainId[receipt.guid] = _targetChainId;
  }

  function getLzFees(uint64 _chainId, uint32 _gasLimit, bytes calldata _extraOptions)
    public
    view
    returns (uint256 calling_, uint256 reading_)
  {
    PeerStatus memory status = peerStatusList[_chainId];

    calling_ =
      IBridge(BRIDGE_ADDRESS).estimateFee(status.lzEndpointId, 0, _gasLimit == 0 ? DEFAULT_GAS_LIMIT : _gasLimit);
    reading_ = quoteReadFee(_peerToAddress(status.peer), status.lzEndpointId, _extraOptions).nativeFee;

    return (calling_, reading_);
  }

  function _peerToAddress(bytes32 _peer) private pure returns (address) {
    return address(uint160(uint256(_peer)));
  }

  function quoteReadFee(address _targetContractAddress, uint32 _targetEid, bytes calldata _extraOptions)
    public
    view
    returns (MessagingFee memory fee)
  {
    return _quote(
      READ_CHANNEL,
      _getCmd(_targetContractAddress, _targetEid, 0),
      combineOptions(READ_CHANNEL, READ_TYPE, _extraOptions),
      false
    );
  }

  function readBridgeConnection(
    address _targetContractAddress,
    uint32 _targetEid,
    uint64 _readDelay,
    bytes calldata _extraOptions
  ) external payable returns (MessagingReceipt memory) {
    require(msg.sender == address(this), "Only callable by BridgeController");

    bytes memory cmd = _getCmd(_targetContractAddress, _targetEid, _readDelay);

    return _lzSend(
      READ_CHANNEL,
      cmd,
      combineOptions(READ_CHANNEL, READ_TYPE, _extraOptions),
      MessagingFee(msg.value, 0),
      payable(msg.sender)
    );
  }

  function _getCmd(address _targetContractAddress, uint32 _targetEid, uint64 _readDelay)
    internal
    view
    returns (bytes memory)
  {
    bytes memory callData = abi.encodeWithSelector(IBridge.isChainLinked.selector, uint64(block.chainid));

    EVMCallRequestV1[] memory readRequests = new EVMCallRequestV1[](1);
    readRequests[0] = EVMCallRequestV1({
      appRequestLabel: 1, // Label for tracking this specific request
      targetEid: _targetEid, // WHICH chain to read from
      isBlockNum: false, // Use timestamp (not block number)
      blockNumOrTimestamp: uint64(block.timestamp + _readDelay), // WHEN to read the state (current time)
      confirmations: 15, // HOW many confirmations to wait for
      to: _targetContractAddress, // WHERE - the contract address to call
      callData: callData // WHAT - the function call to execute
     });

    return ReadCodecV1.encode(0, readRequests);
  }

  function _lzReceive(
    Origin calldata, /*_origin*/
    bytes32 _guid,
    bytes calldata _message,
    address, /*_executor*/
    bytes calldata /*_extraData*/
  ) internal override {
    bool linked = abi.decode(_message, (bool));

    if (!linked) return;

    _completeLink(messageToTargetChainId[_guid]);
  }

  function _completeLink(uint64 _chainId) internal {
    PeerStatus storage status = peerStatusList[_chainId];

    if (status.peer == bytes32(0)) {
      return;
    }

    status.succeed = true;
    emit PeerLinkingCompleted(_chainId);
  }

  function setReadChannel(uint32 _channelId, bool _active) public override onlyOwner {
    _setPeer(_channelId, _active ? AddressCast.toBytes32(address(this)) : bytes32(0));
    READ_CHANNEL = _channelId;
  }

  function getPeerStatus(uint64 _chainId) external view returns (PeerStatus memory) {
    return peerStatusList[_chainId];
  }

  function IsValidDestination(uint32 _dstEid) external view override returns (bool) {
    return peerStatusList[layerZeroToChainId[_dstEid]].succeed;
  }

  receive() external payable {
    revert("Blocked Direct Native Payment");
  }
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol": {
      "content": "// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.20;

library AddressCast {
    error AddressCast_InvalidSizeForAddress();
    error AddressCast_InvalidAddress();

    function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) {
        if (_addressBytes.length > 32) revert AddressCast_InvalidAddress();
        result = bytes32(_addressBytes);
        unchecked {
            uint256 offset = 32 - _addressBytes.length;
            result = result >> (offset * 8);
        }
    }

    function toBytes32(address _address) internal pure returns (bytes32 result) {
        result = bytes32(uint256(uint160(_address)));
    }

    function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) {
        if (_size == 0 || _size > 32) revert AddressCast_InvalidSizeForAddress();
        result = new bytes(_size);
        unchecked {
            uint256 offset = 256 - _size * 8;
            assembly {
                mstore(add(result, 32), shl(offset, _addressBytes32))
            }
        }
    }

    function toAddress(bytes32 _addressBytes32) internal pure returns (address result) {
        result = address(uint160(uint256(_addressBytes32)));
    }

    function toAddress(bytes calldata _addressBytes) internal pure returns (address result) {
        if (_addressBytes.length != 20) revert AddressCast_InvalidAddress();
        result = address(bytes20(_addressBytes));
    }
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { IMessageLibManager } from "./IMessageLibManager.sol";
import { IMessagingComposer } from "./IMessagingComposer.sol";
import { IMessagingChannel } from "./IMessagingChannel.sol";
import { IMessagingContext } from "./IMessagingContext.sol";

struct MessagingParams {
    uint32 dstEid;
    bytes32 receiver;
    bytes message;
    bytes options;
    bool payInLzToken;
}

struct MessagingReceipt {
    bytes32 guid;
    uint64 nonce;
    MessagingFee fee;
}

struct MessagingFee {
    uint256 nativeFee;
    uint256 lzTokenFee;
}

struct Origin {
    uint32 srcEid;
    bytes32 sender;
    uint64 nonce;
}

interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {
    event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);

    event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);

    event PacketDelivered(Origin origin, address receiver);

    event LzReceiveAlert(
        address indexed receiver,
        address indexed executor,
        Origin origin,
        bytes32 guid,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    event LzTokenSet(address token);

    event DelegateSet(address sender, address delegate);

    function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);

    function send(
        MessagingParams calldata _params,
        address _refundAddress
    ) external payable returns (MessagingReceipt memory);

    function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;

    function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);

    function initializable(Origin calldata _origin, address _receiver) external view returns (bool);

    function lzReceive(
        Origin calldata _origin,
        address _receiver,
        bytes32 _guid,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;

    // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order
    function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;

    function setLzToken(address _lzToken) external;

    function lzToken() external view returns (address);

    function nativeToken() external view returns (address);

    function setDelegate(address _delegate) external;
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OApp
 * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
 */
abstract contract OApp is OAppSender, OAppReceiver {
    /**
     * @dev Constructor to initialize the OApp with the provided endpoint and owner.
     * @param _endpoint The address of the LOCAL LayerZero endpoint.
     * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
     */
    constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol implementation.
     * @return receiverVersion The version of the OAppReceiver.sol implementation.
     */
    function oAppVersion()
        public
        pure
        virtual
        override(OAppSender, OAppReceiver)
        returns (uint64 senderVersion, uint64 receiverVersion)
    {
        return (SENDER_VERSION, RECEIVER_VERSION);
    }
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppOptionsType3, EnforcedOptionParam } from "../interfaces/IOAppOptionsType3.sol";

/**
 * @title OAppOptionsType3
 * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.
 */
abstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable {
    uint16 internal constant OPTION_TYPE_3 = 3;

    // @dev The "msgType" should be defined in the child contract.
    mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions;

    /**
     * @dev Sets the enforced options for specific endpoint and message type combinations.
     * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.
     * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.
     * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay
     * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().
     */
    function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner {
        _setEnforcedOptions(_enforcedOptions);
    }

    /**
     * @dev Sets the enforced options for specific endpoint and message type combinations.
     * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
     *
     * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.
     * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.
     * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay
     * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().
     */
    function _setEnforcedOptions(EnforcedOptionParam[] memory _enforcedOptions) internal virtual {
        for (uint256 i = 0; i < _enforcedOptions.length; i++) {
            // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining.
            _assertOptionsType3(_enforcedOptions[i].options);
            enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options;
        }

        emit EnforcedOptionSet(_enforcedOptions);
    }

    /**
     * @notice Combines options for a given endpoint and message type.
     * @param _eid The endpoint ID.
     * @param _msgType The OAPP message type.
     * @param _extraOptions Additional options passed by the caller.
     * @return options The combination of caller specified options AND enforced options.
     *
     * @dev If there is an enforced lzReceive option:
     * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether}
     * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function.
     * @dev This presence of duplicated options is handled off-chain in the verifier/executor.
     */
    function combineOptions(
        uint32 _eid,
        uint16 _msgType,
        bytes calldata _extraOptions
    ) public view virtual returns (bytes memory) {
        bytes memory enforced = enforcedOptions[_eid][_msgType];

        // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.
        if (enforced.length == 0) return _extraOptions;

        // No caller options, return enforced
        if (_extraOptions.length == 0) return enforced;

        // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined.
        if (_extraOptions.length >= 2) {
            _assertOptionsType3(_extraOptions);
            // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced.
            return bytes.concat(enforced, _extraOptions[2:]);
        }

        // No valid set of options was found.
        revert InvalidOptions(_extraOptions);
    }

    /**
     * @dev Internal function to assert that options are of type 3.
     * @param _options The options to be checked.
     */
    function _assertOptionsType3(bytes memory _options) internal pure virtual {
        uint16 optionsType;
        assembly {
            optionsType := mload(add(_options, 2))
        }
        if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);
    }
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/libs/ReadCodecV1.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

struct EVMCallRequestV1 {
    uint16 appRequestLabel; // Label identifying the application or type of request (can be use in lzCompute)
    uint32 targetEid; // Target endpoint ID (representing a target blockchain)
    bool isBlockNum; // True if the request = block number, false if timestamp
    uint64 blockNumOrTimestamp; // Block number or timestamp to use in the request
    uint16 confirmations; // Number of block confirmations on top of the requested block number or timestamp before the view function can be called
    address to; // Address of the target contract on the target chain
    bytes callData; // Calldata for the contract call
}

struct EVMCallComputeV1 {
    uint8 computeSetting; // Compute setting (0 = map only, 1 = reduce only, 2 = map reduce)
    uint32 targetEid; // Target endpoint ID (representing a target blockchain)
    bool isBlockNum; // True if the request = block number, false if timestamp
    uint64 blockNumOrTimestamp; // Block number or timestamp to use in the request
    uint16 confirmations; // Number of block confirmations on top of the requested block number or timestamp before the view function can be called
    address to; // Address of the target contract on the target chain
}

library ReadCodecV1 {
    using SafeCast for uint256;

    uint16 internal constant CMD_VERSION = 1;

    uint8 internal constant REQUEST_VERSION = 1;
    uint16 internal constant RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL = 1;

    uint8 internal constant COMPUTE_VERSION = 1;
    uint16 internal constant COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL = 1;

    error InvalidVersion();
    error InvalidType();

    function decode(
        bytes calldata _cmd
    )
        internal
        pure
        returns (uint16 appCmdLabel, EVMCallRequestV1[] memory evmCallRequests, EVMCallComputeV1 memory compute)
    {
        uint256 offset = 0;
        uint16 cmdVersion = uint16(bytes2(_cmd[offset:offset + 2]));
        offset += 2;
        if (cmdVersion != CMD_VERSION) revert InvalidVersion();

        appCmdLabel = uint16(bytes2(_cmd[offset:offset + 2]));
        offset += 2;

        (evmCallRequests, offset) = decodeRequestsV1(_cmd, offset);

        // decode the compute if it exists
        if (offset < _cmd.length) {
            (compute, ) = decodeEVMCallComputeV1(_cmd, offset);
        }
    }

    function decodeRequestsV1(
        bytes calldata _cmd,
        uint256 _offset
    ) internal pure returns (EVMCallRequestV1[] memory evmCallRequests, uint256 newOffset) {
        newOffset = _offset;
        uint16 requestCount = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
        newOffset += 2;

        evmCallRequests = new EVMCallRequestV1[](requestCount);
        for (uint16 i = 0; i < requestCount; i++) {
            uint8 requestVersion = uint8(_cmd[newOffset]);
            newOffset += 1;
            if (requestVersion != REQUEST_VERSION) revert InvalidVersion();

            uint16 appRequestLabel = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
            newOffset += 2;

            uint16 resolverType = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
            newOffset += 2;

            if (resolverType == RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL) {
                (EVMCallRequestV1 memory request, uint256 nextOffset) = decodeEVMCallRequestV1(
                    _cmd,
                    newOffset,
                    appRequestLabel
                );
                newOffset = nextOffset;
                evmCallRequests[i] = request;
            } else {
                revert InvalidType();
            }
        }
    }

    function decodeEVMCallRequestV1(
        bytes calldata _cmd,
        uint256 _offset,
        uint16 _appRequestLabel
    ) internal pure returns (EVMCallRequestV1 memory request, uint256 newOffset) {
        newOffset = _offset;
        request.appRequestLabel = _appRequestLabel;

        uint16 requestSize = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
        newOffset += 2;
        request.targetEid = uint32(bytes4(_cmd[newOffset:newOffset + 4]));
        newOffset += 4;
        request.isBlockNum = uint8(_cmd[newOffset]) == 1;
        newOffset += 1;
        request.blockNumOrTimestamp = uint64(bytes8(_cmd[newOffset:newOffset + 8]));
        newOffset += 8;
        request.confirmations = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
        newOffset += 2;
        request.to = address(bytes20(_cmd[newOffset:newOffset + 20]));
        newOffset += 20;
        uint16 callDataSize = requestSize - 35;
        request.callData = _cmd[newOffset:newOffset + callDataSize];
        newOffset += callDataSize;
    }

    function decodeEVMCallComputeV1(
        bytes calldata _cmd,
        uint256 _offset
    ) internal pure returns (EVMCallComputeV1 memory compute, uint256 newOffset) {
        newOffset = _offset;
        uint8 computeVersion = uint8(_cmd[newOffset]);
        newOffset += 1;
        if (computeVersion != COMPUTE_VERSION) revert InvalidVersion();
        uint16 computeType = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
        newOffset += 2;
        if (computeType != COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL) revert InvalidType();

        compute.computeSetting = uint8(_cmd[newOffset]);
        newOffset += 1;
        compute.targetEid = uint32(bytes4(_cmd[newOffset:newOffset + 4]));
        newOffset += 4;
        compute.isBlockNum = uint8(_cmd[newOffset]) == 1;
        newOffset += 1;
        compute.blockNumOrTimestamp = uint64(bytes8(_cmd[newOffset:newOffset + 8]));
        newOffset += 8;
        compute.confirmations = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
        newOffset += 2;
        compute.to = address(bytes20(_cmd[newOffset:newOffset + 20]));
        newOffset += 20;
    }

    function decodeCmdAppLabel(bytes calldata _cmd) internal pure returns (uint16) {
        uint256 offset = 0;
        uint16 cmdVersion = uint16(bytes2(_cmd[offset:offset + 2]));
        offset += 2;
        if (cmdVersion != CMD_VERSION) revert InvalidVersion();

        return uint16(bytes2(_cmd[offset:offset + 2]));
    }

    function decodeRequestV1AppRequestLabel(bytes calldata _request) internal pure returns (uint16) {
        uint256 offset = 0;
        uint8 requestVersion = uint8(_request[offset]);
        offset += 1;
        if (requestVersion != REQUEST_VERSION) revert InvalidVersion();

        return uint16(bytes2(_request[offset:offset + 2]));
    }

    function encode(
        uint16 _appCmdLabel,
        EVMCallRequestV1[] memory _evmCallRequests,
        EVMCallComputeV1 memory _evmCallCompute
    ) internal pure returns (bytes memory) {
        bytes memory cmd = encode(_appCmdLabel, _evmCallRequests);
        if (_evmCallCompute.targetEid != 0) {
            // if eid is 0, it means no compute
            cmd = appendEVMCallComputeV1(cmd, _evmCallCompute);
        }
        return cmd;
    }

    function encode(
        uint16 _appCmdLabel,
        EVMCallRequestV1[] memory _evmCallRequests
    ) internal pure returns (bytes memory) {
        bytes memory cmd = abi.encodePacked(CMD_VERSION, _appCmdLabel, _evmCallRequests.length.toUint16());
        for (uint256 i = 0; i < _evmCallRequests.length; i++) {
            cmd = appendEVMCallRequestV1(cmd, _evmCallRequests[i]);
        }
        return cmd;
    }

    // todo: optimize this with Buffer
    function appendEVMCallRequestV1(
        bytes memory _cmd,
        EVMCallRequestV1 memory _request
    ) internal pure returns (bytes memory) {
        bytes memory newCmd = abi.encodePacked(
            _cmd,
            REQUEST_VERSION,
            _request.appRequestLabel,
            RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL,
            (_request.callData.length + 35).toUint16(),
            _request.targetEid
        );
        return
            abi.encodePacked(
                newCmd,
                _request.isBlockNum,
                _request.blockNumOrTimestamp,
                _request.confirmations,
                _request.to,
                _request.callData
            );
    }

    function appendEVMCallComputeV1(
        bytes memory _cmd,
        EVMCallComputeV1 memory _compute
    ) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                _cmd,
                COMPUTE_VERSION,
                COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL,
                _compute.computeSetting,
                _compute.targetEid,
                _compute.isBlockNum,
                _compute.blockNumOrTimestamp,
                _compute.confirmations,
                _compute.to
            );
    }
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/OAppRead.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";

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

abstract contract OAppRead is OApp {
    constructor(address _endpoint, address _delegate) OApp(_endpoint, _delegate) {}

    // -------------------------------
    // Only Owner
    function setReadChannel(uint32 _channelId, bool _active) public virtual onlyOwner {
        _setPeer(_channelId, _active ? AddressCast.toBytes32(address(this)) : bytes32(0));
    }
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/OAppCore.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";

/**
 * @title OAppCore
 * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
 */
abstract contract OAppCore is IOAppCore, Ownable {
    // The LayerZero endpoint associated with the given OApp
    ILayerZeroEndpointV2 public immutable endpoint;

    // Mapping to store peers associated with corresponding endpoints
    mapping(uint32 eid => bytes32 peer) public peers;

    /**
     * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
     * @param _endpoint The address of the LOCAL Layer Zero endpoint.
     * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
     *
     * @dev The delegate typically should be set as the owner of the contract.
     */
    constructor(address _endpoint, address _delegate) {
        endpoint = ILayerZeroEndpointV2(_endpoint);

        if (_delegate == address(0)) revert InvalidDelegate();
        endpoint.setDelegate(_delegate);
    }

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
     * @dev Set this to bytes32(0) to remove the peer address.
     * @dev Peer is a bytes32 to accommodate non-evm chains.
     */
    function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
        _setPeer(_eid, _peer);
    }

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     *
     * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
     * @dev Set this to bytes32(0) to remove the peer address.
     * @dev Peer is a bytes32 to accommodate non-evm chains.
     */
    function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {
        peers[_eid] = _peer;
        emit PeerSet(_eid, _peer);
    }

    /**
     * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
     * ie. the peer is set to bytes32(0).
     * @param _eid The endpoint ID.
     * @return peer The address of the peer associated with the specified endpoint.
     */
    function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
        bytes32 peer = peers[_eid];
        if (peer == bytes32(0)) revert NoPeer(_eid);
        return peer;
    }

    /**
     * @notice Sets the delegate address for the OApp.
     * @param _delegate The address of the delegate to be set.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
     */
    function setDelegate(address _delegate) public onlyOwner {
        endpoint.setDelegate(_delegate);
    }
}
"
    },
    "node_modules/@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
"
    },
    "src/interfaces/IBridge.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IBridge {
  error MissingOneTokenAddress();
  error InvalidFunctionUseOtherSimilarName();
  error InvalidDestinationBridge();
  error InvalidReceiver();
  error NotEnoughNativeToPayLayerZeroFee();
  error OnlySafeGuard();

  event OneBridged(uint64 indexed sourceChainid, address indexed to, uint256 amount);

  function isChainLinked(uint64 _chainId) external view returns (bool);

  function sendMessageAsController(uint32 _eid, uint32 _gasLimit, address _refundTo) external payable;

  function estimateFee(uint32 _dstEid, uint256 _amount, uint32 _lzGasLimit) external view returns (uint256);
}
"
    },
    "src/interfaces/IController.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0;

interface IController {
  struct PeerStatus {
    uint64 chainId;
    uint32 lzEndpointId;
    bytes32 peer;
    uint32 requestTimeout;
    uint8 failures;
    bool succeed;
  }

  error PeerAlreadyExists();

  event PeerLinkingCompleted(uint64 _toChainId);

  function IsValidDestination(uint32 _dstEid) external view returns (bool);
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

struct SetConfigParam {
    uint32 eid;
    uint32 configType;
    bytes config;
}

interface IMessageLibManager {
    struct Timeout {
        address lib;
        uint256 expiry;
    }

    event LibraryRegistered(address newLib);
    event DefaultSendLibrarySet(uint32 eid, address newLib);
    event DefaultReceiveLibrarySet(uint32 eid, address newLib);
    event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);
    event SendLibrarySet(address sender, uint32 eid, address newLib);
    event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);
    event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);

    function registerLibrary(address _lib) external;

    function isRegisteredLibrary(address _lib) external view returns (bool);

    function getRegisteredLibraries() external view returns (address[] memory);

    function setDefaultSendLibrary(uint32 _eid, address _newLib) external;

    function defaultSendLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external;

    function defaultReceiveLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;

    function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);

    function isSupportedEid(uint32 _eid) external view returns (bool);

    function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);

    /// ------------------- OApp interfaces -------------------
    function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;

    function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);

    function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);

    function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;

    function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);

    function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external;

    function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);

    function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;

    function getConfig(
        address _oapp,
        address _lib,
        uint32 _eid,
        uint32 _configType
    ) external view returns (bytes memory config);
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingComposer.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingComposer {
    event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);
    event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);
    event LzComposeAlert(
        address indexed from,
        address indexed to,
        address indexed executor,
        bytes32 guid,
        uint16 index,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    function composeQueue(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index
    ) external view returns (bytes32 messageHash);

    function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;

    function lzCompose(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingChannel.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingChannel {
    event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);
    event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);
    event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);

    function eid() external view returns (uint32);

    // this is an emergency function if a message cannot be verified for some reasons
    // required to provide _nextNonce to avoid race condition
    function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;

    function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);

    function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);

    function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);

    function inboundPayloadHash(
        address _receiver,
        uint32 _srcEid,
        bytes32 _sender,
        uint64 _nonce
    ) external view returns (bytes32);

    function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);
}
"
    },
    "node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingContext.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingContext {
    function isSendingMessage() external view returns (bool);

    function getSendContext() external view returns (uint32 dstEid, address sender);
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppSender
 * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
 */
abstract contract OAppSender is OAppCore {
    using SafeERC20 for IERC20;

    // Custom error messages
    error NotEnoughNative(uint256 msgValue);
    error LzTokenUnavailable();

    // @dev The version of the OAppSender implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant SENDER_VERSION = 1;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
     * ie. this is a SEND only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (SENDER_VERSION, 0);
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
     * @return fee The calculated MessagingFee for the message.
     *      - nativeFee: The native fee for the message.
     *      - lzTokenFee: The LZ token fee for the message.
     */
    function _quote(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        bool _payInLzToken
    ) internal view virtual returns (MessagingFee memory fee) {
        return
            endpoint.quote(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
                address(this)
            );
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _fee The calculated LayerZero fee for the message.
     *      - nativeFee: The native fee.
     *      - lzTokenFee: The lzToken fee.
     * @param _refundAddress The address to receive any excess fee values sent to the endpoint.
     * @return receipt The receipt for the sent message.
     *      - guid: The unique identifier for the sent message.
     *      - nonce: The nonce of the sent message.
     *      - fee: The LayerZero fee incurred for the message.
     */
    function _lzSend(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        MessagingFee memory _fee,
        address _refundAddress
    ) internal virtual returns (MessagingReceipt memory receipt) {
        // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
        uint256 messageValue = _payNative(_fee.nativeFee);
        if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);

        return
            // solhint-disable-next-line check-send-result
            endpoint.send{ value: messageValue }(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
                _refundAddress
            );
    }

    /**
     * @dev Internal function to pay the native fee associated with the message.
     * @param _nativeFee The native fee to be paid.
     * @return nativeFee The amount of native currency paid.
     *
     * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
     * this will need to be overridden because msg.value would contain multiple lzFees.
     * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
     * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
     * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
     */
    function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
        if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
        return _nativeFee;
    }

    /**
     * @dev Internal function to pay the LZ token fee associated with the message.
     * @param _lzTokenFee The LZ token fee to be paid.
     *
     * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
     * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
     */
    function _payLzToken(uint256 _lzTokenFee) internal virtual {
        // @dev Cannot cache the token because it is not immutable in the endpoint.
        address lzToken = endpoint.lzToken();
        if (lzToken == address(0)) revert LzTokenUnavailable();

        // Pay LZ token fee by sending tokens to the endpoint.
        IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
    }
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/OAppReceiver.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppReceiver
 * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
 */
abstract contract OAppReceiver is IOAppReceiver, OAppCore {
    // Custom error message for when the caller is not the registered endpoint/
    error OnlyEndpoint(address addr);

    // @dev The version of the OAppReceiver implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant RECEIVER_VERSION = 2;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
     * ie. this is a RECEIVE only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (0, RECEIVER_VERSION);
    }

    /**
     * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
     * @dev _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @dev _message The lzReceive payload.
     * @param _sender The sender address.
     * @return isSender Is a valid sender.
     *
     * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer.
     * @dev The default sender IS the OAppReceiver implementer.
     */
    function isComposeMsgSender(
        Origin calldata /*_origin*/,
        bytes calldata /*_message*/,
        address _sender
    ) public view virtual returns (bool) {
        return _sender == address(this);
    }

    /**
     * @notice Checks if the path initialization is allowed based on the provided origin.
     * @param origin The origin information containing the source endpoint and sender address.
     * @return Whether the path has been initialized.
     *
     * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
     * @dev This defaults to assuming if a peer has been set, its initialized.
     * Can be overridden by the OApp if there is other logic to determine this.
     */
    function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
        return peers[origin.srcEid] == origin.sender;
    }

    /**
     * @notice Retrieves the next nonce for a given source endpoint and sender address.
     * @dev _srcEid The source endpoint ID.
     * @dev _sender The sender address.
     * @return nonce The next nonce.
     *
     * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
     * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
     * @dev This is also enforced by the OApp.
     * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
     */
    function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {
        return 0;
    }

    /**
     * @dev Entry point for receiving messages or packets from the endpoint.
     * @param _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @param _guid The unique identifier for the received LayerZero message.
     * @param _message The payload of the received message.
     * @param _executor The address of the executor for the received message.
     * @param _extraData Additional arbitrary data provided by the corresponding executor.
     *
     * @dev Entry point for receiving msg/packet from the LayerZero endpoint.
     */
    function lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) public payable virtual {
        // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
        if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);

        // Ensure that the sender matches the expected peer for the source endpoint.
        if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);

        // Call the internal OApp implementation of lzReceive.
        _lzReceive(_origin, _guid, _message, _executor, _extraData);
    }

    /**
     * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) internal virtual;
}
"
    },
    "node_modules/@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppOptionsType3.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @dev Struct representing enforced option parameters.
 */
struct EnforcedOptionParam {
    uint32 eid; // Endpoint ID
    uint16 msgType; // Message Type
    bytes options; // Additional options
}

/**
 * @title IOAppOptionsType3
 * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options.
 */
interface IOAppOptionsType3 {
    // Custom error message for invalid options
    error InvalidOptions(bytes options);

    // Event emitted when enforced options are set
    event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions);

    /**
     * @notice Sets enforced options for specific endpoint and message type combinations.
     * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
     */
    function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;

    /**
     * @notice Combines options for a given endpoint and message type.
     * @param _eid The endpoint ID.
     * @param _msgType The OApp message type.
     * @param _extraOptions Additional options passed by the caller.
     * @return options The combination of caller specified options AND enforced options.
     */
    function combineOptions(
        uint32 _eid,
        uint16 _msgType,
        bytes calldata _extraOptions
    ) external view returns (bytes memory options);
}
"
    },
    "node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidi

Tags:
ERC20, ERC165, Multisig, Burnable, Upgradeable, Multi-Signature, Factory|addr:0x29a64a10d3d429e9e8a6e9428804b3f0b5ab40b3|verified:true|block:23391725|tx:0x642ce8b7b63ffcadacc7556397768f9a418c4ce3bb188dcdb965e144b3b3f8d8|first_check:1758272613

Submitted on: 2025-09-19 11:03:35

Comments

Log in to comment.

No comments yet.