FRAX Price: $0.84 (+4.42%)

Contract

0xfacefeed69e0eb9dB6Ad8Cb0883fC45Df7561Dc2

Overview

FRAX Balance | FXTL Balance

0 FRAX | 162 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Amount:Between 1-1M
Reset Filter

Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction and 4 Token Transfers found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
291925102025-12-08 12:08:5152 days ago1765195731  Contract Creation0 FRAX

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LayerZero Block Relay

Compiler Version
vyper:0.4.3

Optimization Enabled:
Yes

Other Settings:
paris EvmVersion, None license

Contract Source Code (Vyper Json-Input format)

File 1 of 6 : LZBlockRelay.vy
# pragma version 0.4.3
# pragma optimize gas
# pragma nonreentrancy on

"""
@title LayerZero Block Relay

@notice Layer Zero messenger for block hashes.
This contract should be deployed on multiple chains along with BlockOracle and MainnetBlockView.

Main functionality includes requesting lzRead of recent ethereum mainnet blockhashes from MainnetBlockView.
Upon receiving LZ message in lzReceive, the blockhash is committed to the BlockOracle, and if it was a read request,
the contract will attempt to broadcast the blockhash to other chains.

If chain is read-enabled, it will be able to read the blockhash from MainnetBlockView and broadcast it to other chains.
If chain is not read-enabled, it will only be able to receive blockhashes from other chains.

@license Copyright (c) Curve.Fi, 2025 - all rights reserved

@author curve.fi

@custom:security [email protected]

"""


################################################################
#                           INTERFACES                         #
################################################################

interface IBlockOracle:
    def commit_block(block_number: uint256, block_hash: bytes32) -> bool: nonpayable
    def last_confirmed_block_number() -> uint256: view
    def get_block_hash(block_number: uint256) -> bytes32: view


################################################################
#                            MODULES                           #
################################################################

# Import ownership management
from snekmate.auth import ownable

initializes: ownable
exports: (
    ownable.owner,
    ownable.transfer_ownership,
    ownable.renounce_ownership,
)

# Import LayerZero module for cross-chain messaging
from ..modules.oapp_vyper.src import OApp  # main module
from ..modules.oapp_vyper.src import OptionsBuilder  # module for creating options
from ..modules.oapp_vyper.src import ReadCmdCodecV1  # module for reading commands

initializes: OApp[ownable := ownable]

exports: (
    OApp.endpoint,
    OApp.peers,
    OApp.setPeer,
    OApp.setDelegate,
    OApp.isComposeMsgSender,
    OApp.allowInitializePath,
    OApp.nextNonce,
)

################################################################
#                           CONSTANTS                          #
################################################################

MAX_N_BROADCAST: constant(uint256) = 32
GET_BLOCKHASH_SELECTOR: constant(Bytes[4]) = method_id("get_blockhash(uint256,bool)")
READ_RETURN_SIZE: constant(uint32) = 64

################################################################
#                            STORAGE                           #
################################################################

# Read configuration
read_enabled: public(bool)
read_channel: public(uint32)
mainnet_eid: public(uint32)
mainnet_block_view: public(address)

# Block oracle
block_oracle: public(IBlockOracle)

# Structs for cached broadcast info
struct BroadcastTarget:
    eid: uint32
    fee: uint256

struct BroadcastData:
    targets: DynArray[BroadcastTarget, MAX_N_BROADCAST]
    gas_limit: uint128
    requester: address

# Broadcast targets
broadcast_data: HashMap[bytes32, BroadcastData]  # guid -> (targets: (eid, fee), gas_limit, requester)

# lzRead received blocks
received_blocks: HashMap[uint256, bytes32]  # block_number -> block_hash

################################################################
#                            EVENTS                            #
################################################################

event BlockHashBroadcast:
    block_number: indexed(uint256)
    block_hash: indexed(bytes32)
    targets: DynArray[BroadcastTarget, MAX_N_BROADCAST]


################################################################
#                          CONSTRUCTOR                         #
################################################################

@deploy
def __init__(
    _endpoint: address,
):
    """
    @notice Initialize contract with core settings
    @dev Can only be called once, assumes caller is owner, sets as delegate
    @param _endpoint LayerZero endpoint address
    @param _lz_receive_gas_limit Gas limit for lzReceive
    """
    ownable.__init__()
    ownable._transfer_ownership(tx.origin)  # origin to enable createx deployment

    OApp.__init__(_endpoint, tx.origin)  # origin also set as delegate

################################################################
#                      OWNER FUNCTIONS                         #
################################################################

@external
def set_read_config(
    _is_enabled: bool, _read_channel: uint32, _mainnet_eid: uint32, _mainnet_view: address
):
    """
    @notice Configure read functionality
    @param _is_enabled Whether this contract can initiate reads
    @param _read_channel LZ read channel ID
    @param _mainnet_eid Mainnet endpoint ID
    @param _mainnet_view MainnetBlockView contract address
    """
    ownable._check_owner()

    assert _read_channel > OApp.READ_CHANNEL_THRESHOLD, "Invalid read channel"

    assert (_is_enabled and _mainnet_eid != 0 and _mainnet_view != empty(address)) or (
        not _is_enabled and _mainnet_eid == 0 and _mainnet_view == empty(address)
    ), "Invalid read config"

    # Clean up old peer if switching channels while read is enabled
    # This prevents leaving stale peer mappings when changing read channels
    if self.read_enabled and self.read_channel != _read_channel:
        OApp._setPeer(self.read_channel, convert(empty(address), bytes32))

    self.read_enabled = _is_enabled
    self.read_channel = _read_channel
    self.mainnet_eid = _mainnet_eid
    self.mainnet_block_view = _mainnet_view

    peer: bytes32 = convert(self, bytes32) if _is_enabled else convert(empty(address), bytes32)
    OApp._setPeer(_read_channel, peer)


@external
def set_peers(_eids: DynArray[uint32, MAX_N_BROADCAST], _peers: DynArray[address, MAX_N_BROADCAST]):
    """
    @notice Set peers for a corresponding endpoints. Batched version of OApp.setPeer that accept address (EVM only).
    @param _eids The endpoint IDs.
    @param _peers Addresses of the peers to be associated with the corresponding endpoints.
    """
    ownable._check_owner()

    assert len(_eids) == len(_peers), "Invalid peer arrays"
    for i: uint256 in range(0, len(_eids), bound=MAX_N_BROADCAST):
        OApp._setPeer(_eids[i], convert(_peers[i], bytes32))


@external
def set_block_oracle(_oracle: address):
    """
    @notice Set the block oracle address
    @param _oracle Block oracle address
    """
    ownable._check_owner()

    self.block_oracle = IBlockOracle(_oracle)


@external
def withdraw_eth(_amount: uint256):
    """
    @notice Withdraw ETH from contract
    @dev ETH can be accumulated from LZ refunds
    @param _amount Amount to withdraw
    """
    ownable._check_owner()

    assert self.balance >= _amount, "Insufficient balance"
    send(msg.sender, _amount)


################################################################
#                     INTERNAL FUNCTIONS                       #
################################################################


@internal
def _commit_block(_block_number: uint256, _block_hash: bytes32):
    """
    @notice Commit block hash to oracle
    """
    assert self.block_oracle != empty(IBlockOracle), "Oracle not configured"
    extcall self.block_oracle.commit_block(_block_number, _block_hash)


@internal
@view
def _prepare_read_request(_block_number: uint256) -> Bytes[OApp.MAX_MESSAGE_SIZE]:
    """
    @notice Prepare complete read request message for MainnetBlockView
    @param _block_number Block number to request (0 for latest)
    @return Prepared LayerZero message bytes
    """
    # 1. Build calldata
    calldata: Bytes[ReadCmdCodecV1.MAX_CALLDATA_SIZE] = abi_encode(
        _block_number, True, method_id=GET_BLOCKHASH_SELECTOR
    )

    # 2. Prepare ReadCmdRequestV1 struct
    request: ReadCmdCodecV1.EVMCallRequestV1 = ReadCmdCodecV1.EVMCallRequestV1(
        appRequestLabel=1,
        targetEid=self.mainnet_eid,
        isBlockNum=False,
        blockNumOrTimestamp=convert(block.timestamp, uint64),
        confirmations=1, # low confirmations because MainnetBlockView returns aged blockhashes
        to=self.mainnet_block_view,
        callData=calldata,
    )

    # 3. Encode request
    encoded_message: Bytes[ReadCmdCodecV1.MAX_MESSAGE_SIZE] = ReadCmdCodecV1.encode(
        1, [request]
    )  # 1 is _appCmdLabel
    # dev: ReadCmdCodecV1.MAX_MESSAGE_SIZE is opposed to OApp.MAX_MESSAGE_SIZE intentionally so code fails if they are not equal

    return encoded_message


@internal
@payable
def _request_block_hash(
    _block_number: uint256,
    _target_eids: DynArray[uint32, MAX_N_BROADCAST],
    _target_fees: DynArray[uint256, MAX_N_BROADCAST],
    _lz_receive_gas_limit: uint128,
    _read_gas_limit: uint128,
):
    """
    @notice Internal function to request block hash from mainnet and broadcast to specified targets
    @param _block_number Block number to request
    @param _target_eids Target EIDs to broadcast to
    @param _target_fees Target fees to pay per broadcast
    @param _lz_receive_gas_limit Gas limit for lzReceive
    @param _read_gas_limit Gas limit for read operation
    """

    # Store target EIDs and fees for lzReceive
    cached_targets: DynArray[BroadcastTarget, MAX_N_BROADCAST] = []
    sum_target_fees: uint256 = 0
    for i: uint256 in range(0, len(_target_eids), bound=MAX_N_BROADCAST):
        cached_targets.append(BroadcastTarget(eid=_target_eids[i], fee=_target_fees[i]))
        sum_target_fees += _target_fees[i]

    assert sum_target_fees <= msg.value, "Insufficient value" # dev: check is here because we sum here

    message: Bytes[OApp.MAX_MESSAGE_SIZE] = self._prepare_read_request(_block_number)

    # Create options using OptionsBuilder module
    options: Bytes[OptionsBuilder.MAX_OPTIONS_TOTAL_SIZE] = OptionsBuilder.newOptions()
    options = OptionsBuilder.addExecutorLzReadOption(
        options, _read_gas_limit, READ_RETURN_SIZE, convert(sum_target_fees, uint128)
    )

    # Send message
    fees: OApp.MessagingFee = OApp.MessagingFee(nativeFee=msg.value, lzTokenFee=0)
    # Fees = read fee + broadcast fees (value of read return message)
    receipt: OApp.MessagingReceipt = OApp._lzSend(
        self.read_channel, message, options, fees, msg.sender # dev: refund excess fee to sender
    )

    # Store targets for lzReceive using receipt.guid as key
    self.broadcast_data[receipt.guid] = BroadcastData(
        targets=cached_targets,
        gas_limit=_lz_receive_gas_limit,
        requester=msg.sender
    )


@internal
def _broadcast_block(
    _block_number: uint256,
    _block_hash: bytes32,
    _broadcast_data: BroadcastData,
):
    """
    @notice Internal function to broadcast block hash to multiple chains
    @param _block_number Block number to broadcast
    @param _block_hash Block hash to broadcast
    @param _broadcast_data Data for broadcasting
    """
    message: Bytes[OApp.MAX_MESSAGE_SIZE] = abi_encode(_block_number, _block_hash)

    # Сreate options using OptionsBuilder module (same options for all targets)
    options: Bytes[OptionsBuilder.MAX_OPTIONS_TOTAL_SIZE] = OptionsBuilder.newOptions()
    options = OptionsBuilder.addExecutorLzReceiveOption(
        options, _broadcast_data.gas_limit, 0
    )

    for target: BroadcastTarget in _broadcast_data.targets:
        # Skip if peer is not set
        if OApp.peers[target.eid] == empty(bytes32):
            continue

        # Send message
        fees: OApp.MessagingFee = OApp.MessagingFee(nativeFee=target.fee, lzTokenFee=0)
        OApp._lzSend(target.eid, message, options, fees, _broadcast_data.requester)

    log BlockHashBroadcast(
        block_number=_block_number,
        block_hash=_block_hash,
        targets=_broadcast_data.targets,
    )


################################################################
#                     EXTERNAL FUNCTIONS                       #
################################################################

@external
@payable
@reentrant
def __default__():
    """
    @notice Default function to receive ETH
    @dev This is needed to receive refunds from LayerZero
    """
    pass


@external
@view
def quote_read_fee(
    _read_gas_limit: uint128,
    _value: uint128,
) -> uint256:
    """
    @notice Quote fee for reading block hash from mainnet
    @param _read_gas_limit Gas to be provided in return message
    @param _value Value to be provided in return message
    @return Fee in native tokens required for the read operation
    """
    assert self.read_enabled, "Read not enabled - call set_read_config"

    message: Bytes[OApp.MAX_MESSAGE_SIZE] = self._prepare_read_request(0) # dev: 0 for latest block

    # Create options using OptionsBuilder module
    options: Bytes[OptionsBuilder.MAX_OPTIONS_TOTAL_SIZE] = OptionsBuilder.newOptions()
    options = OptionsBuilder.addExecutorLzReadOption(
        options, _read_gas_limit, READ_RETURN_SIZE, _value
    )

    return OApp._quote(
        self.read_channel,
        message,
        options,
        False,
    ).nativeFee


@external
@view
def quote_broadcast_fees(
    _target_eids: DynArray[uint32, MAX_N_BROADCAST],
    _lz_receive_gas_limit: uint128,
) -> DynArray[uint256, MAX_N_BROADCAST]:
    """
    @notice Quote fees for broadcasting block hash to specified targets
    @param _target_eids List of chain IDs to broadcast to
    @param _lz_receive_gas_limit Gas limit for lzReceive
    @return Array of fees per target chain (0 if target not configured)
    """
    # Prepare dummy broadcast message (uint256 number, bytes32 hash)
    message: Bytes[OApp.MAX_MESSAGE_SIZE] = abi_encode(empty(uint256), empty(bytes32))

    # Prepare array of fees per chain
    fees: DynArray[uint256, MAX_N_BROADCAST] = []

    # Prepare options (same for all targets)
    options: Bytes[OptionsBuilder.MAX_OPTIONS_TOTAL_SIZE] = OptionsBuilder.newOptions()
    options = OptionsBuilder.addExecutorLzReceiveOption(options, _lz_receive_gas_limit, 0)

    # Cycle through targets
    for eid: uint32 in _target_eids:
        target: bytes32 = OApp.peers[eid]  # Use peers directly
        if target == empty(bytes32):
            fees.append(0)
            continue

        # Get fee for target EID and append to array
        fees.append(OApp._quote(eid, message, options, False).nativeFee)

    return fees


@external
@payable
def request_block_hash(
    _target_eids: DynArray[uint32, MAX_N_BROADCAST],
    _target_fees: DynArray[uint256, MAX_N_BROADCAST],
    _lz_receive_gas_limit: uint128,
    _read_gas_limit: uint128,
    _block_number: uint256 = 0,
):
    """
    @notice Request block hash from mainnet and broadcast to specified targets
    @param _target_eids List of chain IDs to broadcast to
    @param _target_fees List of fees per chain (must match _target_eids length)
    @param _lz_receive_gas_limit Gas limit for lzReceive (same for all targets)
    @param _read_gas_limit Gas limit for read operation
    @param _block_number Optional block number (0 means latest)
    @dev User must ensure msg.value is sufficient:
         - must cover read fee (quote_read_fee)
         - must cover broadcast fees (quote_broadcast_fees)
    """

    assert self.read_enabled, "Read not enabled"
    assert len(_target_eids) == len(_target_fees), "Length mismatch"

    self._request_block_hash(
        _block_number,
        _target_eids,
        _target_fees,
        _lz_receive_gas_limit,
        _read_gas_limit,
    )


@external
@payable
def broadcast_latest_block(
    _target_eids: DynArray[uint32, MAX_N_BROADCAST],
    _target_fees: DynArray[uint256, MAX_N_BROADCAST],
    _lz_receive_gas_limit: uint128,
):
    """
    @notice Broadcast latest confirmed block hash to specified chains
    @param _target_eids List of chain IDs to broadcast to
    @param _target_fees List of fees per chain (must match _target_eids length)
    @param _lz_receive_gas_limit Gas limit for lzReceive (same for all targets)
    @dev Only broadcast what was received via lzRead to prevent potentially malicious hashes from other sources
    """

    assert self.read_enabled, "Can only broadcast from read-enabled chains"
    assert self.block_oracle != empty(IBlockOracle), "Oracle not configured"
    assert len(_target_eids) == len(_target_fees), "Length mismatch"

    # Get latest block from oracle
    block_number: uint256 = staticcall self.block_oracle.last_confirmed_block_number()
    block_hash: bytes32 = staticcall self.block_oracle.get_block_hash(block_number)
    assert block_hash != empty(bytes32), "No confirmed blocks"

    # Only broadcast if this block was received via lzRead
    assert self.received_blocks[block_number] == block_hash, "Unknown source"

    # Prepare broadcast targets
    broadcast_targets: DynArray[BroadcastTarget, MAX_N_BROADCAST] = []
    sum_target_fees: uint256 = 0
    for i: uint256 in range(0, len(_target_eids), bound=MAX_N_BROADCAST):
        broadcast_targets.append(BroadcastTarget(eid=_target_eids[i], fee=_target_fees[i]))
        sum_target_fees += _target_fees[i]

    assert sum_target_fees <= msg.value, "Insufficient message value"

    self._broadcast_block(
        block_number,
        block_hash,
        BroadcastData(targets=broadcast_targets, gas_limit=_lz_receive_gas_limit, requester=msg.sender),
    )


@payable
@external
def lzReceive(
    _origin: OApp.Origin,
    _guid: bytes32,
    _message: Bytes[OApp.MAX_MESSAGE_SIZE],
    _executor: address,
    _extraData: Bytes[OApp.MAX_EXTRA_DATA_SIZE],
):
    """
    @notice Handle messages: read responses, and regular messages
    @dev Two types of messages:
         1. Read responses (from read channel)
         2. Regular messages (block hash broadcasts from other chains)
    @param _origin Origin information containing srcEid, sender, and nonce
    @param _guid Global unique identifier for the message
    @param _message The encoded message payload containing block number and hash
    @param _executor Address of the executor for the message
    @param _extraData Additional data passed by the executor
    """
    # Verify message source
    OApp._lzReceive(_origin, _guid, _message, _executor, _extraData)

    if _origin.srcEid == self.read_channel:
        # Only handle read response if read is enabled
        assert self.read_enabled, "Read not enabled"
        # Decode block hash and number from response
        block_number: uint256 = 0
        block_hash: bytes32 = empty(bytes32)
        block_number, block_hash = abi_decode(_message, (uint256, bytes32))
        if block_hash == empty(bytes32):
            return  # Invalid response

        # Store received block hash
        self.received_blocks[block_number] = block_hash

        # Commit block hash to oracle
        self._commit_block(block_number, block_hash)

        broadcast_data: BroadcastData = self.broadcast_data[_guid]

        if len(broadcast_data.targets) > 0:
            # Verify that attached value covers requested broadcast fees
            total_fee: uint256 = 0
            for target: BroadcastTarget in broadcast_data.targets:
                total_fee += target.fee
            assert msg.value >= total_fee, "Insufficient msg.value"

            # Perform broadcast
            self._broadcast_block(
                block_number,
                block_hash,
                broadcast_data,
            )
    else:
        # Regular message - decode and commit block hash
        block_number: uint256 = 0
        block_hash: bytes32 = empty(bytes32)
        block_number, block_hash = abi_decode(_message, (uint256, bytes32))
        self._commit_block(block_number, block_hash)

File 2 of 6 : ownable.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Owner-Based Access Control Functions
@custom:contract-name ownable
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions can be used to implement a basic access
        control mechanism, where there is an account (an owner)
        that can be granted exclusive access to specific functions.
        By default, the owner account will be the one that deploys
        the contract. This can later be changed with `transfer_ownership`.
        An exemplary integration can be found in the ERC-20 implementation here:
        https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/tokens/erc20.vy.
        The implementation is inspired by OpenZeppelin's implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol.
"""


# @dev Returns the address of the current owner.
# @notice If you declare a variable as `public`,
# Vyper automatically generates an `external`
# getter function for the variable.
owner: public(address)


# @dev Emitted when the ownership is transferred
# from `previous_owner` to `new_owner`.
event OwnershipTransferred:
    previous_owner: indexed(address)
    new_owner: indexed(address)


@deploy
@payable
def __init__():
    """
    @dev To omit the opcodes for checking the `msg.value`
         in the creation-time EVM bytecode, the constructor
         is declared as `payable`.
    @notice The `owner` role will be assigned to
            the `msg.sender`.
    """
    self._transfer_ownership(msg.sender)


@external
def transfer_ownership(new_owner: address):
    """
    @dev Transfers the ownership of the contract
         to a new account `new_owner`.
    @notice Note that this function can only be
            called by the current `owner`. Also,
            the `new_owner` cannot be the zero address.
    @param new_owner The 20-byte address of the new owner.
    """
    self._check_owner()
    assert new_owner != empty(address), "ownable: new owner is the zero address"
    self._transfer_ownership(new_owner)


@external
def renounce_ownership():
    """
    @dev Leaves the contract without an owner.
    @notice Renouncing ownership will leave the
            contract without an owner, thereby
            removing any functionality that is
            only available to the owner.
    """
    self._check_owner()
    self._transfer_ownership(empty(address))


@internal
def _check_owner():
    """
    @dev Throws if the sender is not the owner.
    """
    assert msg.sender == self.owner, "ownable: caller is not the owner"


@internal
def _transfer_ownership(new_owner: address):
    """
    @dev Transfers the ownership of the contract
         to a new account `new_owner`.
    @notice This is an `internal` function without
            access restriction.
    @param new_owner The 20-byte address of the new owner.
    """
    old_owner: address = self.owner
    self.owner = new_owner
    log OwnershipTransferred(previous_owner=old_owner, new_owner=new_owner)

File 3 of 6 : VyperConstants.vy
# pragma version 0.4.3

"""
@title LayerZero Vyper Constants
@license Copyright (c) Curve.Fi, 2025 - all rights reserved
@notice Vyper does not allow truly dynamic byte arrays, and requires constants to cap the size of the array.
This file contains such constants for the LayerZero OApp.
@dev IMPORTANT: Tune these down as much as possible according to intended use case to save on gas.

@author curve.fi
@custom:security [email protected]
"""

# dev: THESE CONSTANTS WERE TUNED DOWN TO THE LIMITS OF LZBLOCKRELAY FUNCTIONALITY

# Options size limits
MAX_OPTIONS_TOTAL_SIZE: constant(uint256) = 54
MAX_OPTION_SINGLE_SIZE: constant(uint256) = 48

# Message size limits
MAX_MESSAGE_SIZE: constant(uint256) = 183
MAX_EXTRA_DATA_SIZE: constant(uint256) = 64

# ReadCmdCodecV1 limits
MAX_CALLDATA_SIZE: constant(uint256) = 68

File 4 of 6 : OApp.vy
# pragma version 0.4.3

"""
@title OApp (LayerZero V2 OApp Standard)

@notice Vyper implementation of LayerZero OApp standard.
This contract implements the OApp interface for cross-chain messaging via LayerZero.
It combines the functionality of OAppCore, OAppSender, OAppReceiver, and OAppRead
into a single contract.

To use _quote/_lzSend, you must provide _options.
To build options, OptionsBuilder.vy should be used in your app.

To use lzRead functionality, you must use ReadCmdCodecV1.vy to encode read requests.

@dev Vyper implementation differs from Solidity OApp in:
- message size limits are handled differently (Vyper does not allow infinite bytes arrays, must be capped)
- fees are handled differently (payNative, payLzToken are inlined and allow many sends in single tx)


@license Copyright (c) Curve.Fi, 2025 - all rights reserved

@author curve.fi

@custom:security [email protected]
"""

################################################################
#                            MODULES                           #
################################################################

# Ownership management. Must be initialized in main contract.
from snekmate.auth import ownable

uses: ownable

# Vyper-specific constants
from . import VyperConstants as constants

################################################################
#                         INTERFACES                           #
################################################################

# ERC20 interface is needed for lzToken fee payment
from ethereum.ercs import IERC20

# LayerZero EndpointV2 interface
interface ILayerZeroEndpointV2:
    def quote(_params: MessagingParams, _sender: address) -> MessagingFee: view
    def send(_params: MessagingParams, _refundAddress: address) -> MessagingReceipt: payable
    def setDelegate(_delegate: address): nonpayable
    def eid() -> uint32: view
    def lzToken() -> address: view


################################################################
#                           EVENTS                            #
################################################################

event PeerSet:
    eid: uint32
    peer: bytes32


################################################################
#                           CONSTANTS                          #
################################################################

# Message size limits
MAX_MESSAGE_SIZE: constant(uint256) = constants.MAX_MESSAGE_SIZE
MAX_OPTIONS_TOTAL_SIZE: constant(uint256) = constants.MAX_OPTIONS_TOTAL_SIZE
MAX_EXTRA_DATA_SIZE: constant(uint256) = constants.MAX_EXTRA_DATA_SIZE

# Offspec constant, useful for read messages detection
READ_CHANNEL_THRESHOLD: constant(
    uint32
) = 4294965694  # max(uint32)-1601, 1600 channels reserved for read


################################################################
#                           STORAGE                            #
################################################################

# The LayerZero endpoint associated with the given OApp
endpoint: public(immutable(ILayerZeroEndpointV2))

# Mapping to store peers associated with corresponding endpoints
peers: public(HashMap[uint32, bytes32])

################################################################
#                           STRUCTS                            #
################################################################

struct MessagingParams:
    dstEid: uint32
    receiver: bytes32
    message: Bytes[MAX_MESSAGE_SIZE]
    options: Bytes[MAX_OPTIONS_TOTAL_SIZE]
    payInLzToken: bool


struct MessagingReceipt:
    guid: bytes32
    nonce: uint64
    fee: MessagingFee


struct MessagingFee:
    nativeFee: uint256
    lzTokenFee: uint256


struct Origin:
    srcEid: uint32
    sender: bytes32
    nonce: uint64


################################################################
#                         CONSTRUCTOR                          #
################################################################

@deploy
def __init__(_endpoint: address, _delegate: address):
    """
    @notice Initialize OApp with endpoint and delegate
    @param _endpoint LayerZero endpoint address
    @param _delegate Address that can manage LZ configurations
    """
    assert _endpoint != empty(address), "Invalid endpoint"
    assert _delegate != empty(address), "Invalid delegate"

    # Set up endpoint
    endpoint = ILayerZeroEndpointV2(_endpoint)

    # Set delegate for endpoint config
    extcall endpoint.setDelegate(_delegate)


################################################################
#                           OAppCore                           #
################################################################

@external
def setPeer(_eid: uint32, _peer: bytes32):
    """
    @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.
    """
    ownable._check_owner()

    self._setPeer(_eid, _peer)


@internal
def _setPeer(_eid: uint32, _peer: bytes32):
    """
    @notice Internal function to set peer address
    @param _eid The endpoint ID.
    @param _peer The address of the peer to be associated with the corresponding endpoint.
    """
    self.peers[_eid] = _peer

    log PeerSet(eid=_eid, peer=_peer)


@view
@internal
def _getPeerOrRevert(_eid: uint32) -> bytes32:
    """
    @notice Internal function to get the peer address associated with a specific endpoint;
    reverts if NOT set.
    @param _eid The endpoint ID.
    @return peer The address of the peer associated with the specified endpoint.
    """
    peer: bytes32 = self.peers[_eid]
    assert peer != empty(bytes32), "OApp: no peer"
    return peer


@external
def setDelegate(_delegate: address):
    """
    @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.
    """
    ownable._check_owner()

    extcall endpoint.setDelegate(_delegate)


################################################################
#                           OAppRead                           #
################################################################

@external
def setReadChannel(_channelId: uint32, _active: bool):
    """
    @notice Set or unset a read channel for this OApp
    @param _channelId The channel ID to use for read requests
    @param _active Whether to activate or deactivate the channel
    """
    ownable._check_owner()

    peer: bytes32 = convert(self, bytes32) if _active else convert(empty(address), bytes32)
    self._setPeer(_channelId, peer)


################################################################
#                         OAppReceiver                         #
################################################################

# Vyper-specific:
# oAppVersion - not implemented

@external
@view
def isComposeMsgSender(
    _origin: Origin, _message: Bytes[MAX_MESSAGE_SIZE], _sender: address
) -> bool:
    """
    @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
    @param _origin The origin information containing the source endpoint and sender address.
    @param _message The lzReceive payload.
    @param _sender The sender address.
    @return isSender Is a valid sender.
    """
    return _sender == self


@external
@view
def allowInitializePath(_origin: Origin) -> bool:
    """
    @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.
    """
    return self.peers[_origin.srcEid] == _origin.sender


@external
@pure
def nextNonce(_srcEid: uint32, _sender: bytes32) -> uint64:
    """
    @notice Retrieves the next nonce for a given source endpoint and sender address.
    @dev Vyper-specific: If your app relies on ordered execution, you must change this function.
    @param _srcEid The source endpoint ID.
    @param _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.
    """
    return 0


@internal
@view
def _lzReceive(
    _origin: Origin,
    _guid: bytes32,
    _message: Bytes[MAX_MESSAGE_SIZE],
    _executor: address,
    _extraData: Bytes[MAX_EXTRA_DATA_SIZE],
):
    """
    @dev Vyper-specific: This must be called first in external lzReceive implementation.
    Name changed to _lzReceive due to internal nature of the function.

    @notice 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.
    """
    # Verify that the sender is the endpoint
    assert msg.sender == endpoint.address, "OApp: only endpoint"

    # Verify that the message comes from a trusted peer
    assert self._getPeerOrRevert(_origin.srcEid) == _origin.sender, "OApp: invalid sender"


################################################################
#                         OAppSender                           #
################################################################

# Vyper-specific:
# oAppVersion - not implemented

@internal
@view
def _quote(
    _dstEid: uint32,
    _message: Bytes[MAX_MESSAGE_SIZE],
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
    _payInLzToken: bool,
) -> MessagingFee:
    """
    @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.
    """

    return staticcall endpoint.quote(
        MessagingParams(
            dstEid=_dstEid,
            receiver=self._getPeerOrRevert(_dstEid),
            message=_message,
            options=_options,
            payInLzToken=_payInLzToken,
        ),
        self,
    )


@internal
@payable
def _lzSend(
    _dstEid: uint32,
    _message: Bytes[MAX_MESSAGE_SIZE],
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
    _fee: MessagingFee,
    _refundAddress: address,
) -> MessagingReceipt:
    """
    @dev Vyper-specific: fees are treated differently than in Solidity OApp.
        - _payNative and _payLzToken are inlined.
        - Multiple sends are supported within single transaction (msg.value >= native_fee) instead of '=='.

    @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.
    """
    # Get the peer address for the destination or revert if not set
    peer: bytes32 = self._getPeerOrRevert(_dstEid)

    # Handle native fee
    native_fee: uint256 = _fee.nativeFee
    if native_fee > 0:
        assert msg.value >= native_fee, "OApp: not enough fee"

    lzToken_fee: uint256 = _fee.lzTokenFee
    if lzToken_fee > 0:
        # Pay LZ token fee by sending tokens to the endpoint.
        lzToken: address = staticcall endpoint.lzToken()
        assert lzToken != empty(address), "OApp: LZ token unavailable"
        assert extcall IERC20(lzToken).transferFrom(msg.sender, endpoint.address, lzToken_fee, default_return_value=True), "OApp: token transfer failed"

    return extcall endpoint.send(
        MessagingParams(
            dstEid=_dstEid,
            receiver=peer,
            message=_message,
            options=_options,
            payInLzToken=_fee.lzTokenFee > 0,
        ),
        _refundAddress,
        value=native_fee,
    )

File 5 of 6 : OptionsBuilder.vy
# pragma version 0.4.3

"""
@title LayerZero Options Builder
@license Copyright (c) Curve.Fi, 2025 - all rights reserved
@author curve.fi
@custom:security [email protected]
"""

# Vyper-specific constants
from . import VyperConstants as constants


################################################################
#                           CONSTANTS                          #
################################################################

MAX_OPTIONS_TOTAL_SIZE: constant(uint256) = constants.MAX_OPTIONS_TOTAL_SIZE
MAX_OPTION_SINGLE_SIZE: constant(uint256) = constants.MAX_OPTION_SINGLE_SIZE

# LayerZero protocol constants
TYPE_1: constant(uint16) = 1
TYPE_2: constant(uint16) = 2
TYPE_3: constant(uint16) = 3

EXECUTOR_WORKER_ID: constant(uint8) = 1
DVN_WORKER_ID: constant(uint8) = 2

# Option types
OPTION_TYPE_LZRECEIVE: constant(uint8) = 1
OPTION_TYPE_NATIVE_DROP: constant(uint8) = 2
OPTION_TYPE_LZCOMPOSE: constant(uint8) = 3
OPTION_TYPE_ORDERED_EXECUTION: constant(uint8) = 4
OPTION_TYPE_LZREAD: constant(uint8) = 5

# DVN option types
OPTION_TYPE_DVN: constant(uint8) = 10
OPTION_TYPE_DVN_PRECRIME: constant(uint8) = 1


################################################################
#                        OptionsBuilder                        #
################################################################
# Includes partial implementation of ExecutorOptions.sol

@internal
@pure
def newOptions() -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @notice Creates a new options container with type 3.
    @return options The newly created options container.
    """
    options: Bytes[MAX_OPTIONS_TOTAL_SIZE] = concat(convert(TYPE_3, bytes2), b"")

    return options


@internal
@pure
def addExecutorOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
    _optionType: uint8,
    _option: Bytes[MAX_OPTION_SINGLE_SIZE],
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds an executor option to the existing options.
    @param _options The existing options container.
    @param _optionType The type of the executor option.
    @param _option The encoded data for the executor option.
    @return options The updated options container.
    """
    assert convert(slice(_options, 0, 2), uint16) == TYPE_3, "OApp: invalid option type"
    # Account for header bytes: 1 worker + 2 size + 1 type = 4 bytes
    assert (len(_options) + len(_option) + 4 <= MAX_OPTIONS_TOTAL_SIZE), "OApp: options size exceeded"

    return concat(
        convert(_options, Bytes[MAX_OPTIONS_TOTAL_SIZE - MAX_OPTION_SINGLE_SIZE - 4]), # downcast Bytes size, -4 for header
        convert(EXECUTOR_WORKER_ID, bytes1),
        convert(convert(len(_option) + 1, uint16), bytes2),  # +1 for optionType
        convert(_optionType, bytes1),
        _option,
    )


@internal
@pure
def addExecutorLzReceiveOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE], _gas: uint128, _value: uint128
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @notice Adds an executor LZ receive option to the existing options.
    @param _options The existing options container.
    @param _gas The gasLimit used on the lzReceive() function in the OApp.
    @param _value The msg.value passed to the lzReceive() function in the OApp.
    @return options The updated options container.
    @dev When multiples of this option are added, they are summed by the executor
    eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,
    that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.

    @dev Vyper-specific: ExecutorOptions.encodeLzReceiveOption is inlined here.
    OnlyType3 is not checked here as it is checked in addExecutorOption.
    """
    option: Bytes[MAX_OPTION_SINGLE_SIZE] = b""
    gas_bytes: bytes16 = convert(_gas, bytes16)

    if _value > 0:
        value_bytes: bytes16 = convert(_value, bytes16)
        option = concat(gas_bytes, value_bytes)
    else:
        option = concat(gas_bytes, b"")  # bytes -> Bytes

    return self.addExecutorOption(_options, OPTION_TYPE_LZRECEIVE, option)


@internal
@pure
def addExecutorNativeDropOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE], _amount: uint128, _receiver: bytes32
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds an executor native drop option to the existing options.
    @param _options The existing options container.
    @param _amount The amount for the native value that is airdropped to the 'receiver'.
    @param _receiver The receiver address for the native drop option.
    @return options The updated options container.
    @dev When multiples of this option are added, they are summed by the executor on the remote chain.
    """
    option: Bytes[MAX_OPTION_SINGLE_SIZE] = concat(convert(_amount, bytes16), _receiver)

    return self.addExecutorOption(_options, OPTION_TYPE_NATIVE_DROP, option)


@internal
@pure
def addExecutorLzComposeOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
    _index: uint16,
    _gas: uint128,
    _value: uint128,
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds an executor LZ compose option to the existing options.
    @param _options The existing options container.
    @param _index The index for the lzCompose() function call.
    @param _gas The gasLimit for the lzCompose() function call.
    @param _value The msg.value for the lzCompose() function call.
    @return options The updated options container.
    @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.
    @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.
    @dev ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2
    """
    option: Bytes[MAX_OPTION_SINGLE_SIZE] = b""

    index_bytes: bytes2 = convert(_index, bytes2)
    gas_bytes: bytes16 = convert(_gas, bytes16)

    if _value > 0:
        value_bytes: bytes16 = convert(_value, bytes16)
        option = concat(index_bytes, gas_bytes, value_bytes)
    else:
        option = concat(index_bytes, gas_bytes)

    return self.addExecutorOption(_options, OPTION_TYPE_LZCOMPOSE, option)


@internal
@pure
def addExecutorOrderedExecutionOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds an executor ordered execution option to the existing options.
    @param _options The existing options container.
    @return options The updated options container.
    """
    return self.addExecutorOption(_options, OPTION_TYPE_ORDERED_EXECUTION, b"")


@internal
@pure
def addExecutorLzReadOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE], _gas: uint128, _size: uint32, _value: uint128
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds an executor LZ read option to the existing options.
    @param _options The existing options container.
    @param _gas The gasLimit for the lzRead() function call.
    @param _size The size of the lzRead() function call.
    @param _value The msg.value for the lzRead return function call.
    @return options The updated options container.
    """
    option: Bytes[MAX_OPTION_SINGLE_SIZE] = b""

    gas_bytes: bytes16 = convert(_gas, bytes16)
    size_bytes: bytes4 = convert(_size, bytes4)

    if _value > 0:
        value_bytes: bytes16 = convert(_value, bytes16)
        option = concat(gas_bytes, size_bytes, value_bytes)
    else:
        option = concat(gas_bytes, size_bytes)

    return self.addExecutorOption(_options, OPTION_TYPE_LZREAD, option)


@internal
@pure
def addDVNOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE],
    _dvnIdx: uint8,
    _optionType: uint8,
    _option: Bytes[MAX_OPTION_SINGLE_SIZE],
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds a DVN option to the existing options.
    @param _options The existing options container.
    @param _dvnIdx The DVN index for the DVN option.
    @param _optionType The type of the DVN option.
    @param _option The encoded data for the DVN option.
    @return options The updated options container.
    """
    assert convert(slice(_options, 0, 2), uint16) == TYPE_3, "OApp: invalid option type"
    # Account for header bytes: 1 worker + 2 size + 1 dvnIdx + 1 type = 5 bytes
    assert (len(_options) + len(_option) + 5 <= MAX_OPTIONS_TOTAL_SIZE), "OApp: dvn options size exceeded"

    return concat(
        convert(_options, Bytes[MAX_OPTIONS_TOTAL_SIZE - MAX_OPTION_SINGLE_SIZE - 5]), # downcast Bytes size
        convert(DVN_WORKER_ID, bytes1),
        convert(convert(len(_option) + 2, uint16), bytes2),  # +2 for optionType and dvnIdx
        convert(_dvnIdx, bytes1),
        convert(_optionType, bytes1),
        _option,
    )


@internal
@pure
def addDVNPreCrimeOption(
    _options: Bytes[MAX_OPTIONS_TOTAL_SIZE], _dvnIdx: uint8
) -> Bytes[MAX_OPTIONS_TOTAL_SIZE]:
    """
    @dev Adds a DVN pre-crime option to the existing options.
    @param _options The existing options container.
    @param _dvnIdx The DVN index for the pre-crime option.
    @return options The updated options container.
    """
    return self.addDVNOption(_options, _dvnIdx, OPTION_TYPE_DVN_PRECRIME, b"")

File 6 of 6 : ReadCmdCodecV1.vy
# pragma version 0.4.3

"""
@title LayerZero Read Command Codec V1
@license Copyright (c) Curve.Fi, 2025 - all rights reserved
@author curve.fi
@custom:security [email protected]
"""

# Vyper-specific constants
from . import VyperConstants as constants


################################################################
#                           CONSTANTS                          #
################################################################

# Vyper Byte size limits
MAX_MESSAGE_SIZE: constant(uint256) = constants.MAX_MESSAGE_SIZE
MAX_CALLDATA_SIZE: constant(uint256) = constants.MAX_CALLDATA_SIZE

MAX_EVM_CALL_REQUESTS: constant(uint256) = (MAX_MESSAGE_SIZE - 6 - 39) // (MAX_CALLDATA_SIZE + 42)
# +6 is general header, see encode()
# +39 is single compute command length, see appendEVMCallComputeV1
# +42 is per-call header length, see appendEVMCallRequestV1

# Read codec constants
CMD_VERSION: constant(uint16) = 1
REQUEST_VERSION: constant(uint8) = 1
RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL: constant(uint16) = 1

COMPUTE_VERSION: constant(uint8) = 1
COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL: constant(uint16) = 1

# Compute settings
COMPUTE_SETTING_MAP_ONLY: constant(uint8) = 0
COMPUTE_SETTING_REDUCE_ONLY: constant(uint8) = 1
COMPUTE_SETTING_MAP_REDUCE: constant(uint8) = 2
COMPUTE_SETTING_NONE: constant(uint8) = 3

################################################################
#                           STRUCTS                            #
################################################################

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


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


# ################################################################
# #                     ReadCmdCodecV1 LIBRARY                   #
# ################################################################

# Vyper-specific:
# decode - not implemented
# decodeRequestsV1 - not implemented
# decodeEVMCallRequestV1 - not implemented
# decodeEVMCallComputeV1 - not implemented

@internal
@pure
def _decodeCmdAppLabel(_cmd: Bytes[MAX_MESSAGE_SIZE]) -> uint16:
    cmdVersion: uint16 = convert(slice(_cmd, 0, 2), uint16)
    assert cmdVersion == CMD_VERSION, "OApp: InvalidVersion"
    return convert(slice(_cmd, 2, 2), uint16)


@internal
@pure
def _decodeRequestV1AppRequestLabel(_request: Bytes[MAX_MESSAGE_SIZE]) -> uint16:
    requestVersion: uint8 = convert(slice(_request, 0, 1), uint8)
    assert requestVersion == REQUEST_VERSION, "OApp: InvalidVersion"
    return convert(slice(_request, 1, 2), uint16)


@internal
@pure
def encode(
    _appCmdLabel: uint16,
    _evmCallRequests: DynArray[EVMCallRequestV1, MAX_EVM_CALL_REQUESTS],
    _evmCallCompute: EVMCallComputeV1 = empty(EVMCallComputeV1),
) -> Bytes[MAX_MESSAGE_SIZE]:
    cmd: Bytes[MAX_MESSAGE_SIZE] = concat(
        convert(CMD_VERSION, bytes2),
        convert(_appCmdLabel, bytes2),
        convert(convert(len(_evmCallRequests), uint16), bytes2),
    )
    for call_request: EVMCallRequestV1 in _evmCallRequests:
        cmd = self.appendEVMCallRequestV1(cmd, call_request)

    if _evmCallCompute.targetEid != 0:
        cmd = self.appendEVMCallComputeV1(cmd, _evmCallCompute)
    return cmd


@internal
@pure
def appendEVMCallRequestV1(
    _cmd: Bytes[MAX_MESSAGE_SIZE], _request: EVMCallRequestV1
) -> Bytes[MAX_MESSAGE_SIZE]:
    """
    @notice Appends an EVM call request to the command
    @param _cmd The existing command bytes
    @param _request The EVM call request to append
    @return The updated command bytes
    """

    # dev: assert that appending new request to existing command will not exceed the max size
    assert (len(_cmd) + MAX_CALLDATA_SIZE + 42 <= MAX_MESSAGE_SIZE), "OApp: Command too large"
    # dev: 42 is length of all fields excluding existing command and callData
    return concat(
        # current cmd
        convert(_cmd, Bytes[MAX_MESSAGE_SIZE - MAX_CALLDATA_SIZE - 42]), # downcast Bytes size
        # newCmd
        convert(REQUEST_VERSION, bytes1),
        convert(_request.appRequestLabel, bytes2),
        convert(RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL, bytes2),
        convert(convert(len(_request.callData) + 35, uint16), bytes2),
        convert(_request.targetEid, bytes4),
        # new request
        convert(_request.isBlockNum, bytes1),
        convert(_request.blockNumOrTimestamp, bytes8),
        convert(_request.confirmations, bytes2),
        convert(_request.to, bytes20),
        _request.callData,
    )


@internal
@pure
def appendEVMCallComputeV1(
    _cmd: Bytes[MAX_MESSAGE_SIZE], _compute: EVMCallComputeV1
) -> Bytes[MAX_MESSAGE_SIZE]:
    """
    @notice Appends an EVM call compute to the command
    @param _cmd The existing command bytes
    @param _compute The EVM call compute to append
    @return The updated command bytes
    """

    assert len(_cmd) + 39 <= MAX_MESSAGE_SIZE, "OApp: Command too large"
    # dev: 39 is length of all fields excluding existing command
    return concat(
        convert(_cmd, Bytes[MAX_MESSAGE_SIZE - 39]), # downcast Bytes size
        convert(COMPUTE_VERSION, bytes1),
        convert(COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL, bytes2),
        convert(_compute.computeSetting, bytes1),
        convert(_compute.targetEid, bytes4),
        convert(_compute.isBlockNum, bytes1),
        convert(_compute.blockNumOrTimestamp, bytes8),
        convert(_compute.confirmations, bytes2),
        convert(_compute.to, bytes20),
    )

Settings
{
  "outputSelection": {
    "contracts/messengers/LZBlockRelay.vy": [
      "evm.bytecode",
      "evm.deployedBytecode",
      "abi"
    ]
  },
  "search_paths": [
    ".",
    "0",
    ".venv/lib/python3.12/site-packages"
  ],
  "evmVersion": "paris"
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"name":"block_number","type":"uint256"},{"indexed":true,"name":"block_hash","type":"bytes32"},{"components":[{"name":"eid","type":"uint32"},{"name":"fee","type":"uint256"}],"indexed":false,"name":"targets","type":"tuple[]"}],"name":"BlockHashBroadcast","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previous_owner","type":"address"},{"indexed":true,"name":"new_owner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eid","type":"uint32"},{"indexed":false,"name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"new_owner","type":"address"}],"name":"transfer_ownership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounce_ownership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint32"}],"name":"peers","outputs":[{"name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_eid","type":"uint32"},{"name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"name":"srcEid","type":"uint32"},{"name":"sender","type":"bytes32"},{"name":"nonce","type":"uint64"}],"name":"_origin","type":"tuple"},{"name":"_message","type":"bytes"},{"name":"_sender","type":"address"}],"name":"isComposeMsgSender","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"name":"srcEid","type":"uint32"},{"name":"sender","type":"bytes32"},{"name":"nonce","type":"uint64"}],"name":"_origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_srcEid","type":"uint32"},{"name":"_sender","type":"bytes32"}],"name":"nextNonce","outputs":[{"name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"name":"_is_enabled","type":"bool"},{"name":"_read_channel","type":"uint32"},{"name":"_mainnet_eid","type":"uint32"},{"name":"_mainnet_view","type":"address"}],"name":"set_read_config","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_eids","type":"uint32[]"},{"name":"_peers","type":"address[]"}],"name":"set_peers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_oracle","type":"address"}],"name":"set_block_oracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdraw_eth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"name":"_read_gas_limit","type":"uint128"},{"name":"_value","type":"uint128"}],"name":"quote_read_fee","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_target_eids","type":"uint32[]"},{"name":"_lz_receive_gas_limit","type":"uint128"}],"name":"quote_broadcast_fees","outputs":[{"name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_target_eids","type":"uint32[]"},{"name":"_target_fees","type":"uint256[]"},{"name":"_lz_receive_gas_limit","type":"uint128"},{"name":"_read_gas_limit","type":"uint128"}],"name":"request_block_hash","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"name":"_target_eids","type":"uint32[]"},{"name":"_target_fees","type":"uint256[]"},{"name":"_lz_receive_gas_limit","type":"uint128"},{"name":"_read_gas_limit","type":"uint128"},{"name":"_block_number","type":"uint256"}],"name":"request_block_hash","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"name":"_target_eids","type":"uint32[]"},{"name":"_target_fees","type":"uint256[]"},{"name":"_lz_receive_gas_limit","type":"uint128"}],"name":"broadcast_latest_block","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"name":"srcEid","type":"uint32"},{"name":"sender","type":"bytes32"},{"name":"nonce","type":"uint64"}],"name":"_origin","type":"tuple"},{"name":"_guid","type":"bytes32"},{"name":"_message","type":"bytes"},{"name":"_executor","type":"address"},{"name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"read_enabled","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"read_channel","outputs":[{"name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mainnet_eid","outputs":[{"name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mainnet_block_view","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"block_oracle","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_endpoint","type":"address"}],"outputs":[],"stateMutability":"nonpayable","type":"constructor"}]

6132835150346101e45760206134a46000396000518060a01c6101e45761014052610028610093565b32604052610034610059565b61014051604052326060526100476100a1565b6132836101e9610000396132a3610000f35b6001546060526040516001556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060006080a3565b3360405261009f610059565b565b6040516101235760208060e05260106080527f496e76616c696420656e64706f696e740000000000000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b6060516101a55760208060e05260106080527f496e76616c69642064656c65676174650000000000000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b604051613283526132835163ca5eb5e160805260605160a052803b156101e457600060806024609c6000855af16101e1573d600060003e3d6000fd5b50565b600080fd60003560e01c60026015820660011b61325901601e39600051565b638da5cb5b811861003657346132545760015460405260206040f35b63bb0b6a53811861007357602436103417613254576004358060201c61325457604052600260405160205260005260406000205460605260206060f35b63ca5eb5e1811861196c57602436103417613254576004358060a01c613254576101005261009f61196e565b602061328360003960005163ca5eb5e1610120526101005161014052803b15613254576000610120602461013c6000855af16100e0573d600060003e3d6000fd5b50005b63f0350c0481186101d057602436103417613254576004358060a01c613254576101005261010f61196e565b610100516101bf576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a00160468160468460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b610100516040526101ce6119f5565b005b63bf23b95a811861196c576044361034176132545760043560040160208135116132545780356000816020811161325457801561022f57905b8060051b6020850101358060201c613254578160051b6101200152600101818118610209575b50508061010052505060243560040160208135116132545780356000816020811161325457801561028257905b8060051b6020850101358060a01c613254578160051b610540015260010181811861025c575b5050806105205250506000546002146132545760026000556102a261196e565b61052051610100511815610332576020806109a0526013610940527f496e76616c69642070656572206172726179730000000000000000000000000061096052610940816109a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610980528060040161099cfd5b6000610100516020811161325457801561039457905b806109405261094051610100518110156132545760051b610120015160405261094051610520518110156132545760051b6105400151606052610389611a2f565b600101818118610348575b50506003600055005b63b15e13ee81186103c45734613254576103b561196e565b60006040526103c26119f5565b005b6313137d65811861196c5760e3361115613254576004358060201c6132545761184052602435611860526044358060401c6132545761188052608435600401803560b781116132545750602081350180826118a037505060a4358060a01c613254576119805260c43560040180356040811161325457506060816119a037506000546002146132545760026000556118405161014052611860516101605261188051610180526064356101a05260206118a05101806101c0826118a060045afa156132545750611980516102a05260606102c060606119a060045afa15613254576104ad61303c565b60045461184051186107545760035461054257602080611a60526010611a00527f52656164206e6f7420656e61626c656400000000000000000000000000000000611a2052611a0081611a600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0611a405280600401611a5cfd5b604036611a003760406118a05118613254576118a0516118c00161190011613254576118c051611a40526118e051611a6052611a408051611a00526020810151611a205250611a2051156107af57611a20516009611a0051602052600052604060002055611a0051604052611a20516060526105bc613174565b60086064356020526000526040600020805460208160061b01600081601f0160051c6041811161325457801561060657905b808501548160051b611a4001526001018181186105ee575b5050505060418101546122605260428101546122805250611a4051156107af5760006122a0526000611a40516020811161325457801561067f57905b8060061b611a600180516122c05260208101516122e052506122a0516122e05180820182811061325457905090506122a052600101818118610642575b50506122a05134101561070e576020806123205260166122c0527f496e73756666696369656e74206d73672e76616c7565000000000000000000006122e0526122c0816123200181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612300528060040161231cfd5b611a005161062052611a205161064052611a405160208160061b018061066082611a4060045afa1561325457505061226051610e805261228051610ea0526107af612e4a565b604036611a003760406118a05118613254576118a0516118c00161190011613254576118c051611a40526118e051611a6052611a408051611a00526020810151611a205250611a0051604052611a20516060526107af613174565b6003600055005b635e280f1181186107d4573461325457602061328360403960206040f35b636eb7385a81186109b157604436103417613254576004358060801c61325457610d20526024358060801c61325457610d4052600054600214613254576003546108c057602080610de0526027610d60527f52656164206e6f7420656e61626c6564202d2063616c6c207365745f72656164610d80527f5f636f6e66696700000000000000000000000000000000000000000000000000610da052610d6081610de00160478160478460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610dc05280600401610ddcfd5b6000610980526108d1610e40612006565b610e40602081510180610d60828460045afa156132545750506108f5610ea061210f565b610ea06056610e4060568360045afa15613254575060566102206056610e4060045afa1561325457610d20516102805260406102a052610d40516102c05261093e610ea061236a565b610ea06056610f0060568360045afa1561325457506056610e406056610f0060045afa15613254576020600454610140526020610d6051018061016082610d6060045afa15613254575060566102406056610e4060045afa156132545760006102a0526109ac610ea061251e565b610ea0f35b63994283aa811861196c57606336111561325457600435600401602081351161325457803560008160208111613254578015610a0f57905b8060051b6020850101358060201c613254578160051b61186001526001018181186109e9575b505080611840525050602435600401602081351161325457803560208160051b018083611c60375050506044358060801c6132545761208052600054600214613254576002600055600354610b065760208061212052602b6120a0527f43616e206f6e6c792062726f6164636173742066726f6d20726561642d656e616120c0527f626c656420636861696e730000000000000000000000000000000000000000006120e0526120a08161212001604b81604b8460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612100528060040161211cfd5b600754610b8f576020806121005260156120a0527f4f7261636c65206e6f7420636f6e6669677572656400000000000000000000006120c0526120a0816121000181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06120e052806004016120fcfd5b611c6051611840511815610c1f5760208061210052600f6120a0527f4c656e677468206d69736d6174636800000000000000000000000000000000006120c0526120a0816121000181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06120e052806004016120fcfd5b60075463017a494d6120c05260206120c060046120dc845afa610c47573d600060003e3d6000fd5b60203d10613254576120c09050516120a052600754639724283f6120e0526120a0516121005260206120e060246120fc845afa610c89573d600060003e3d6000fd5b60203d10613254576120e09050516120c0526120c051610d25576020806121405260136120e0527f4e6f20636f6e6669726d656420626c6f636b7300000000000000000000000000612100526120e0816121400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612120528060040161213cfd5b6120c05160096120a0516020526000526040600020541815610dc35760208061214052600e6120e0527f556e6b6e6f776e20736f75726365000000000000000000000000000000000000612100526120e0816121400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612120528060040161213cfd5b60006120e05260006129005260006118405160208111613254578015610e7557905b80612920526120e051601f8111613254578060061b6121000161292051611840518110156132545760051b6118600151815261292051611c60518110156132545760051b611c800151602082015250600181016120e052506129005161292051611c60518110156132545760051b611c800151808201828110613254579050905061290052600101818118610de5575b505034612900511115610f045760208061298052601a612920527f496e73756666696369656e74206d6573736167652076616c756500000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b6120a051610620526120c051610640526120e05160208160061b0180610660826120e060045afa1561325457505061208051610e805233610ea052610f47612e4a565b6003600055005b633400288b8118610f9157604436103417613254576004358060201c6132545761010052610f7a61196e565b61010051604052602435606052610f8f611a2f565b005b6382413eac811861196c5760a436103417613254576004358060201c613254576040526024356060526044358060401c61325457608052606435600401803560b7811161325457506020813501808260a03750506084358060a01c61325457610180523061018051146101a05260206101a0f35b63ff7bd03d811861105a57606436103417613254576004358060201c613254576040526024356060526044358060401c6132545760805260605160026040516020526000526040600020541460a052602060a0f35b638d001316811861196c5734613254576000546002146132545760045460405260206040f35b637d25a05e811861196c57604436103417613254576004358060201c61325457604052600060605260206060f35b632be655cd811861196c57608436103417613254576004358060011c61325457610100526024358060201c61325457610120526044358060201c61325457610140526064358060a01c613254576101605260005460021461325457600260005561111661196e565b63fffff9bf6101205112156111a7576020806101e0526014610180527f496e76616c69642072656164206368616e6e656c0000000000000000000000006101a052610180816101e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101c052806004016101dcfd5b610100516111b65760006111cd565b61014051156111ca576101605115156111cd565b60005b6111f957610100516111f257610140516111eb5761016051156111fc565b60006111fc565b60006111fc565b60015b611282576020806101e0526013610180527f496e76616c6964207265616420636f6e666967000000000000000000000000006101a052610180816101e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101c052806004016101dcfd5b60035461129057600061129a565b6101205160045414155b156112b25760045460405260006060526112b2611a2f565b61010051600355610120516004556101405160055561016051600655610100516112dd5760006112df565b305b6101805261012051604052610180516060526112f9611a2f565b6003600055005b63bd0a2294811861196c57602436103417613254576004358060a01c613254576101005260005460021461325457600260005561133b61196e565b610100516007556003600055005b6330a95e67811861141c576024361034176132545760005460021461325457600260005561137561196e565b60043547101561140157602080610160526014610100527f496e73756666696369656e742062616c616e636500000000000000000000000061012052610100816101600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b6000600060006000600435336000f115613254576003600055005b633516c5be811861196c5734613254576000546002146132545760035460405260206040f35b63742a6dcb81186116a157604436103417613254576004356004016020813511613254578035600081602081116132545780156114a157905b8060051b6020850101358060201c613254578160051b610540015260010181811861147b575b5050806105205250506024358060801c613254576109405260005460021461325457604036610a60376040610a4052610a40606061096060608360045afa1561325457506000610a40526114f6610ec061210f565b610ec06056610e6060568360045afa15613254575060566102206056610e6060045afa1561325457610940516102805260006102a052611537610ec0612638565b610ec06056610f2060568360045afa1561325457506056610e606056610f2060045afa15613254576000610520516020811161325457801561164057905b8060051b6105400151610ec0526002610ec051602052600052604060002054610ee052610ee0516115c557610a4051601f81116132545760008160051b610a60015260018101610a405250611635565b610ec0516101405260206109605101806101608261096060045afa15613254575060566102406056610e6060045afa156132545760006102a05261160a610f0061251e565b610f0051610f4052610a4051601f811161325457610f40518160051b610a60015260018101610a4052505b600101818118611575575b5050602080610ec05280610ec0016000610a40518083528060051b6000826020811161325457801561168c57905b8060051b610a6001518160051b60208801015260010181811861166e575b50508201602001915050905081019050610ec0f35b6341930981811861196c5760a336111561325457608435612900525b60043560040160208135116132545780356000816020811161325457801561170757905b8060051b6020850101358060201c613254578160051b6120a001526001018181186116e1575b505080612080525050602435600401602081351161325457803560208160051b0180836124a0375050506044358060801c613254576128c0526064358060801c613254576128e0526000546002146132545760026000556003546117e757602080612980526010612920527f52656164206e6f7420656e61626c65640000000000000000000000000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b6124a0516120805118156118775760208061298052600f612920527f4c656e677468206d69736d61746368000000000000000000000000000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b61290051610d20526120805160208160051b0180610d408261208060045afa156132545750506124a05160208160051b0180611160826124a060045afa156132545750506128c051611580526128e0516115a0526118d3612b71565b6003600055005b63b5775a2c811861196c576083361115613254576000612900526116bd565b63b5c3cbd0811861196c5734613254576000546002146132545760055460405260206040f35b6386e39385811861196c5734613254576000546002146132545760065460405260206040f35b636959a37f811861196c5734613254576000546002146132545760075460405260206040f35b5b005b6001543318156119f35760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b6001546060526040516001556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060006080a3565b60605160026040516020526000526040600020557f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b60405160805260605160a05260406080a1565b60b760405160448101818110613254579050602a81018181106132545790501115611b1e576020806102c0526017610260527f4f4170703a20436f6d6d616e6420746f6f206c6172676500000000000000000061028052610260816102c00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06102a052806004016102bcfd5b600060496040511161325457604080516020820183610280018281848460045afa1561325457505080830192505050600160f81b816102800152600181019050610120518060f01b9050816102800152600281019050600160f01b8161028001526002810190506101e051602381018181106132545790508060101c613254578060f01b9050816102800152600281019050610140518060e01b9050816102800152600481019050610160518060f81b9050816102800152600181019050610180518060c01b90508161028001526008810190506101a0518060f01b90508161028001526002810190506101c0518060601b90508161028001526014810190506101e051816102800181818361020060045afa1561325457508082019150508061026052610260905060208151018083828460045afa1561325457505050565b60b7604051602781018181106132545790501115611cf8576020806102405260176101e0527f4f4170703a20436f6d6d616e6420746f6f206c61726765000000000000000000610200526101e0816102400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610220528060040161023cfd5b600060906040511161325457604080516020820183610200018281848460045afa1561325457505080830192505050600160f81b816102000152600181019050600160f01b816102000152600281019050610120518060f81b9050816102000152600181019050610140518060e01b9050816102000152600481019050610160518060f81b9050816102000152600181019050610180518060c01b90508161020001526008810190506101a0518060f01b90508161020001526002810190506101c0518060601b9050816102000152601481019050806101e0526101e0905060208151018083828460045afa1561325457505050565b6000600160f01b816106a00152600281019050610360518060f01b9050816106a00152600281019050610380518060101c613254578060f01b9050816106a001526002810190508061068052610680905080516105a05260208101516105c0525060006103805160018111613254578015611f5b57905b61014081026103a00180516106805260208101516106a05260408101516106c05260608101516106e05260808101516107005260a08101516107205260c08101606461074060648360045afa1561325457505060206105a05101806040826105a060045afa15613254575061068051610120526106a051610140526106c051610160526106e05161018052610700516101a052610720516101c05260646101e0606461074060045afa1561325457611f1e6107c0611a77565b6107c06020815101806108a0828460045afa1561325457505060206108a05101806105a0826108a060045afa156132545750600101818118611e65575b50506105005115611fec5760206105a05101806040826105a060045afa1561325457506104e05161012052610500516101405261052051610160526105405161018052610560516101a052610580516101c052611fb9610680611c5e565b610680602081510180610760828460045afa1561325457505060206107605101806105a08261076060045afa1561325457505b60206105a051018082826105a060045afa15613254575050565b637b754d2d610a2452600461098051610a44526001610a6452604001610a2052610a2060646109a060648360045afa1561325457506001610a2052600554610a40526000610a6052428060401c61325457610a80526001610aa052600654610ac0526064610ae060646109a060045afa1561325457600161036052610a20516103a052610a40516103c052610a60516103e052610a805161040052610aa05161042052610ac0516104405260646104606064610ae060045afa156132545760016103805260c0366104e0376120dc610c40611dee565b610c40602081510180610b60828460045afa156132545750506020610b605101808282610b6060045afa15613254575050565b6000600360f01b8160e001526002810190506020600060a05260a0018160e00150508060c05260c0905080516040526020810151606052506056816056604060045afa156132545750565b60036001604051111561325457606051610140526002610120526101206020810151815160200360031b1c9050181561220f576020806101c0526019610160527f4f4170703a20696e76616c6964206f7074696f6e20747970650000000000000061018052610160816101c00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101a052806004016101bcfd5b603660405160c05180820182811061325457905090506004810181811061325457905011156122ba5760208061018052601b610120527f4f4170703a206f7074696f6e732073697a65206578636565646564000000000061014052610120816101800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b6000600260405111613254576040805160208201836101400181518152505080830192505050600160f81b81610140015260018101905060c051600181018181106132545790508060101c613254578060f01b905081610140015260028101905060a0518060f81b905081610140015260018101905060c051816101400181818360e060045afa1561325457508082019150508061012052610120905060568260568360045afa15613254575050565b60006102e052610280518060801b9050610340526102a0518060e01b90506103605260016102c05112156123d957600061034051816103a0015260108101905061036051816103a001526004810190508061038052610380905080516102e05260208101516103005250612436565b6102c0518060801b905061038052600061034051816103c0015260108101905061036051816103c0015260048101905061038051816103c00152601081019050806103a0526103a0905060446102e060448360045afa1561325457505b60566040605661022060045afa1561325457600560a052605060c060506102e060045afa156132545761246a61038061215a565b61038060568260568360045afa15613254575050565b60026040516020526000526040600020546060526060516125165760208060e052600d6080527f4f4170703a206e6f20706565720000000000000000000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b606051815250565b602061328360003960005163ddc28c586102e05260408061030052806103000160a0610140518252610140516040526125586102c0612480565b6102c05160208301528060408301528082016020610160510180828261016060045afa1561325457508051806020830101601f82600003163682375050601f19601f82516020010116905081019050806060830152808201605681605661024060045afa15613254578051806020830101601f82600003163682375050601f19601f825160200101169050810190506102a051608083015290508101905030610320525060406102e06102246102fc845afa612619573d600060003e3d6000fd5b60403d10613254576102e0905080518252602081015160208301525050565b60006102c052610280518060801b90506103205260016102a051121561269c57600061032051816103800152601081019050602060006103405261034001816103800150508061036052610360905080516102c05260208101516102e052506126e7565b6102a0518060801b905061034052600061032051816103800152601081019050610340518161038001526010810190508061036052610360905080516102c05260208101516102e052505b60566040605661022060045afa1561325457600160a052605060c060506102c060045afa156132545761271b61034061215a565b61034060568260568360045afa15613254575050565b61014051604052612743610320612480565b61032051610300526102a0516103205261032051156127e957610320513410156127e9576020806103a0526014610340527f4f4170703a206e6f7420656e6f7567682066656500000000000000000000000061036052610340816103a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b6102c0516103405261034051156129f557602061328360003960005163e4fe1d94610380526020610380600461039c845afa61282a573d600060003e3d6000fd5b3d602081183d602010021880610380016103a01161325457610380518060a01c613254576103c052506103c090505161036052610360516128e7576020806103e052601a610380527f4f4170703a204c5a20746f6b656e20756e617661696c61626c650000000000006103a052610380816103e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06103c052806004016103dcfd5b610360516323b872dd61038052336103a05260206132836103c039610340516103e0526020610380606461039c6000855af1612928573d600060003e3d6000fd5b3d61293f57803b1561325457600161040052612969565b3d602081183d602010021880610380016103a01161325457610380518060011c6132545761040052505b6104009050516129f55760208061048052601b610420527f4f4170703a20746f6b656e207472616e73666572206661696c6564000000000061044052610420816104800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610460528060040161047cfd5b6020613283600039600051632637a4506103605260408061038052806103800160a06101405182526103005160208301528060408301528082016020610160510180828261016060045afa1561325457508051806020830101601f82600003163682375050601f19601f82516020010116905081019050806060830152808201605681605661024060045afa15613254578051806020830101601f82600003163682375050601f19601f825160200101169050810190506102c051151560808301529050810190506102e0516103a05250608061036061022461037c61032051855af1612ae7573d600060003e3d6000fd5b3d608081183d608010021880610360016103e0116132545780610360016103e01161325457610360516105a052610380518060401c613254576105c05280610360016103e011613254576103a0516105e0526103c05161060052506105a0905080518252602081015160208301526040810160408301815181526020820151602082015250505050565b60006115c0526000611de0526000610d405160208111613254578015612c2357905b80611e00526115c051601f8111613254578060061b6115e001611e0051610d40518110156132545760051b610d6001518152611e0051611160518110156132545760051b6111800151602082015250600181016115c05250611de051611e0051611160518110156132545760051b61118001518082018281106132545790509050611de052600101818118612b93575b505034611de0511115612cb257602080611e60526012611e00527f496e73756666696369656e742076616c75650000000000000000000000000000611e2052611e0081611e600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0611e405280600401611e5cfd5b610d205161098052612cc5611ee0612006565b611ee0602081510180611e00828460045afa15613254575050612ce9611f4061210f565b611f406056611ee060568360045afa15613254575060566102206056611ee060045afa15613254576115a0516102805260406102a052611de0518060801c613254576102c052612d3a611f4061236a565b611f406056611fa060568360045afa1561325457506056611ee06056611fa060045afa156132545734611f40526000611f6052600454610140526020611e0051018061016082611e0060045afa15613254575060566102406056611ee060045afa1561325457611f40516102a052611f60516102c052336102e052612dc0612000612731565b6120008051611f80526020810151611fa052604081018051611fc0526020810151611fe05250506008611f805160205260005260406000206115c05160208160061b01600081601f0160051c60418111613254578015612e3457905b8060051b6115c0015181860155600101818118612e1c575b5050505061158051604182015533604282015550565b61062051610fc05261064051610fe0526040610fa052610fa06060610ec060608360045afa156132545750612e8061100061210f565b6110006056610fa060568360045afa15613254575060566102206056610fa060045afa1561325457610e80516102805260006102a052612ec1611000612638565b611000605661106060568360045afa1561325457506056610fa0605661106060045afa156132545760006106605160208111613254578015612fa357905b8060061b610680018051611000526020810151611020525060026110005160205260005260406000205415612f9857611020516110405260006110605261100051610140526020610ec051018061016082610ec060045afa15613254575060566102406056610fa060045afa1561325457611040516102a052611060516102c052610ea0516102e052612f93611080612731565b611080505b600101818118612eff575b505061064051610620517f12a7d4a99e6a8e491eb7429684890e803da2899b11916334f8486a84d538c99f6020806110005280611000016000610660518083528060061b6000826020811161325457801561302657905b8060061b610680018160061b602088010181518152602082015160208201525050600101818118612ffa575b50508201602001915050905081019050611000a3565b60206132836000396000513318156130d057602080610380526013610320527f4f4170703a206f6e6c7920656e64706f696e740000000000000000000000000061034052610320816103800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610360528060040161037cfd5b61016051610140516040526130e6610320612480565b610320511815613172576020806103a0526014610340527f4f4170703a20696e76616c69642073656e64657200000000000000000000000061036052610340816103a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b565b6007546131f65760208060e05260156080527f4f7261636c65206e6f7420636f6e66696775726564000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60075463939074b160805260405160a05260605160c052602060806044609c6000855af1613229573d600060003e3d6000fd5b3d602081183d60201002188060800160a011613254576080518060011c6132545760e0525060e05050565b600080fd039d196b10801300196b10ae00e3196b1005001a196b18da196b07b6191f0f4e18f9196b13491945144285582045bf25efe5ab076902e782feb39f957f66aaecf35cc443ea61cae57364633aa919328381182a1820a16576797065728300040300380000000000000000000000001a44076050125825900e736c501f859c50fe728c

Deployed Bytecode

0x60003560e01c60026015820660011b61325901601e39600051565b638da5cb5b811861003657346132545760015460405260206040f35b63bb0b6a53811861007357602436103417613254576004358060201c61325457604052600260405160205260005260406000205460605260206060f35b63ca5eb5e1811861196c57602436103417613254576004358060a01c613254576101005261009f61196e565b602061328360003960005163ca5eb5e1610120526101005161014052803b15613254576000610120602461013c6000855af16100e0573d600060003e3d6000fd5b50005b63f0350c0481186101d057602436103417613254576004358060a01c613254576101005261010f61196e565b610100516101bf576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a00160468160468460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b610100516040526101ce6119f5565b005b63bf23b95a811861196c576044361034176132545760043560040160208135116132545780356000816020811161325457801561022f57905b8060051b6020850101358060201c613254578160051b6101200152600101818118610209575b50508061010052505060243560040160208135116132545780356000816020811161325457801561028257905b8060051b6020850101358060a01c613254578160051b610540015260010181811861025c575b5050806105205250506000546002146132545760026000556102a261196e565b61052051610100511815610332576020806109a0526013610940527f496e76616c69642070656572206172726179730000000000000000000000000061096052610940816109a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610980528060040161099cfd5b6000610100516020811161325457801561039457905b806109405261094051610100518110156132545760051b610120015160405261094051610520518110156132545760051b6105400151606052610389611a2f565b600101818118610348575b50506003600055005b63b15e13ee81186103c45734613254576103b561196e565b60006040526103c26119f5565b005b6313137d65811861196c5760e3361115613254576004358060201c6132545761184052602435611860526044358060401c6132545761188052608435600401803560b781116132545750602081350180826118a037505060a4358060a01c613254576119805260c43560040180356040811161325457506060816119a037506000546002146132545760026000556118405161014052611860516101605261188051610180526064356101a05260206118a05101806101c0826118a060045afa156132545750611980516102a05260606102c060606119a060045afa15613254576104ad61303c565b60045461184051186107545760035461054257602080611a60526010611a00527f52656164206e6f7420656e61626c656400000000000000000000000000000000611a2052611a0081611a600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0611a405280600401611a5cfd5b604036611a003760406118a05118613254576118a0516118c00161190011613254576118c051611a40526118e051611a6052611a408051611a00526020810151611a205250611a2051156107af57611a20516009611a0051602052600052604060002055611a0051604052611a20516060526105bc613174565b60086064356020526000526040600020805460208160061b01600081601f0160051c6041811161325457801561060657905b808501548160051b611a4001526001018181186105ee575b5050505060418101546122605260428101546122805250611a4051156107af5760006122a0526000611a40516020811161325457801561067f57905b8060061b611a600180516122c05260208101516122e052506122a0516122e05180820182811061325457905090506122a052600101818118610642575b50506122a05134101561070e576020806123205260166122c0527f496e73756666696369656e74206d73672e76616c7565000000000000000000006122e0526122c0816123200181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612300528060040161231cfd5b611a005161062052611a205161064052611a405160208160061b018061066082611a4060045afa1561325457505061226051610e805261228051610ea0526107af612e4a565b604036611a003760406118a05118613254576118a0516118c00161190011613254576118c051611a40526118e051611a6052611a408051611a00526020810151611a205250611a0051604052611a20516060526107af613174565b6003600055005b635e280f1181186107d4573461325457602061328360403960206040f35b636eb7385a81186109b157604436103417613254576004358060801c61325457610d20526024358060801c61325457610d4052600054600214613254576003546108c057602080610de0526027610d60527f52656164206e6f7420656e61626c6564202d2063616c6c207365745f72656164610d80527f5f636f6e66696700000000000000000000000000000000000000000000000000610da052610d6081610de00160478160478460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610dc05280600401610ddcfd5b6000610980526108d1610e40612006565b610e40602081510180610d60828460045afa156132545750506108f5610ea061210f565b610ea06056610e4060568360045afa15613254575060566102206056610e4060045afa1561325457610d20516102805260406102a052610d40516102c05261093e610ea061236a565b610ea06056610f0060568360045afa1561325457506056610e406056610f0060045afa15613254576020600454610140526020610d6051018061016082610d6060045afa15613254575060566102406056610e4060045afa156132545760006102a0526109ac610ea061251e565b610ea0f35b63994283aa811861196c57606336111561325457600435600401602081351161325457803560008160208111613254578015610a0f57905b8060051b6020850101358060201c613254578160051b61186001526001018181186109e9575b505080611840525050602435600401602081351161325457803560208160051b018083611c60375050506044358060801c6132545761208052600054600214613254576002600055600354610b065760208061212052602b6120a0527f43616e206f6e6c792062726f6164636173742066726f6d20726561642d656e616120c0527f626c656420636861696e730000000000000000000000000000000000000000006120e0526120a08161212001604b81604b8460045afa15613254578051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612100528060040161211cfd5b600754610b8f576020806121005260156120a0527f4f7261636c65206e6f7420636f6e6669677572656400000000000000000000006120c0526120a0816121000181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06120e052806004016120fcfd5b611c6051611840511815610c1f5760208061210052600f6120a0527f4c656e677468206d69736d6174636800000000000000000000000000000000006120c0526120a0816121000181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06120e052806004016120fcfd5b60075463017a494d6120c05260206120c060046120dc845afa610c47573d600060003e3d6000fd5b60203d10613254576120c09050516120a052600754639724283f6120e0526120a0516121005260206120e060246120fc845afa610c89573d600060003e3d6000fd5b60203d10613254576120e09050516120c0526120c051610d25576020806121405260136120e0527f4e6f20636f6e6669726d656420626c6f636b7300000000000000000000000000612100526120e0816121400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612120528060040161213cfd5b6120c05160096120a0516020526000526040600020541815610dc35760208061214052600e6120e0527f556e6b6e6f776e20736f75726365000000000000000000000000000000000000612100526120e0816121400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612120528060040161213cfd5b60006120e05260006129005260006118405160208111613254578015610e7557905b80612920526120e051601f8111613254578060061b6121000161292051611840518110156132545760051b6118600151815261292051611c60518110156132545760051b611c800151602082015250600181016120e052506129005161292051611c60518110156132545760051b611c800151808201828110613254579050905061290052600101818118610de5575b505034612900511115610f045760208061298052601a612920527f496e73756666696369656e74206d6573736167652076616c756500000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b6120a051610620526120c051610640526120e05160208160061b0180610660826120e060045afa1561325457505061208051610e805233610ea052610f47612e4a565b6003600055005b633400288b8118610f9157604436103417613254576004358060201c6132545761010052610f7a61196e565b61010051604052602435606052610f8f611a2f565b005b6382413eac811861196c5760a436103417613254576004358060201c613254576040526024356060526044358060401c61325457608052606435600401803560b7811161325457506020813501808260a03750506084358060a01c61325457610180523061018051146101a05260206101a0f35b63ff7bd03d811861105a57606436103417613254576004358060201c613254576040526024356060526044358060401c6132545760805260605160026040516020526000526040600020541460a052602060a0f35b638d001316811861196c5734613254576000546002146132545760045460405260206040f35b637d25a05e811861196c57604436103417613254576004358060201c61325457604052600060605260206060f35b632be655cd811861196c57608436103417613254576004358060011c61325457610100526024358060201c61325457610120526044358060201c61325457610140526064358060a01c613254576101605260005460021461325457600260005561111661196e565b63fffff9bf6101205112156111a7576020806101e0526014610180527f496e76616c69642072656164206368616e6e656c0000000000000000000000006101a052610180816101e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101c052806004016101dcfd5b610100516111b65760006111cd565b61014051156111ca576101605115156111cd565b60005b6111f957610100516111f257610140516111eb5761016051156111fc565b60006111fc565b60006111fc565b60015b611282576020806101e0526013610180527f496e76616c6964207265616420636f6e666967000000000000000000000000006101a052610180816101e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101c052806004016101dcfd5b60035461129057600061129a565b6101205160045414155b156112b25760045460405260006060526112b2611a2f565b61010051600355610120516004556101405160055561016051600655610100516112dd5760006112df565b305b6101805261012051604052610180516060526112f9611a2f565b6003600055005b63bd0a2294811861196c57602436103417613254576004358060a01c613254576101005260005460021461325457600260005561133b61196e565b610100516007556003600055005b6330a95e67811861141c576024361034176132545760005460021461325457600260005561137561196e565b60043547101561140157602080610160526014610100527f496e73756666696369656e742062616c616e636500000000000000000000000061012052610100816101600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b6000600060006000600435336000f115613254576003600055005b633516c5be811861196c5734613254576000546002146132545760035460405260206040f35b63742a6dcb81186116a157604436103417613254576004356004016020813511613254578035600081602081116132545780156114a157905b8060051b6020850101358060201c613254578160051b610540015260010181811861147b575b5050806105205250506024358060801c613254576109405260005460021461325457604036610a60376040610a4052610a40606061096060608360045afa1561325457506000610a40526114f6610ec061210f565b610ec06056610e6060568360045afa15613254575060566102206056610e6060045afa1561325457610940516102805260006102a052611537610ec0612638565b610ec06056610f2060568360045afa1561325457506056610e606056610f2060045afa15613254576000610520516020811161325457801561164057905b8060051b6105400151610ec0526002610ec051602052600052604060002054610ee052610ee0516115c557610a4051601f81116132545760008160051b610a60015260018101610a405250611635565b610ec0516101405260206109605101806101608261096060045afa15613254575060566102406056610e6060045afa156132545760006102a05261160a610f0061251e565b610f0051610f4052610a4051601f811161325457610f40518160051b610a60015260018101610a4052505b600101818118611575575b5050602080610ec05280610ec0016000610a40518083528060051b6000826020811161325457801561168c57905b8060051b610a6001518160051b60208801015260010181811861166e575b50508201602001915050905081019050610ec0f35b6341930981811861196c5760a336111561325457608435612900525b60043560040160208135116132545780356000816020811161325457801561170757905b8060051b6020850101358060201c613254578160051b6120a001526001018181186116e1575b505080612080525050602435600401602081351161325457803560208160051b0180836124a0375050506044358060801c613254576128c0526064358060801c613254576128e0526000546002146132545760026000556003546117e757602080612980526010612920527f52656164206e6f7420656e61626c65640000000000000000000000000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b6124a0516120805118156118775760208061298052600f612920527f4c656e677468206d69736d61746368000000000000000000000000000000000061294052612920816129800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0612960528060040161297cfd5b61290051610d20526120805160208160051b0180610d408261208060045afa156132545750506124a05160208160051b0180611160826124a060045afa156132545750506128c051611580526128e0516115a0526118d3612b71565b6003600055005b63b5775a2c811861196c576083361115613254576000612900526116bd565b63b5c3cbd0811861196c5734613254576000546002146132545760055460405260206040f35b6386e39385811861196c5734613254576000546002146132545760065460405260206040f35b636959a37f811861196c5734613254576000546002146132545760075460405260206040f35b5b005b6001543318156119f35760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b6001546060526040516001556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060006080a3565b60605160026040516020526000526040600020557f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b60405160805260605160a05260406080a1565b60b760405160448101818110613254579050602a81018181106132545790501115611b1e576020806102c0526017610260527f4f4170703a20436f6d6d616e6420746f6f206c6172676500000000000000000061028052610260816102c00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06102a052806004016102bcfd5b600060496040511161325457604080516020820183610280018281848460045afa1561325457505080830192505050600160f81b816102800152600181019050610120518060f01b9050816102800152600281019050600160f01b8161028001526002810190506101e051602381018181106132545790508060101c613254578060f01b9050816102800152600281019050610140518060e01b9050816102800152600481019050610160518060f81b9050816102800152600181019050610180518060c01b90508161028001526008810190506101a0518060f01b90508161028001526002810190506101c0518060601b90508161028001526014810190506101e051816102800181818361020060045afa1561325457508082019150508061026052610260905060208151018083828460045afa1561325457505050565b60b7604051602781018181106132545790501115611cf8576020806102405260176101e0527f4f4170703a20436f6d6d616e6420746f6f206c61726765000000000000000000610200526101e0816102400181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610220528060040161023cfd5b600060906040511161325457604080516020820183610200018281848460045afa1561325457505080830192505050600160f81b816102000152600181019050600160f01b816102000152600281019050610120518060f81b9050816102000152600181019050610140518060e01b9050816102000152600481019050610160518060f81b9050816102000152600181019050610180518060c01b90508161020001526008810190506101a0518060f01b90508161020001526002810190506101c0518060601b9050816102000152601481019050806101e0526101e0905060208151018083828460045afa1561325457505050565b6000600160f01b816106a00152600281019050610360518060f01b9050816106a00152600281019050610380518060101c613254578060f01b9050816106a001526002810190508061068052610680905080516105a05260208101516105c0525060006103805160018111613254578015611f5b57905b61014081026103a00180516106805260208101516106a05260408101516106c05260608101516106e05260808101516107005260a08101516107205260c08101606461074060648360045afa1561325457505060206105a05101806040826105a060045afa15613254575061068051610120526106a051610140526106c051610160526106e05161018052610700516101a052610720516101c05260646101e0606461074060045afa1561325457611f1e6107c0611a77565b6107c06020815101806108a0828460045afa1561325457505060206108a05101806105a0826108a060045afa156132545750600101818118611e65575b50506105005115611fec5760206105a05101806040826105a060045afa1561325457506104e05161012052610500516101405261052051610160526105405161018052610560516101a052610580516101c052611fb9610680611c5e565b610680602081510180610760828460045afa1561325457505060206107605101806105a08261076060045afa1561325457505b60206105a051018082826105a060045afa15613254575050565b637b754d2d610a2452600461098051610a44526001610a6452604001610a2052610a2060646109a060648360045afa1561325457506001610a2052600554610a40526000610a6052428060401c61325457610a80526001610aa052600654610ac0526064610ae060646109a060045afa1561325457600161036052610a20516103a052610a40516103c052610a60516103e052610a805161040052610aa05161042052610ac0516104405260646104606064610ae060045afa156132545760016103805260c0366104e0376120dc610c40611dee565b610c40602081510180610b60828460045afa156132545750506020610b605101808282610b6060045afa15613254575050565b6000600360f01b8160e001526002810190506020600060a05260a0018160e00150508060c05260c0905080516040526020810151606052506056816056604060045afa156132545750565b60036001604051111561325457606051610140526002610120526101206020810151815160200360031b1c9050181561220f576020806101c0526019610160527f4f4170703a20696e76616c6964206f7074696f6e20747970650000000000000061018052610160816101c00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06101a052806004016101bcfd5b603660405160c05180820182811061325457905090506004810181811061325457905011156122ba5760208061018052601b610120527f4f4170703a206f7074696f6e732073697a65206578636565646564000000000061014052610120816101800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b6000600260405111613254576040805160208201836101400181518152505080830192505050600160f81b81610140015260018101905060c051600181018181106132545790508060101c613254578060f01b905081610140015260028101905060a0518060f81b905081610140015260018101905060c051816101400181818360e060045afa1561325457508082019150508061012052610120905060568260568360045afa15613254575050565b60006102e052610280518060801b9050610340526102a0518060e01b90506103605260016102c05112156123d957600061034051816103a0015260108101905061036051816103a001526004810190508061038052610380905080516102e05260208101516103005250612436565b6102c0518060801b905061038052600061034051816103c0015260108101905061036051816103c0015260048101905061038051816103c00152601081019050806103a0526103a0905060446102e060448360045afa1561325457505b60566040605661022060045afa1561325457600560a052605060c060506102e060045afa156132545761246a61038061215a565b61038060568260568360045afa15613254575050565b60026040516020526000526040600020546060526060516125165760208060e052600d6080527f4f4170703a206e6f20706565720000000000000000000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b606051815250565b602061328360003960005163ddc28c586102e05260408061030052806103000160a0610140518252610140516040526125586102c0612480565b6102c05160208301528060408301528082016020610160510180828261016060045afa1561325457508051806020830101601f82600003163682375050601f19601f82516020010116905081019050806060830152808201605681605661024060045afa15613254578051806020830101601f82600003163682375050601f19601f825160200101169050810190506102a051608083015290508101905030610320525060406102e06102246102fc845afa612619573d600060003e3d6000fd5b60403d10613254576102e0905080518252602081015160208301525050565b60006102c052610280518060801b90506103205260016102a051121561269c57600061032051816103800152601081019050602060006103405261034001816103800150508061036052610360905080516102c05260208101516102e052506126e7565b6102a0518060801b905061034052600061032051816103800152601081019050610340518161038001526010810190508061036052610360905080516102c05260208101516102e052505b60566040605661022060045afa1561325457600160a052605060c060506102c060045afa156132545761271b61034061215a565b61034060568260568360045afa15613254575050565b61014051604052612743610320612480565b61032051610300526102a0516103205261032051156127e957610320513410156127e9576020806103a0526014610340527f4f4170703a206e6f7420656e6f7567682066656500000000000000000000000061036052610340816103a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b6102c0516103405261034051156129f557602061328360003960005163e4fe1d94610380526020610380600461039c845afa61282a573d600060003e3d6000fd5b3d602081183d602010021880610380016103a01161325457610380518060a01c613254576103c052506103c090505161036052610360516128e7576020806103e052601a610380527f4f4170703a204c5a20746f6b656e20756e617661696c61626c650000000000006103a052610380816103e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a06103c052806004016103dcfd5b610360516323b872dd61038052336103a05260206132836103c039610340516103e0526020610380606461039c6000855af1612928573d600060003e3d6000fd5b3d61293f57803b1561325457600161040052612969565b3d602081183d602010021880610380016103a01161325457610380518060011c6132545761040052505b6104009050516129f55760208061048052601b610420527f4f4170703a20746f6b656e207472616e73666572206661696c6564000000000061044052610420816104800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610460528060040161047cfd5b6020613283600039600051632637a4506103605260408061038052806103800160a06101405182526103005160208301528060408301528082016020610160510180828261016060045afa1561325457508051806020830101601f82600003163682375050601f19601f82516020010116905081019050806060830152808201605681605661024060045afa15613254578051806020830101601f82600003163682375050601f19601f825160200101169050810190506102c051151560808301529050810190506102e0516103a05250608061036061022461037c61032051855af1612ae7573d600060003e3d6000fd5b3d608081183d608010021880610360016103e0116132545780610360016103e01161325457610360516105a052610380518060401c613254576105c05280610360016103e011613254576103a0516105e0526103c05161060052506105a0905080518252602081015160208301526040810160408301815181526020820151602082015250505050565b60006115c0526000611de0526000610d405160208111613254578015612c2357905b80611e00526115c051601f8111613254578060061b6115e001611e0051610d40518110156132545760051b610d6001518152611e0051611160518110156132545760051b6111800151602082015250600181016115c05250611de051611e0051611160518110156132545760051b61118001518082018281106132545790509050611de052600101818118612b93575b505034611de0511115612cb257602080611e60526012611e00527f496e73756666696369656e742076616c75650000000000000000000000000000611e2052611e0081611e600181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0611e405280600401611e5cfd5b610d205161098052612cc5611ee0612006565b611ee0602081510180611e00828460045afa15613254575050612ce9611f4061210f565b611f406056611ee060568360045afa15613254575060566102206056611ee060045afa15613254576115a0516102805260406102a052611de0518060801c613254576102c052612d3a611f4061236a565b611f406056611fa060568360045afa1561325457506056611ee06056611fa060045afa156132545734611f40526000611f6052600454610140526020611e0051018061016082611e0060045afa15613254575060566102406056611ee060045afa1561325457611f40516102a052611f60516102c052336102e052612dc0612000612731565b6120008051611f80526020810151611fa052604081018051611fc0526020810151611fe05250506008611f805160205260005260406000206115c05160208160061b01600081601f0160051c60418111613254578015612e3457905b8060051b6115c0015181860155600101818118612e1c575b5050505061158051604182015533604282015550565b61062051610fc05261064051610fe0526040610fa052610fa06060610ec060608360045afa156132545750612e8061100061210f565b6110006056610fa060568360045afa15613254575060566102206056610fa060045afa1561325457610e80516102805260006102a052612ec1611000612638565b611000605661106060568360045afa1561325457506056610fa0605661106060045afa156132545760006106605160208111613254578015612fa357905b8060061b610680018051611000526020810151611020525060026110005160205260005260406000205415612f9857611020516110405260006110605261100051610140526020610ec051018061016082610ec060045afa15613254575060566102406056610fa060045afa1561325457611040516102a052611060516102c052610ea0516102e052612f93611080612731565b611080505b600101818118612eff575b505061064051610620517f12a7d4a99e6a8e491eb7429684890e803da2899b11916334f8486a84d538c99f6020806110005280611000016000610660518083528060061b6000826020811161325457801561302657905b8060061b610680018160061b602088010181518152602082015160208201525050600101818118612ffa575b50508201602001915050905081019050611000a3565b60206132836000396000513318156130d057602080610380526013610320527f4f4170703a206f6e6c7920656e64706f696e740000000000000000000000000061034052610320816103800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610360528060040161037cfd5b61016051610140516040526130e6610320612480565b610320511815613172576020806103a0526014610340527f4f4170703a20696e76616c69642073656e64657200000000000000000000000061036052610340816103a00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b565b6007546131f65760208060e05260156080527f4f7261636c65206e6f7420636f6e66696775726564000000000000000000000060a05260808160e00181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60075463939074b160805260405160a05260605160c052602060806044609c6000855af1613229573d600060003e3d6000fd5b3d602081183d60201002188060800160a011613254576080518060011c6132545760e0525060e05050565b600080fd039d196b10801300196b10ae00e3196b1005001a196b18da196b07b6191f0f4e18f9196b1349194514420000000000000000000000001a44076050125825900e736c501f859c50fe728c

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001a44076050125825900e736c501f859c50fe728c

-----Decoded View---------------
Arg [0] : _endpoint (address): 0x1a44076050125825900e736c501f859c50fE728c

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001a44076050125825900e736c501f859c50fe728c


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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