MOVR Price: $21.56 (-0.72%)
Gas: 3 GWei

Contract

0x69663Eb604C7d534e9149fa855D89d9104E75363

Overview

MOVR Balance

Moonriver Chain LogoMoonriver Chain LogoMoonriver Chain Logo0 MOVR

MOVR Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60a0604030341702022-11-21 9:29:00493 days ago1669022940IN
 Contract Creation
0 MOVR0.003590831

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
MessageBus

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 12 : MessageBus.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.17;

import "./MessageBusSender.sol";
import "./MessageBusReceiver.sol";

contract MessageBus is MessageBusSender, MessageBusReceiver {
    constructor(
        ISigsVerifier _sigsVerifier,
        address _liquidityBridge,
        address _pegBridge,
        address _pegVault,
        address _pegBridgeV2,
        address _pegVaultV2
    )
        MessageBusSender(_sigsVerifier)
        MessageBusReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2)
    {}

    // this is only to be called by Proxy via delegateCall as initOwner will require _owner is 0.
    // so calling init on this contract directly will guarantee to fail
    function init(
        address _liquidityBridge,
        address _pegBridge,
        address _pegVault,
        address _pegBridgeV2,
        address _pegVaultV2
    ) external {
        // MUST manually call ownable init and must only call once
        initOwner();
        // we don't need sender init as _sigsVerifier is immutable so already in the deployed code
        initReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2);
    }
}

File 2 of 12 : MessageBusSender.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.17;

import "../../safeguard/Ownable.sol";
import "../../interfaces/ISigsVerifier.sol";

contract MessageBusSender is Ownable {
    ISigsVerifier public immutable sigsVerifier;

    uint256 public feeBase;
    uint256 public feePerByte;
    mapping(address => uint256) public withdrawnFees;

    event Message(address indexed sender, address receiver, uint256 dstChainId, bytes message, uint256 fee);
    // message to non-evm chain with >20 bytes addr
    event Message2(address indexed sender, bytes receiver, uint256 dstChainId, bytes message, uint256 fee);

    event MessageWithTransfer(
        address indexed sender,
        address receiver,
        uint256 dstChainId,
        address bridge,
        bytes32 srcTransferId,
        bytes message,
        uint256 fee
    );

    event FeeWithdrawn(address receiver, uint256 amount);

    event FeeBaseUpdated(uint256 feeBase);
    event FeePerByteUpdated(uint256 feePerByte);

    constructor(ISigsVerifier _sigsVerifier) {
        sigsVerifier = _sigsVerifier;
    }

    /**
     * @notice Sends a message to a contract on another chain.
     * Sender needs to make sure the uniqueness of the message Id, which is computed as
     * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message).
     * If messages with the same Id are sent, only one of them will succeed at dst chain.
     * A fee is charged in the native gas token.
     * @param _receiver The address of the destination app contract.
     * @param _dstChainId The destination chain ID.
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
     */
    function sendMessage(
        address _receiver,
        uint256 _dstChainId,
        bytes calldata _message
    ) external payable {
        _sendMessage(_dstChainId, _message);
        emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value);
    }

    // Send message to non-evm chain with bytes for receiver address,
    // otherwise same as above.
    function sendMessage(
        bytes calldata _receiver,
        uint256 _dstChainId,
        bytes calldata _message
    ) external payable {
        _sendMessage(_dstChainId, _message);
        emit Message2(msg.sender, _receiver, _dstChainId, _message, msg.value);
    }

    function _sendMessage(uint256 _dstChainId, bytes calldata _message) private {
        require(_dstChainId != block.chainid, "Invalid chainId");
        uint256 minFee = calcFee(_message);
        require(msg.value >= minFee, "Insufficient fee");
    }

    /**
     * @notice Sends a message associated with a transfer to a contract on another chain.
     * If messages with the same srcTransferId are sent, only one of them will succeed.
     * A fee is charged in the native token.
     * @param _receiver The address of the destination app contract.
     * @param _dstChainId The destination chain ID.
     * @param _srcBridge The bridge contract to send the transfer with.
     * @param _srcTransferId The transfer ID.
     * @param _dstChainId The destination chain ID.
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
     */
    function sendMessageWithTransfer(
        address _receiver,
        uint256 _dstChainId,
        address _srcBridge,
        bytes32 _srcTransferId,
        bytes calldata _message
    ) external payable {
        require(_dstChainId != block.chainid, "Invalid chainId");
        uint256 minFee = calcFee(_message);
        require(msg.value >= minFee, "Insufficient fee");
        // SGN needs to verify
        // 1. msg.sender matches sender of the src transfer
        // 2. dstChainId matches dstChainId of the src transfer
        // 3. bridge is either liquidity bridge, peg src vault, or peg dst bridge
        emit MessageWithTransfer(msg.sender, _receiver, _dstChainId, _srcBridge, _srcTransferId, _message, msg.value);
    }

    /**
     * @notice Withdraws message fee in the form of native gas token.
     * @param _account The address receiving the fee.
     * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be
     * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function withdrawFee(
        address _account,
        uint256 _cumulativeFee,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external {
        bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "withdrawFee"));
        sigsVerifier.verifySigs(abi.encodePacked(domain, _account, _cumulativeFee), _sigs, _signers, _powers);
        uint256 amount = _cumulativeFee - withdrawnFees[_account];
        require(amount > 0, "No new amount to withdraw");
        withdrawnFees[_account] = _cumulativeFee;
        (bool sent, ) = _account.call{value: amount, gas: 50000}("");
        require(sent, "failed to withdraw fee");
        emit FeeWithdrawn(_account, amount);
    }

    /**
     * @notice Calculates the required fee for the message.
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
     @ @return The required fee.
     */
    function calcFee(bytes calldata _message) public view returns (uint256) {
        return feeBase + _message.length * feePerByte;
    }

    // -------------------- Admin --------------------

    function setFeePerByte(uint256 _fee) external onlyOwner {
        feePerByte = _fee;
        emit FeePerByteUpdated(feePerByte);
    }

    function setFeeBase(uint256 _fee) external onlyOwner {
        feeBase = _fee;
        emit FeeBaseUpdated(feeBase);
    }
}

File 3 of 12 : MessageBusReceiver.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.9;

import "../libraries/MsgDataTypes.sol";
import "../interfaces/IMessageReceiverApp.sol";
import "../../interfaces/IBridge.sol";
import "../../interfaces/IOriginalTokenVault.sol";
import "../../interfaces/IOriginalTokenVaultV2.sol";
import "../../interfaces/IPeggedTokenBridge.sol";
import "../../interfaces/IPeggedTokenBridgeV2.sol";
import "../../safeguard/Ownable.sol";

contract MessageBusReceiver is Ownable {
    mapping(bytes32 => MsgDataTypes.TxStatus) public executedMessages;

    address public liquidityBridge; // liquidity bridge address
    address public pegBridge; // peg bridge address
    address public pegVault; // peg original vault address
    address public pegBridgeV2; // peg bridge address
    address public pegVaultV2; // peg original vault address

    // minimum amount of gas needed by this contract before it tries to
    // deliver a message to the target contract.
    uint256 public preExecuteMessageGasUsage;

    event Executed(
        MsgDataTypes.MsgType msgType,
        bytes32 msgId,
        MsgDataTypes.TxStatus status,
        address indexed receiver,
        uint64 srcChainId,
        bytes32 srcTxHash
    );
    event NeedRetry(MsgDataTypes.MsgType msgType, bytes32 msgId, uint64 srcChainId, bytes32 srcTxHash);
    event CallReverted(string reason); // help debug

    event LiquidityBridgeUpdated(address liquidityBridge);
    event PegBridgeUpdated(address pegBridge);
    event PegVaultUpdated(address pegVault);
    event PegBridgeV2Updated(address pegBridgeV2);
    event PegVaultV2Updated(address pegVaultV2);

    constructor(
        address _liquidityBridge,
        address _pegBridge,
        address _pegVault,
        address _pegBridgeV2,
        address _pegVaultV2
    ) {
        liquidityBridge = _liquidityBridge;
        pegBridge = _pegBridge;
        pegVault = _pegVault;
        pegBridgeV2 = _pegBridgeV2;
        pegVaultV2 = _pegVaultV2;
    }

    function initReceiver(
        address _liquidityBridge,
        address _pegBridge,
        address _pegVault,
        address _pegBridgeV2,
        address _pegVaultV2
    ) internal {
        require(liquidityBridge == address(0), "liquidityBridge already set");
        liquidityBridge = _liquidityBridge;
        pegBridge = _pegBridge;
        pegVault = _pegVault;
        pegBridgeV2 = _pegBridgeV2;
        pegVaultV2 = _pegVaultV2;
    }

    // ============== functions called by executor ==============

    /**
     * @notice Execute a message with a successful transfer.
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _transfer The transfer info.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function executeMessageWithTransfer(
        bytes calldata _message,
        MsgDataTypes.TransferInfo calldata _transfer,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) public payable {
        // For message with token transfer, message Id is computed through transfer info
        // in order to guarantee that each transfer can only be used once.
        bytes32 messageId = verifyTransfer(_transfer);
        require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed");
        executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;

        bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransfer"));
        IBridge(liquidityBridge).verifySigs(
            abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash),
            _sigs,
            _signers,
            _powers
        );
        MsgDataTypes.TxStatus status;
        IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransfer(_transfer, _message);
        if (est == IMessageReceiverApp.ExecutionStatus.Success) {
            status = MsgDataTypes.TxStatus.Success;
        } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
            executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
            emit NeedRetry(
                MsgDataTypes.MsgType.MessageWithTransfer,
                messageId,
                _transfer.srcChainId,
                _transfer.srcTxHash
            );
            return;
        } else {
            est = executeMessageWithTransferFallback(_transfer, _message);
            if (est == IMessageReceiverApp.ExecutionStatus.Success) {
                status = MsgDataTypes.TxStatus.Fallback;
            } else {
                status = MsgDataTypes.TxStatus.Fail;
            }
        }
        executedMessages[messageId] = status;
        emitMessageWithTransferExecutedEvent(messageId, status, _transfer);
    }

    /**
     * @notice Execute a message with a refunded transfer.
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _transfer The transfer info.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function executeMessageWithTransferRefund(
        bytes calldata _message, // the same message associated with the original transfer
        MsgDataTypes.TransferInfo calldata _transfer,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) public payable {
        // similar to executeMessageWithTransfer
        bytes32 messageId = verifyTransfer(_transfer);
        require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed");
        executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;

        bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransferRefund"));
        IBridge(liquidityBridge).verifySigs(
            abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash),
            _sigs,
            _signers,
            _powers
        );
        MsgDataTypes.TxStatus status;
        IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransferRefund(_transfer, _message);
        if (est == IMessageReceiverApp.ExecutionStatus.Success) {
            status = MsgDataTypes.TxStatus.Success;
        } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
            executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
            emit NeedRetry(
                MsgDataTypes.MsgType.MessageWithTransfer,
                messageId,
                _transfer.srcChainId,
                _transfer.srcTxHash
            );
            return;
        } else {
            status = MsgDataTypes.TxStatus.Fail;
        }
        executedMessages[messageId] = status;
        emitMessageWithTransferExecutedEvent(messageId, status, _transfer);
    }

    /**
     * @notice Execute a message not associated with a transfer.
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _route The info about the sender and the receiver.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function executeMessage(
        bytes calldata _message,
        MsgDataTypes.RouteInfo calldata _route,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external payable {
        MsgDataTypes.Route memory route = getRouteInfo(_route);
        executeMessage(_message, route, _sigs, _signers, _powers, "Message");
    }

    // execute message from non-evm chain with bytes for sender address,
    // otherwise same as above.
    function executeMessage(
        bytes calldata _message,
        MsgDataTypes.RouteInfo2 calldata _route,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external payable {
        MsgDataTypes.Route memory route = getRouteInfo(_route);
        executeMessage(_message, route, _sigs, _signers, _powers, "Message2");
    }

    function executeMessage(
        bytes calldata _message,
        MsgDataTypes.Route memory _route,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers,
        string memory domainName
    ) private {
        // For message without associated token transfer, message Id is computed through message info,
        // in order to guarantee that each message can only be applied once
        bytes32 messageId = computeMessageOnlyId(_route, _message);
        require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "message already executed");
        executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;

        bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), domainName));
        IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId), _sigs, _signers, _powers);
        MsgDataTypes.TxStatus status;
        IMessageReceiverApp.ExecutionStatus est = executeMessage(_route, _message);
        if (est == IMessageReceiverApp.ExecutionStatus.Success) {
            status = MsgDataTypes.TxStatus.Success;
        } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
            executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
            emit NeedRetry(MsgDataTypes.MsgType.MessageOnly, messageId, _route.srcChainId, _route.srcTxHash);
            return;
        } else {
            status = MsgDataTypes.TxStatus.Fail;
        }
        executedMessages[messageId] = status;
        emitMessageOnlyExecutedEvent(messageId, status, _route);
    }

    // ================= utils (to avoid stack too deep) =================

    function emitMessageWithTransferExecutedEvent(
        bytes32 _messageId,
        MsgDataTypes.TxStatus _status,
        MsgDataTypes.TransferInfo calldata _transfer
    ) private {
        emit Executed(
            MsgDataTypes.MsgType.MessageWithTransfer,
            _messageId,
            _status,
            _transfer.receiver,
            _transfer.srcChainId,
            _transfer.srcTxHash
        );
    }

    function emitMessageOnlyExecutedEvent(
        bytes32 _messageId,
        MsgDataTypes.TxStatus _status,
        MsgDataTypes.Route memory _route
    ) private {
        emit Executed(
            MsgDataTypes.MsgType.MessageOnly,
            _messageId,
            _status,
            _route.receiver,
            _route.srcChainId,
            _route.srcTxHash
        );
    }

    function executeMessageWithTransfer(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
        private
        returns (IMessageReceiverApp.ExecutionStatus)
    {
        uint256 gasLeftBeforeExecution = gasleft();
        (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
            abi.encodeWithSelector(
                IMessageReceiverApp.executeMessageWithTransfer.selector,
                _transfer.sender,
                _transfer.token,
                _transfer.amount,
                _transfer.srcChainId,
                _message,
                msg.sender
            )
        );
        if (ok) {
            return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
        }
        handleExecutionRevert(gasLeftBeforeExecution, res);
        return IMessageReceiverApp.ExecutionStatus.Fail;
    }

    function executeMessageWithTransferFallback(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
        private
        returns (IMessageReceiverApp.ExecutionStatus)
    {
        uint256 gasLeftBeforeExecution = gasleft();
        (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
            abi.encodeWithSelector(
                IMessageReceiverApp.executeMessageWithTransferFallback.selector,
                _transfer.sender,
                _transfer.token,
                _transfer.amount,
                _transfer.srcChainId,
                _message,
                msg.sender
            )
        );
        if (ok) {
            return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
        }
        handleExecutionRevert(gasLeftBeforeExecution, res);
        return IMessageReceiverApp.ExecutionStatus.Fail;
    }

    function executeMessageWithTransferRefund(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
        private
        returns (IMessageReceiverApp.ExecutionStatus)
    {
        uint256 gasLeftBeforeExecution = gasleft();
        (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
            abi.encodeWithSelector(
                IMessageReceiverApp.executeMessageWithTransferRefund.selector,
                _transfer.token,
                _transfer.amount,
                _message,
                msg.sender
            )
        );
        if (ok) {
            return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
        }
        handleExecutionRevert(gasLeftBeforeExecution, res);
        return IMessageReceiverApp.ExecutionStatus.Fail;
    }

    function verifyTransfer(MsgDataTypes.TransferInfo calldata _transfer) private view returns (bytes32) {
        bytes32 transferId;
        address bridgeAddr;
        if (_transfer.t == MsgDataTypes.TransferType.LqRelay) {
            transferId = keccak256(
                abi.encodePacked(
                    _transfer.sender,
                    _transfer.receiver,
                    _transfer.token,
                    _transfer.amount,
                    _transfer.srcChainId,
                    uint64(block.chainid),
                    _transfer.refId
                )
            );
            bridgeAddr = liquidityBridge;
            require(IBridge(bridgeAddr).transfers(transferId) == true, "bridge relay not exist");
        } else if (_transfer.t == MsgDataTypes.TransferType.LqWithdraw) {
            transferId = keccak256(
                abi.encodePacked(
                    uint64(block.chainid),
                    _transfer.wdseq,
                    _transfer.receiver,
                    _transfer.token,
                    _transfer.amount
                )
            );
            bridgeAddr = liquidityBridge;
            require(IBridge(bridgeAddr).withdraws(transferId) == true, "bridge withdraw not exist");
        } else if (
            _transfer.t == MsgDataTypes.TransferType.PegMint || _transfer.t == MsgDataTypes.TransferType.PegWithdraw
        ) {
            transferId = keccak256(
                abi.encodePacked(
                    _transfer.receiver,
                    _transfer.token,
                    _transfer.amount,
                    _transfer.sender,
                    _transfer.srcChainId,
                    _transfer.refId
                )
            );
            if (_transfer.t == MsgDataTypes.TransferType.PegMint) {
                bridgeAddr = pegBridge;
                require(IPeggedTokenBridge(bridgeAddr).records(transferId) == true, "mint record not exist");
            } else {
                // _transfer.t == MsgDataTypes.TransferType.PegWithdraw
                bridgeAddr = pegVault;
                require(IOriginalTokenVault(bridgeAddr).records(transferId) == true, "withdraw record not exist");
            }
        } else if (
            _transfer.t == MsgDataTypes.TransferType.PegV2Mint || _transfer.t == MsgDataTypes.TransferType.PegV2Withdraw
        ) {
            if (_transfer.t == MsgDataTypes.TransferType.PegV2Mint) {
                bridgeAddr = pegBridgeV2;
            } else {
                // MsgDataTypes.TransferType.PegV2Withdraw
                bridgeAddr = pegVaultV2;
            }
            transferId = keccak256(
                abi.encodePacked(
                    _transfer.receiver,
                    _transfer.token,
                    _transfer.amount,
                    _transfer.sender,
                    _transfer.srcChainId,
                    _transfer.refId,
                    bridgeAddr
                )
            );
            if (_transfer.t == MsgDataTypes.TransferType.PegV2Mint) {
                require(IPeggedTokenBridgeV2(bridgeAddr).records(transferId) == true, "mint record not exist");
            } else {
                // MsgDataTypes.TransferType.PegV2Withdraw
                require(IOriginalTokenVaultV2(bridgeAddr).records(transferId) == true, "withdraw record not exist");
            }
        }
        return keccak256(abi.encodePacked(MsgDataTypes.MsgType.MessageWithTransfer, bridgeAddr, transferId));
    }

    function computeMessageOnlyId(MsgDataTypes.Route memory _route, bytes calldata _message)
        private
        view
        returns (bytes32)
    {
        bytes memory sender = _route.senderBytes;
        if (sender.length == 0) {
            sender = abi.encodePacked(_route.sender);
        }
        return
            keccak256(
                abi.encodePacked(
                    MsgDataTypes.MsgType.MessageOnly,
                    sender,
                    _route.receiver,
                    _route.srcChainId,
                    _route.srcTxHash,
                    uint64(block.chainid),
                    _message
                )
            );
    }

    function executeMessage(MsgDataTypes.Route memory _route, bytes calldata _message)
        private
        returns (IMessageReceiverApp.ExecutionStatus)
    {
        uint256 gasLeftBeforeExecution = gasleft();
        bool ok;
        bytes memory res;
        if (_route.senderBytes.length == 0) {
            (ok, res) = address(_route.receiver).call{value: msg.value}(
                abi.encodeWithSelector(
                    bytes4(keccak256(bytes("executeMessage(address,uint64,bytes,address)"))),
                    _route.sender,
                    _route.srcChainId,
                    _message,
                    msg.sender
                )
            );
        } else {
            (ok, res) = address(_route.receiver).call{value: msg.value}(
                abi.encodeWithSelector(
                    bytes4(keccak256(bytes("executeMessage(bytes,uint64,bytes,address)"))),
                    _route.senderBytes,
                    _route.srcChainId,
                    _message,
                    msg.sender
                )
            );
        }
        if (ok) {
            return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
        }
        handleExecutionRevert(gasLeftBeforeExecution, res);
        return IMessageReceiverApp.ExecutionStatus.Fail;
    }

    function handleExecutionRevert(uint256 _gasLeftBeforeExecution, bytes memory _returnData) private {
        uint256 gasLeftAfterExecution = gasleft();
        uint256 maxTargetGasLimit = block.gaslimit - preExecuteMessageGasUsage;
        if (_gasLeftBeforeExecution < maxTargetGasLimit && gasLeftAfterExecution <= _gasLeftBeforeExecution / 64) {
            // if this happens, the executor must have not provided sufficient gas limit,
            // then the tx should revert instead of recording a non-retryable failure status
            // https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-f-gas-to-send-with-call-operations
            assembly {
                invalid()
            }
        }
        string memory revertMsg = getRevertMsg(_returnData);
        // revert the execution if the revert message has the ABORT prefix
        checkAbortPrefix(revertMsg);
        // otherwiase, emit revert message, return and mark the execution as failed (non-retryable)
        emit CallReverted(revertMsg);
    }

    // https://ethereum.stackexchange.com/a/83577
    // https://github.com/Uniswap/v3-periphery/blob/v1.0.0/contracts/base/Multicall.sol
    function getRevertMsg(bytes memory _returnData) private pure returns (string memory) {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (_returnData.length < 68) return "Transaction reverted silently";
        assembly {
            // Slice the sighash.
            _returnData := add(_returnData, 0x04)
        }
        return abi.decode(_returnData, (string)); // All that remains is the revert string
    }

    function checkAbortPrefix(string memory _revertMsg) private pure {
        bytes memory prefixBytes = bytes(MsgDataTypes.ABORT_PREFIX);
        bytes memory msgBytes = bytes(_revertMsg);
        if (msgBytes.length >= prefixBytes.length) {
            for (uint256 i = 0; i < prefixBytes.length; i++) {
                if (msgBytes[i] != prefixBytes[i]) {
                    return; // prefix not match, return
                }
            }
            revert(_revertMsg); // prefix match, revert
        }
    }

    function getRouteInfo(MsgDataTypes.RouteInfo calldata _route) private pure returns (MsgDataTypes.Route memory) {
        return MsgDataTypes.Route(_route.sender, "", _route.receiver, _route.srcChainId, _route.srcTxHash);
    }

    function getRouteInfo(MsgDataTypes.RouteInfo2 calldata _route) private pure returns (MsgDataTypes.Route memory) {
        return MsgDataTypes.Route(address(0), _route.sender, _route.receiver, _route.srcChainId, _route.srcTxHash);
    }

    // ================= helper functions =====================

    /**
     * @notice combine bridge transfer and msg execution calls into a single tx
     * @dev caller needs to get the required input params from SGN
     * @param _transferParams params to call bridge transfer
     * @param _msgParams params to execute message
     */
    function transferAndExecuteMsg(
        MsgDataTypes.BridgeTransferParams calldata _transferParams,
        MsgDataTypes.MsgWithTransferExecutionParams calldata _msgParams
    ) external {
        _bridgeTransfer(_msgParams.transfer.t, _transferParams);
        executeMessageWithTransfer(
            _msgParams.message,
            _msgParams.transfer,
            _msgParams.sigs,
            _msgParams.signers,
            _msgParams.powers
        );
    }

    /**
     * @notice combine bridge refund and msg execution calls into a single tx
     * @dev caller needs to get the required input params from SGN
     * @param _transferParams params to call bridge transfer for refund
     * @param _msgParams params to execute message for refund
     */
    function refundAndExecuteMsg(
        MsgDataTypes.BridgeTransferParams calldata _transferParams,
        MsgDataTypes.MsgWithTransferExecutionParams calldata _msgParams
    ) external {
        _bridgeTransfer(_msgParams.transfer.t, _transferParams);
        executeMessageWithTransferRefund(
            _msgParams.message,
            _msgParams.transfer,
            _msgParams.sigs,
            _msgParams.signers,
            _msgParams.powers
        );
    }

    function _bridgeTransfer(MsgDataTypes.TransferType t, MsgDataTypes.BridgeTransferParams calldata _transferParams)
        private
    {
        if (t == MsgDataTypes.TransferType.LqRelay) {
            IBridge(liquidityBridge).relay(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        } else if (t == MsgDataTypes.TransferType.LqWithdraw) {
            IBridge(liquidityBridge).withdraw(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        } else if (t == MsgDataTypes.TransferType.PegMint) {
            IPeggedTokenBridge(pegBridge).mint(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        } else if (t == MsgDataTypes.TransferType.PegV2Mint) {
            IPeggedTokenBridgeV2(pegBridgeV2).mint(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        } else if (t == MsgDataTypes.TransferType.PegWithdraw) {
            IOriginalTokenVault(pegVault).withdraw(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        } else if (t == MsgDataTypes.TransferType.PegV2Withdraw) {
            IOriginalTokenVaultV2(pegVaultV2).withdraw(
                _transferParams.request,
                _transferParams.sigs,
                _transferParams.signers,
                _transferParams.powers
            );
        }
    }

    // ================= contract config =================

    function setLiquidityBridge(address _addr) public onlyOwner {
        require(_addr != address(0), "invalid address");
        liquidityBridge = _addr;
        emit LiquidityBridgeUpdated(liquidityBridge);
    }

    function setPegBridge(address _addr) public onlyOwner {
        require(_addr != address(0), "invalid address");
        pegBridge = _addr;
        emit PegBridgeUpdated(pegBridge);
    }

    function setPegVault(address _addr) public onlyOwner {
        require(_addr != address(0), "invalid address");
        pegVault = _addr;
        emit PegVaultUpdated(pegVault);
    }

    function setPegBridgeV2(address _addr) public onlyOwner {
        require(_addr != address(0), "invalid address");
        pegBridgeV2 = _addr;
        emit PegBridgeV2Updated(pegBridgeV2);
    }

    function setPegVaultV2(address _addr) public onlyOwner {
        require(_addr != address(0), "invalid address");
        pegVaultV2 = _addr;
        emit PegVaultV2Updated(pegVaultV2);
    }

    function setPreExecuteMessageGasUsage(uint256 _usage) public onlyOwner {
        preExecuteMessageGasUsage = _usage;
    }
}

File 4 of 12 : Ownable.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 *
 * This adds a normal func that setOwner if _owner is address(0). So we can't allow
 * renounceOwnership. So we can support Proxy based upgradable contract
 */
abstract contract Ownable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(msg.sender);
    }

    /**
     * @dev Only to be called by inherit contracts, in their init func called by Proxy
     * we require _owner == address(0), which is only possible when it's a delegateCall
     * because constructor sets _owner in contract state.
     */
    function initOwner() internal {
        require(_owner == address(0), "owner already set");
        _setOwner(msg.sender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 5 of 12 : ISigsVerifier.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface ISigsVerifier {
    /**
     * @notice Verifies that a message is signed by a quorum among the signers.
     * @param _msg signed message
     * @param _sigs list of signatures sorted by signer addresses in ascending order
     * @param _signers sorted list of current signers
     * @param _powers powers of current signers
     */
    function verifySigs(
        bytes memory _msg,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external view;
}

File 6 of 12 : MsgDataTypes.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

library MsgDataTypes {
    string constant ABORT_PREFIX = "MSG::ABORT:";

    // bridge operation type at the sender side (src chain)
    enum BridgeSendType {
        Null,
        Liquidity,
        PegDeposit,
        PegBurn,
        PegV2Deposit,
        PegV2Burn,
        PegV2BurnFrom
    }

    // bridge operation type at the receiver side (dst chain)
    enum TransferType {
        Null,
        LqRelay, // relay through liquidity bridge
        LqWithdraw, // withdraw from liquidity bridge
        PegMint, // mint through pegged token bridge
        PegWithdraw, // withdraw from original token vault
        PegV2Mint, // mint through pegged token bridge v2
        PegV2Withdraw // withdraw from original token vault v2
    }

    enum MsgType {
        MessageWithTransfer,
        MessageOnly
    }

    enum TxStatus {
        Null,
        Success,
        Fail,
        Fallback,
        Pending // transient state within a transaction
    }

    struct TransferInfo {
        TransferType t;
        address sender;
        address receiver;
        address token;
        uint256 amount;
        uint64 wdseq; // only needed for LqWithdraw (refund)
        uint64 srcChainId;
        bytes32 refId;
        bytes32 srcTxHash; // src chain msg tx hash
    }

    struct RouteInfo {
        address sender;
        address receiver;
        uint64 srcChainId;
        bytes32 srcTxHash; // src chain msg tx hash
    }

    // used for msg from non-evm chains with longer-bytes address
    struct RouteInfo2 {
        bytes sender;
        address receiver;
        uint64 srcChainId;
        bytes32 srcTxHash;
    }

    // combination of RouteInfo and RouteInfo2 for easier processing
    struct Route {
        address sender; // from RouteInfo
        bytes senderBytes; // from RouteInfo2
        address receiver;
        uint64 srcChainId;
        bytes32 srcTxHash;
    }

    struct MsgWithTransferExecutionParams {
        bytes message;
        TransferInfo transfer;
        bytes[] sigs;
        address[] signers;
        uint256[] powers;
    }

    struct BridgeTransferParams {
        bytes request;
        bytes[] sigs;
        address[] signers;
        uint256[] powers;
    }
}

File 7 of 12 : IMessageReceiverApp.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IMessageReceiverApp {
    enum ExecutionStatus {
        Fail, // execution failed, finalized
        Success, // execution succeeded, finalized
        Retry // execution rejected, can retry later
    }

    /**
     * @notice Called by MessageBus to execute a message
     * @param _sender The address of the source app contract
     * @param _srcChainId The source chain ID where the transfer is originated from
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _executor Address who called the MessageBus execution function
     */
    function executeMessage(
        address _sender,
        uint64 _srcChainId,
        bytes calldata _message,
        address _executor
    ) external payable returns (ExecutionStatus);

    // same as above, except that sender is an non-evm chain address,
    // otherwise same as above.
    function executeMessage(
        bytes calldata _sender,
        uint64 _srcChainId,
        bytes calldata _message,
        address _executor
    ) external payable returns (ExecutionStatus);

    /**
     * @notice Called by MessageBus to execute a message with an associated token transfer.
     * The contract is guaranteed to have received the right amount of tokens before this function is called.
     * @param _sender The address of the source app contract
     * @param _token The address of the token that comes out of the bridge
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
     * @param _srcChainId The source chain ID where the transfer is originated from
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _executor Address who called the MessageBus execution function
     */
    function executeMessageWithTransfer(
        address _sender,
        address _token,
        uint256 _amount,
        uint64 _srcChainId,
        bytes calldata _message,
        address _executor
    ) external payable returns (ExecutionStatus);

    /**
     * @notice Only called by MessageBus if
     *         1. executeMessageWithTransfer reverts, or
     *         2. executeMessageWithTransfer returns ExecutionStatus.Fail
     * The contract is guaranteed to have received the right amount of tokens before this function is called.
     * @param _sender The address of the source app contract
     * @param _token The address of the token that comes out of the bridge
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
     * @param _srcChainId The source chain ID where the transfer is originated from
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
     * @param _executor Address who called the MessageBus execution function
     */
    function executeMessageWithTransferFallback(
        address _sender,
        address _token,
        uint256 _amount,
        uint64 _srcChainId,
        bytes calldata _message,
        address _executor
    ) external payable returns (ExecutionStatus);

    /**
     * @notice Called by MessageBus to process refund of the original transfer from this contract.
     * The contract is guaranteed to have received the refund before this function is called.
     * @param _token The token address of the original transfer
     * @param _amount The amount of the original transfer
     * @param _message The same message associated with the original transfer
     * @param _executor Address who called the MessageBus execution function
     */
    function executeMessageWithTransferRefund(
        address _token,
        uint256 _amount,
        bytes calldata _message,
        address _executor
    ) external payable returns (ExecutionStatus);
}

File 8 of 12 : IBridge.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IBridge {
    function send(
        address _receiver,
        address _token,
        uint256 _amount,
        uint64 _dstChainId,
        uint64 _nonce,
        uint32 _maxSlippage
    ) external;

    function sendNative(
        address _receiver,
        uint256 _amount,
        uint64 _dstChainId,
        uint64 _nonce,
        uint32 _maxSlippage
    ) external payable;

    function relay(
        bytes calldata _relayRequest,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external;

    function transfers(bytes32 transferId) external view returns (bool);

    function withdraws(bytes32 withdrawId) external view returns (bool);

    function withdraw(
        bytes calldata _wdmsg,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external;

    /**
     * @notice Verifies that a message is signed by a quorum among the signers.
     * @param _msg signed message
     * @param _sigs list of signatures sorted by signer addresses in ascending order
     * @param _signers sorted list of current signers
     * @param _powers powers of current signers
     */
    function verifySigs(
        bytes memory _msg,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external view;
}

File 9 of 12 : IOriginalTokenVault.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IOriginalTokenVault {
    /**
     * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge
     * @param _token local token address
     * @param _amount locked token amount
     * @param _mintChainId destination chainId to mint tokens
     * @param _mintAccount destination account to receive minted tokens
     * @param _nonce user input to guarantee unique depositId
     */
    function deposit(
        address _token,
        uint256 _amount,
        uint64 _mintChainId,
        address _mintAccount,
        uint64 _nonce
    ) external;

    /**
     * @notice Lock native token as original token to trigger mint at a remote chain's PeggedTokenBridge
     * @param _amount locked token amount
     * @param _mintChainId destination chainId to mint tokens
     * @param _mintAccount destination account to receive minted tokens
     * @param _nonce user input to guarantee unique depositId
     */
    function depositNative(
        uint256 _amount,
        uint64 _mintChainId,
        address _mintAccount,
        uint64 _nonce
    ) external payable;

    /**
     * @notice Withdraw locked original tokens triggered by a burn at a remote chain's PeggedTokenBridge.
     * @param _request The serialized Withdraw protobuf.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the bridge's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function withdraw(
        bytes calldata _request,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external;

    function records(bytes32 recordId) external view returns (bool);
}

File 10 of 12 : IOriginalTokenVaultV2.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IOriginalTokenVaultV2 {
    /**
     * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge
     * @param _token local token address
     * @param _amount locked token amount
     * @param _mintChainId destination chainId to mint tokens
     * @param _mintAccount destination account to receive minted tokens
     * @param _nonce user input to guarantee unique depositId
     */
    function deposit(
        address _token,
        uint256 _amount,
        uint64 _mintChainId,
        address _mintAccount,
        uint64 _nonce
    ) external returns (bytes32);

    /**
     * @notice Lock native token as original token to trigger mint at a remote chain's PeggedTokenBridge
     * @param _amount locked token amount
     * @param _mintChainId destination chainId to mint tokens
     * @param _mintAccount destination account to receive minted tokens
     * @param _nonce user input to guarantee unique depositId
     */
    function depositNative(
        uint256 _amount,
        uint64 _mintChainId,
        address _mintAccount,
        uint64 _nonce
    ) external payable returns (bytes32);

    /**
     * @notice Withdraw locked original tokens triggered by a burn at a remote chain's PeggedTokenBridge.
     * @param _request The serialized Withdraw protobuf.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the bridge's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function withdraw(
        bytes calldata _request,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external returns (bytes32);

    function records(bytes32 recordId) external view returns (bool);
}

File 11 of 12 : IPeggedTokenBridge.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IPeggedTokenBridge {
    /**
     * @notice Burn tokens to trigger withdrawal at a remote chain's OriginalTokenVault
     * @param _token local token address
     * @param _amount locked token amount
     * @param _withdrawAccount account who withdraw original tokens on the remote chain
     * @param _nonce user input to guarantee unique depositId
     */
    function burn(
        address _token,
        uint256 _amount,
        address _withdrawAccount,
        uint64 _nonce
    ) external;

    /**
     * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault.
     * @param _request The serialized Mint protobuf.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function mint(
        bytes calldata _request,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external;

    function records(bytes32 recordId) external view returns (bool);
}

File 12 of 12 : IPeggedTokenBridgeV2.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.8.0;

interface IPeggedTokenBridgeV2 {
    /**
     * @notice Burn pegged tokens to trigger a cross-chain withdrawal of the original tokens at a remote chain's
     * OriginalTokenVault, or mint at another remote chain
     * @param _token The pegged token address.
     * @param _amount The amount to burn.
     * @param _toChainId If zero, withdraw from original vault; otherwise, the remote chain to mint tokens.
     * @param _toAccount The account to receive tokens on the remote chain
     * @param _nonce A number to guarantee unique depositId. Can be timestamp in practice.
     */
    function burn(
        address _token,
        uint256 _amount,
        uint64 _toChainId,
        address _toAccount,
        uint64 _nonce
    ) external returns (bytes32);

    // same with `burn` above, use openzeppelin ERC20Burnable interface
    function burnFrom(
        address _token,
        uint256 _amount,
        uint64 _toChainId,
        address _toAccount,
        uint64 _nonce
    ) external returns (bytes32);

    /**
     * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault.
     * @param _request The serialized Mint protobuf.
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
     * +2/3 of the sigsVerifier's current signing power to be delivered.
     * @param _signers The sorted list of signers.
     * @param _powers The signing powers of the signers.
     */
    function mint(
        bytes calldata _request,
        bytes[] calldata _sigs,
        address[] calldata _signers,
        uint256[] calldata _powers
    ) external returns (bytes32);

    function records(bytes32 recordId) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ISigsVerifier","name":"_sigsVerifier","type":"address"},{"internalType":"address","name":"_liquidityBridge","type":"address"},{"internalType":"address","name":"_pegBridge","type":"address"},{"internalType":"address","name":"_pegVault","type":"address"},{"internalType":"address","name":"_pegBridgeV2","type":"address"},{"internalType":"address","name":"_pegVaultV2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"CallReverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum MsgDataTypes.MsgType","name":"msgType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"msgId","type":"bytes32"},{"indexed":false,"internalType":"enum MsgDataTypes.TxStatus","name":"status","type":"uint8"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint64","name":"srcChainId","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeBase","type":"uint256"}],"name":"FeeBaseUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feePerByte","type":"uint256"}],"name":"FeePerByteUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidityBridge","type":"address"}],"name":"LiquidityBridgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Message","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"receiver","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Message2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bridge","type":"address"},{"indexed":false,"internalType":"bytes32","name":"srcTransferId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"MessageWithTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum MsgDataTypes.MsgType","name":"msgType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"msgId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"srcChainId","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"name":"NeedRetry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pegBridge","type":"address"}],"name":"PegBridgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pegBridgeV2","type":"address"}],"name":"PegBridgeV2Updated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pegVault","type":"address"}],"name":"PegVaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pegVaultV2","type":"address"}],"name":"PegVaultV2Updated","type":"event"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"calcFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.RouteInfo","name":"_route","type":"tuple"},{"internalType":"bytes[]","name":"_sigs","type":"bytes[]"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint256[]","name":"_powers","type":"uint256[]"}],"name":"executeMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"components":[{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.RouteInfo2","name":"_route","type":"tuple"},{"internalType":"bytes[]","name":"_sigs","type":"bytes[]"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint256[]","name":"_powers","type":"uint256[]"}],"name":"executeMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"components":[{"internalType":"enum MsgDataTypes.TransferType","name":"t","type":"uint8"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"wdseq","type":"uint64"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"refId","type":"bytes32"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.TransferInfo","name":"_transfer","type":"tuple"},{"internalType":"bytes[]","name":"_sigs","type":"bytes[]"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint256[]","name":"_powers","type":"uint256[]"}],"name":"executeMessageWithTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"components":[{"internalType":"enum MsgDataTypes.TransferType","name":"t","type":"uint8"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"wdseq","type":"uint64"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"refId","type":"bytes32"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.TransferInfo","name":"_transfer","type":"tuple"},{"internalType":"bytes[]","name":"_sigs","type":"bytes[]"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint256[]","name":"_powers","type":"uint256[]"}],"name":"executeMessageWithTransferRefund","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"executedMessages","outputs":[{"internalType":"enum MsgDataTypes.TxStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePerByte","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidityBridge","type":"address"},{"internalType":"address","name":"_pegBridge","type":"address"},{"internalType":"address","name":"_pegVault","type":"address"},{"internalType":"address","name":"_pegBridgeV2","type":"address"},{"internalType":"address","name":"_pegVaultV2","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidityBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegBridgeV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegVaultV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preExecuteMessageGasUsage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"uint256[]","name":"powers","type":"uint256[]"}],"internalType":"struct MsgDataTypes.BridgeTransferParams","name":"_transferParams","type":"tuple"},{"components":[{"internalType":"bytes","name":"message","type":"bytes"},{"components":[{"internalType":"enum MsgDataTypes.TransferType","name":"t","type":"uint8"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"wdseq","type":"uint64"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"refId","type":"bytes32"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.TransferInfo","name":"transfer","type":"tuple"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"uint256[]","name":"powers","type":"uint256[]"}],"internalType":"struct MsgDataTypes.MsgWithTransferExecutionParams","name":"_msgParams","type":"tuple"}],"name":"refundAndExecuteMsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_receiver","type":"bytes"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"},{"internalType":"address","name":"_srcBridge","type":"address"},{"internalType":"bytes32","name":"_srcTransferId","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"sendMessageWithTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFeeBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFeePerByte","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setLiquidityBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setPegBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setPegBridgeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setPegVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setPegVaultV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_usage","type":"uint256"}],"name":"setPreExecuteMessageGasUsage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sigsVerifier","outputs":[{"internalType":"contract ISigsVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"uint256[]","name":"powers","type":"uint256[]"}],"internalType":"struct MsgDataTypes.BridgeTransferParams","name":"_transferParams","type":"tuple"},{"components":[{"internalType":"bytes","name":"message","type":"bytes"},{"components":[{"internalType":"enum MsgDataTypes.TransferType","name":"t","type":"uint8"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"wdseq","type":"uint64"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bytes32","name":"refId","type":"bytes32"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"}],"internalType":"struct MsgDataTypes.TransferInfo","name":"transfer","type":"tuple"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"uint256[]","name":"powers","type":"uint256[]"}],"internalType":"struct MsgDataTypes.MsgWithTransferExecutionParams","name":"_msgParams","type":"tuple"}],"name":"transferAndExecuteMsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_cumulativeFee","type":"uint256"},{"internalType":"bytes[]","name":"_sigs","type":"bytes[]"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint256[]","name":"_powers","type":"uint256[]"}],"name":"withdrawFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawnFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x6080604052600436106101fe5760003560e01c806382980dc41161011d578063ccf2683b116100b0578063dfa2dbaf1161007f578063f2fde38b11610064578063f2fde38b146105bd578063f60bbe2a146105dd578063f83b0fb9146105f357600080fd5b8063dfa2dbaf1461057d578063e2c1ed251461059d57600080fd5b8063ccf2683b146104d9578063cd2abd661461050d578063d8257d171461054a578063db2c20c81461056a57600080fd5b806395e911a8116100ec57806395e911a8146104705780639b05a775146104865780639f3ce55a146104a6578063c66a9c5a146104b957600080fd5b806382980dc4146103da57806382efd502146104125780638da5cb5b1461043257806395b12c271461045057600080fd5b8063468a2d04116101955780635b3e5f50116101645780635b3e5f5014610367578063723d0a9d146103945780637b80ab20146103b45780637d7a101d146103c757600080fd5b8063468a2d04146102eb5780635335dca2146102fe578063584e45e114610331578063588be02b1461034757600080fd5b80633f395aff116101d15780633f395aff1461028557806340d0d026146102985780634289fbb3146102b85780634586f331146102cb57600080fd5b806303cbfe661461020357806306c28bd6146102255780632ff4c41114610245578063359ef75b14610265575b600080fd5b34801561020f57600080fd5b5061022361021e366004612f40565b610613565b005b34801561023157600080fd5b50610223610240366004612f5b565b61070c565b34801561025157600080fd5b50610223610260366004612fc0565b610798565b34801561027157600080fd5b50610223610280366004613074565b610a33565b61022361029336600461311b565b610a4f565b3480156102a457600080fd5b506102236102b3366004613224565b610d3f565b6102236102c6366004613290565b610d97565b3480156102d757600080fd5b506102236102e6366004612f5b565b610e7f565b6102236102f9366004613308565b610edb565b34801561030a57600080fd5b5061031e6103193660046133cd565b610f3b565b6040519081526020015b60405180910390f35b34801561033d57600080fd5b5061031e600a5481565b34801561035357600080fd5b50610223610362366004612f40565b610f61565b34801561037357600080fd5b5061031e610382366004612f40565b60036020526000908152604090205481565b3480156103a057600080fd5b506102236103af366004613224565b61104e565b6102236103c236600461311b565b61109c565b6102236103d536600461340f565b6112a9565b3480156103e657600080fd5b506005546103fa906001600160a01b031681565b6040516001600160a01b039091168152602001610328565b34801561041e57600080fd5b5061022361042d366004612f40565b611306565b34801561043e57600080fd5b506000546001600160a01b03166103fa565b34801561045c57600080fd5b506008546103fa906001600160a01b031681565b34801561047c57600080fd5b5061031e60015481565b34801561049257600080fd5b506102236104a1366004612f40565b6113f3565b6102236104b4366004613489565b6114e0565b3480156104c557600080fd5b506009546103fa906001600160a01b031681565b3480156104e557600080fd5b506103fa7f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c81565b34801561051957600080fd5b5061053d610528366004612f5b565b60046020526000908152604090205460ff1681565b604051610328919061350d565b34801561055657600080fd5b506007546103fa906001600160a01b031681565b61022361057836600461351b565b61153a565b34801561058957600080fd5b506006546103fa906001600160a01b031681565b3480156105a957600080fd5b506102236105b8366004612f5b565b61158e565b3480156105c957600080fd5b506102236105d8366004612f40565b61161a565b3480156105e957600080fd5b5061031e60025481565b3480156105ff57600080fd5b5061022361060e366004612f40565b6116f9565b336106266000546001600160a01b031690565b6001600160a01b03161461066f5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec383398151915260448201526064015b60405180910390fd5b6001600160a01b0381166106b75760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fd60e9ceb4f54f1bfb1741a4b35fc9d806d7ed48200b523203b92248ea38fa17d906020015b60405180910390a150565b3361071f6000546001600160a01b031690565b6001600160a01b0316146107635760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60018190556040518181527f892dfdc99ecd3bb4f2f2cb118dca02f0bd16640ff156d3c6459d4282e336a5f290602001610701565b600046306040516020016107e992919091825260601b6001600160601b03191660208201527f77697468647261774665650000000000000000000000000000000000000000006034820152603f0190565b60408051808303601f19018152828252805160209182012090830181905260608c901b6001600160601b0319168383015260548084018c9052825180850390910181526074840192839052633416de1160e11b90925292507f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c6001600160a01b03169163682dbc229161088a918b908b908b908b908b908b9060780161377f565b60006040518083038186803b1580156108a257600080fd5b505afa1580156108b6573d6000803e3d6000fd5b505050506001600160a01b0389166000908152600360205260408120546108dd908a6137f3565b90506000811161092f5760405162461bcd60e51b815260206004820152601960248201527f4e6f206e657720616d6f756e7420746f207769746864726177000000000000006044820152606401610666565b6001600160a01b038a166000818152600360205260408082208c90555190919061c35090849084818181858888f193505050503d806000811461098e576040519150601f19603f3d011682016040523d82523d6000602084013e610993565b606091505b50509050806109e45760405162461bcd60e51b815260206004820152601660248201527f6661696c656420746f20776974686472617720666565000000000000000000006044820152606401610666565b604080516001600160a01b038d168152602081018490527f78473f3f373f7673597f4f0fa5873cb4d375fea6d4339ad6b56dbd411513cb3f910160405180910390a15050505050505050505050565b610a3b6117e6565b610a48858585858561184a565b5050505050565b6000610a5a88611902565b90506000808281526004602081905260409091205460ff1690811115610a8257610a826134e3565b14610acf5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572000000000000000000000000006054820152606701604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e6101000135604051602001610b8e959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401610bc5979695949392919061377f565b60006040518083038186803b158015610bdd57600080fd5b505afa158015610bf1573d6000803e3d6000fd5b50505050600080610c038b8e8e61216b565b90506001816002811115610c1957610c196134e3565b03610c275760019150610cef565b6002816002811115610c3b57610c3b6134e3565b03610cbb576000848152600460205260408120805460ff19166001835b02179055507fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c6000858d60c0016020810190610c949190613828565b8e6101000135604051610caa9493929190613862565b60405180910390a150505050610d34565b610cc68b8e8e6122a6565b90506001816002811115610cdc57610cdc6134e3565b03610cea5760039150610cef565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115610d1f57610d1f6134e3565b0217905550610d2f84838d6122e1565b505050505b505050505050505050565b610d58610d526040830160208401613895565b83612353565b610d93610d6582806138b6565b60208401610d776101408601866138fd565b610d856101608801886138fd565b6103c26101808a018a6138fd565b5050565b468503610dd85760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b6000610de48383610f3b565b905080341015610e295760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b336001600160a01b03167f172762498a59a3bc4fed3f2b63f94f17ea0193cffdc304fe7d3eaf4d342d2f6688888888888834604051610e6e9796959493929190613947565b60405180910390a250505050505050565b33610e926000546001600160a01b031690565b6001600160a01b031614610ed65760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b600a55565b6000610ee68861259d565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600781526020017f4d65737361676500000000000000000000000000000000000000000000000000815250612654565b50505050505050505050565b600254600090610f4b9083613994565b600154610f5891906139ab565b90505b92915050565b33610f746000546001600160a01b031690565b6001600160a01b031614610fb85760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166110005760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527fbf9977180dc6e6cff25598c8e59150cecd7f8e448e092633d38ab7ee223ae05890602001610701565b611061610d526040830160208401613895565b610d9361106e82806138b6565b602084016110806101408601866138fd565b61108e6101608801886138fd565b6102936101808a018a6138fd565b60006110a788611902565b90506000808281526004602081905260409091205460ff16908111156110cf576110cf6134e3565b1461111c5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572526566756e64000000000000006054820152606d01604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e61010001356040516020016111db959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401611212979695949392919061377f565b60006040518083038186803b15801561122a57600080fd5b505afa15801561123e573d6000803e3d6000fd5b505050506000806112508b8e8e6128a8565b90506001816002811115611266576112666134e3565b036112745760019150610cef565b6002816002811115611288576112886134e3565b03610cea576000848152600460205260408120805460ff1916600183610c58565b6112b48383836128ff565b336001600160a01b03167fe66fbe37d84ca73c589f782ac278844918ea6c56a4917f58707f715588080df28686868686346040516112f7969594939291906139be565b60405180910390a25050505050565b336113196000546001600160a01b031690565b6001600160a01b03161461135d5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166113a55760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb337a6c76476534518d5816caeb86263972470fedccfd047a35eb1825eaa9e890602001610701565b336114066000546001600160a01b031690565b6001600160a01b03161461144a5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166114925760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527fa9db0c32d9c6c2f75f3b95047a9e67cc1c010eab792a4e6ca777ce918ad94aad90602001610701565b6114eb8383836128ff565b336001600160a01b03167fce3972bfffe49d317e1d128047a97a3d86b25c94f6f04409f988ef854d25e0e4858585853460405161152c9594939291906139ff565b60405180910390a250505050565b600061154588612997565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600881526020017f4d65737361676532000000000000000000000000000000000000000000000000815250612654565b336115a16000546001600160a01b031690565b6001600160a01b0316146115e55760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60028190556040518181527f210d4d5d2d36d571207dac98e383e2441c684684c885fb2d7c54f8d24422074c90602001610701565b3361162d6000546001600160a01b031690565b6001600160a01b0316146116715760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166116ed5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610666565b6116f681612a2d565b50565b3361170c6000546001600160a01b031690565b6001600160a01b0316146117505760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166117985760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527f918a691a2a82482a10e11f43d7b627b2ba220dd08f251cb61933c42560f6fcb590602001610701565b6000546001600160a01b03161561183f5760405162461bcd60e51b815260206004820152601160248201527f6f776e657220616c7265616479207365740000000000000000000000000000006044820152606401610666565b61184833612a2d565b565b6005546001600160a01b0316156118a35760405162461bcd60e51b815260206004820152601b60248201527f6c697175696469747942726964676520616c72656164792073657400000000006044820152606401610666565b600580546001600160a01b03199081166001600160a01b03978816179091556006805482169587169590951790945560078054851693861693909317909255600880548416918516919091179055600980549092169216919091179055565b6000808060016119156020860186613895565b6006811115611926576119266134e3565b03611ab15761193b6040850160208601612f40565b61194b6060860160408701612f40565b61195b6080870160608801612f40565b608087013561197060e0890160c08a01613828565b6040516001600160601b0319606096871b8116602083015294861b851660348201529290941b9092166048820152605c8101919091526001600160c01b031960c092831b8116607c8301524690921b909116608482015260e0850135608c82015260ac0160408051808303601f19018152908290528051602090910120600554633c64f04b60e01b8352600483018290529093506001600160a01b031691508190633c64f04b90602401602060405180830381865afa158015611a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5b9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601660248201527f6272696467652072656c6179206e6f74206578697374000000000000000000006044820152606401610666565b612136565b6002611ac06020860186613895565b6006811115611ad157611ad16134e3565b03611c2e5746611ae760c0860160a08701613828565b611af76060870160408801612f40565b611b076080880160608901612f40565b6040516001600160c01b031960c095861b811660208301529390941b90921660288401526001600160601b0319606091821b8116603085015291901b1660448201526080850135605882015260780160408051808303601f19018152908290528051602090910120600554631c13568560e31b8352600483018290529093506001600160a01b03169150819063e09ab42890602401602060405180830381865afa158015611bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdd9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f627269646765207769746864726177206e6f74206578697374000000000000006044820152606401610666565b6003611c3d6020860186613895565b6006811115611c4e57611c4e6134e3565b1480611c7757506004611c646020860186613895565b6006811115611c7557611c756134e3565b145b15611eda57611c8c6060850160408601612f40565b611c9c6080860160608701612f40565b6080860135611cb16040880160208901612f40565b611cc160e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b851660348201526048810193909352931b909116606882015260c09190911b6001600160c01b031916607c82015260e0850135608482015260a40160408051601f19818403018152919052805160209091012091506003611d416020860186613895565b6006811115611d5257611d526134e3565b03611e1957506006546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e64725906024015b602060405180830381865afa158015611da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc89190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601560248201527f6d696e74207265636f7264206e6f7420657869737400000000000000000000006044820152606401610666565b506007546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e6472590602401602060405180830381865afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6005611ee96020860186613895565b6006811115611efa57611efa6134e3565b1480611f2357506006611f106020860186613895565b6006811115611f2157611f216134e3565b145b15612136576005611f376020860186613895565b6006811115611f4857611f486134e3565b03611f5f57506008546001600160a01b0316611f6d565b506009546001600160a01b03165b611f7d6060850160408601612f40565b611f8d6080860160608701612f40565b6080860135611fa26040880160208901612f40565b611fb260e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b85166034820152604881019390935290841b8316606883015260c01b6001600160c01b031916607c82015260e087013560848201529183901b1660a482015260b80160408051601f198184030181529190528051602090910120915060056120396020860186613895565b600681111561204a5761204a6134e3565b0361207c576040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401611d87565b6040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401602060405180830381865afa1580156120c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e59190613a3a565b15156001146121365760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6000818360405160200161214c93929190613a73565b6040516020818303038152906040528051906020012092505050919050565b6000805a90506000806121846060880160408901612f40565b6001600160a01b031634631f34afff60e21b6121a660408b0160208c01612f40565b6121b660808c0160608d01612f40565b60808c01356121cb60e08e0160c08f01613828565b8c8c336040516024016121e49796959493929190613a9f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122229190613af8565b60006040518083038185875af1925050503d806000811461225f576040519150601f19603f3d011682016040523d82523d6000602084013e612264565b606091505b5091509150811561228d57808060200190518101906122839190613b14565b935050505061229f565b6122978382612a7d565b600093505050505b9392505050565b6000805a90506000806122bf6060880160408901612f40565b6001600160a01b031634632d5bd7e360e11b6121a660408b0160208c01612f40565b6122f16060820160408301612f40565b6001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6000858561232f60e0870160c08801613828565b866101000135604051612346959493929190613b35565b60405180910390a2505050565b6001826006811115612367576123676134e3565b03612407576005546001600160a01b031663cdd1b25d61238783806138b6565b61239460208601866138fd565b6123a160408801886138fd565b6123ae60608a018a6138fd565b6040518963ffffffff1660e01b81526004016123d1989796959493929190613b73565b600060405180830381600087803b1580156123eb57600080fd5b505af11580156123ff573d6000803e3d6000fd5b505050505050565b600282600681111561241b5761241b6134e3565b0361243b576005546001600160a01b031663a21a928061238783806138b6565b600382600681111561244f5761244f6134e3565b0361246f576006546001600160a01b031663f873430261238783806138b6565b6005826006811115612483576124836134e3565b03612535576008546001600160a01b031663f87343026124a383806138b6565b6124b060208601866138fd565b6124bd60408801886138fd565b6124ca60608a018a6138fd565b6040518963ffffffff1660e01b81526004016124ed989796959493929190613b73565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190613bd3565b505050565b6004826006811115612549576125496134e3565b03612569576007546001600160a01b031663a21a928061238783806138b6565b600682600681111561257d5761257d6134e3565b03610d93576009546001600160a01b031663a21a92806124a383806138b6565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a08101909152806125e26020850185612f40565b6001600160a01b031681526020016040518060200160405280600081525081526020018360200160208101906126189190612f40565b6001600160a01b031681526020016126366060850160408601613828565b67ffffffffffffffff16815260200183606001358152509050919050565b6000612661898c8c612b08565b90506000808281526004602081905260409091205460ff1690811115612689576126896134e3565b146126d65760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c726561647920657865637574656400000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff191690931790925590516127059146913091879101613bec565b60408051601f1981840301815282825280516020918201206005549184018190528383018690528251808503840181526060850193849052633416de1160e11b90935293506001600160a01b03169163682dbc2291612772918d908d908d908d908d908d9060640161377f565b60006040518083038186803b15801561278a57600080fd5b505afa15801561279e573d6000803e3d6000fd5b505050506000806127b08c8f8f612b9c565b905060018160028111156127c6576127c66134e3565b036127d45760019150612858565b60028160028111156127e8576127e86134e3565b036128535760008481526004602052604090819020805460ff1916905560608d015160808e015191517fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c9261284292600192899290613862565b60405180910390a150505050610f2f565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115612888576128886134e3565b021790555061289884838e612d7d565b5050505050505050505050505050565b6000805a90506000806128c16060880160408901612f40565b6001600160a01b0316346305e5a4c160e11b6128e360808b0160608c01612f40565b8a608001358a8a336040516024016121e4959493929190613c2b565b4683036129405760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b600061294c8383610f3b565b9050803410156129915760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b50505050565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a0810190915260008152602081016129e084806138b6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020908101906126189060408601908601612f40565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005a90506000600a5445612a9291906137f3565b90508084108015612aad5750612aa9604085613c6a565b8211155b15612ab457fe5b6000612abf84612dcb565b9050612aca81612e2a565b7fffdd6142bbb721f3400e3908b04b86f60649b2e4d191e3f4c50c32c3e6471d2f81604051612af99190613c8c565b60405180910390a15050505050565b60208301518051600091908203612b50578451604051612b3e919060200160609190911b6001600160601b031916815260140190565b60405160208183030381529060405290505b600181866040015187606001518860800151468989604051602001612b7c989796959493929190613c9f565b604051602081830303815290604052805190602001209150509392505050565b6000805a905060006060866020015151600003612c8c5786604001516001600160a01b0316346040518060600160405280602c8152602001613ee3602c91398051602090910120895160608b0151604051612c019291908c908c903390602401613d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c3f9190613af8565b60006040518083038185875af1925050503d8060008114612c7c576040519150601f19603f3d011682016040523d82523d6000602084013e612c81565b606091505b509092509050612d63565b86604001516001600160a01b0316346040518060600160405280602a8152602001613e99602a91398051906020012089602001518a606001518a8a33604051602401612cdc959493929190613d54565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612d1a9190613af8565b60006040518083038185875af1925050503d8060008114612d57576040519150601f19603f3d011682016040523d82523d6000602084013e612d5c565b606091505b5090925090505b811561228d57808060200190518101906122839190613b14565b80604001516001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6001858585606001518660800151604051612346959493929190613b35565b6060604482511015612e1057505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b60048201915081806020019051810190610f5b9190613dbc565b60408051808201909152600b8082527f4d53473a3a41424f52543a000000000000000000000000000000000000000000602083015282518391116125305760005b8251811015612f0957828181518110612e8657612e86613e69565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916828281518110612ec557612ec5613e69565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612ef75750505050565b80612f0181613e7f565b915050612e6b565b508260405162461bcd60e51b81526004016106669190613c8c565b80356001600160a01b0381168114612f3b57600080fd5b919050565b600060208284031215612f5257600080fd5b610f5882612f24565b600060208284031215612f6d57600080fd5b5035919050565b60008083601f840112612f8657600080fd5b50813567ffffffffffffffff811115612f9e57600080fd5b6020830191508360208260051b8501011115612fb957600080fd5b9250929050565b60008060008060008060008060a0898b031215612fdc57600080fd5b612fe589612f24565b975060208901359650604089013567ffffffffffffffff8082111561300957600080fd5b6130158c838d01612f74565b909850965060608b013591508082111561302e57600080fd5b61303a8c838d01612f74565b909650945060808b013591508082111561305357600080fd5b506130608b828c01612f74565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561308c57600080fd5b61309586612f24565b94506130a360208701612f24565b93506130b160408701612f24565b92506130bf60608701612f24565b91506130cd60808701612f24565b90509295509295909350565b60008083601f8401126130eb57600080fd5b50813567ffffffffffffffff81111561310357600080fd5b602083019150836020828501011115612fb957600080fd5b6000806000806000806000806000898b036101a081121561313b57600080fd5b8a3567ffffffffffffffff8082111561315357600080fd5b61315f8e838f016130d9565b909c509a508a9150610120601f198401121561317a57600080fd5b60208d0199506101408d013592508083111561319557600080fd5b6131a18e848f01612f74565b90995097506101608d01359250889150808311156131be57600080fd5b6131ca8e848f01612f74565b90975095506101808d01359250869150808311156131e757600080fd5b50506131f58c828d01612f74565b915080935050809150509295985092959850929598565b60006080828403121561321e57600080fd5b50919050565b6000806040838503121561323757600080fd5b823567ffffffffffffffff8082111561324f57600080fd5b61325b8683870161320c565b9350602085013591508082111561327157600080fd5b5083016101a0818603121561328557600080fd5b809150509250929050565b60008060008060008060a087890312156132a957600080fd5b6132b287612f24565b9550602087013594506132c760408801612f24565b935060608701359250608087013567ffffffffffffffff8111156132ea57600080fd5b6132f689828a016130d9565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c03121561332757600080fd5b893567ffffffffffffffff8082111561333f57600080fd5b61334b8d838e016130d9565b909b5099508991506133608d60208e0161320c565b985060a08c013591508082111561337657600080fd5b6133828d838e01612f74565b909850965060c08c013591508082111561339b57600080fd5b6133a78d838e01612f74565b909650945060e08c01359150808211156133c057600080fd5b506131f58c828d01612f74565b600080602083850312156133e057600080fd5b823567ffffffffffffffff8111156133f757600080fd5b613403858286016130d9565b90969095509350505050565b60008060008060006060868803121561342757600080fd5b853567ffffffffffffffff8082111561343f57600080fd5b61344b89838a016130d9565b909750955060208801359450604088013591508082111561346b57600080fd5b50613478888289016130d9565b969995985093965092949392505050565b6000806000806060858703121561349f57600080fd5b6134a885612f24565b935060208501359250604085013567ffffffffffffffff8111156134cb57600080fd5b6134d7878288016130d9565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b60058110613509576135096134e3565b9052565b60208101610f5b82846134f9565b600080600080600080600080600060a08a8c03121561353957600080fd5b893567ffffffffffffffff8082111561355157600080fd5b61355d8d838e016130d9565b909b50995060208c013591508082111561357657600080fd5b6135828d838e0161320c565b985060408c013591508082111561359857600080fd5b6135a48d838e01612f74565b909850965060608c01359150808211156135bd57600080fd5b6135c98d838e01612f74565b909650945060808c01359150808211156133c057600080fd5b60005b838110156135fd5781810151838201526020016135e5565b50506000910152565b6000815180845261361e8160208601602086016135e2565b601f01601f19169290920160200192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b81835260006020808501808196508560051b810191508460005b878110156136e05782840389528135601e1988360301811261369657600080fd5b8701858101903567ffffffffffffffff8111156136b257600080fd5b8036038213156136c157600080fd5b6136cc868284613632565b9a87019a9550505090840190600101613675565b5091979650505050505050565b8183526000602080850194508260005b85811015613729576001600160a01b0361371683612f24565b16875295820195908201906001016136fd565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561376657600080fd5b8260051b80836020870137939093016020019392505050565b608081526000613792608083018a613606565b82810360208401526137a581898b61365b565b905082810360408401526137ba8187896136ed565b905082810360608401526137cf818587613734565b9a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f5b57610f5b6137dd565b8581528460208201528284604083013760409201918201526060019392505050565b60006020828403121561383a57600080fd5b813567ffffffffffffffff8116811461229f57600080fd5b60028110613509576135096134e3565b608081016138708287613852565b84602083015267ffffffffffffffff8416604083015282606083015295945050505050565b6000602082840312156138a757600080fd5b81356007811061229f57600080fd5b6000808335601e198436030181126138cd57600080fd5b83018035915067ffffffffffffffff8211156138e857600080fd5b602001915036819003821315612fb957600080fd5b6000808335601e1984360301811261391457600080fd5b83018035915067ffffffffffffffff82111561392f57600080fd5b6020019150600581901b3603821315612fb957600080fd5b60006001600160a01b03808a16835288602084015280881660408401525085606083015260c0608083015261398060c083018587613632565b90508260a083015298975050505050505050565b8082028115828204841417610f5b57610f5b6137dd565b80820180821115610f5b57610f5b6137dd565b6080815260006139d260808301888a613632565b86602084015282810360408401526139eb818688613632565b915050826060830152979650505050505050565b6001600160a01b0386168152846020820152608060408201526000613a28608083018587613632565b90508260608301529695505050505050565b600060208284031215613a4c57600080fd5b8151801515811461229f57600080fd5b60028110613a6c57613a6c6134e3565b60f81b9052565b613a7d8185613a5c565b60609290921b6001600160601b03191660018301526015820152603501919050565b60006001600160a01b03808a168352808916602084015287604084015267ffffffffffffffff8716606084015260c06080840152613ae160c084018688613632565b915080841660a08401525098975050505050505050565b60008251613b0a8184602087016135e2565b9190910192915050565b600060208284031215613b2657600080fd5b81516003811061229f57600080fd5b60a08101613b438288613852565b856020830152613b5660408301866134f9565b67ffffffffffffffff939093166060820152608001529392505050565b608081526000613b87608083018a8c613632565b8281036020840152613b9a81898b61365b565b90508281036040840152613baf8187896136ed565b90508281036060840152613bc4818587613734565b9b9a5050505050505050505050565b600060208284031215613be557600080fd5b5051919050565b8381526bffffffffffffffffffffffff198360601b16602082015260008251613c1c8160348501602087016135e2565b91909101603401949350505050565b60006001600160a01b03808816835286602084015260806040840152613c55608084018688613632565b91508084166060840152509695505050505050565b600082613c8757634e487b7160e01b600052601260045260246000fd5b500490565b602081526000610f586020830184613606565b613ca9818a613a5c565b60008851613cbe816001850160208d016135e2565b80830190506bffffffffffffffffffffffff198960601b1660018201526001600160c01b0319808960c01b16601583015287601d830152808760c01b16603d830152508385604583013760009301604501928352509098975050505050505050565b60006001600160a01b03808816835267ffffffffffffffff8716602084015260806040840152613c55608084018688613632565b608081526000613d676080830188613606565b67ffffffffffffffff871660208401528281036040840152613d8a818688613632565b9150506001600160a01b03831660608301529695505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215613dce57600080fd5b815167ffffffffffffffff80821115613de657600080fd5b818401915084601f830112613dfa57600080fd5b815181811115613e0c57613e0c613da6565b604051601f8201601f19908116603f01168101908382118183101715613e3457613e34613da6565b81604052828152876020848701011115613e4d57600080fd5b613e5e8360208301602088016135e2565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613e9157613e916137dd565b506001019056fe657865637574654d6573736167652862797465732c75696e7436342c62797465732c61646472657373294f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572657865637574654d65737361676528616464726573732c75696e7436342c62797465732c6164647265737329a2646970667358221220006def5a78ed98e487079542720cb6f70211c18a567430956ef44d12536e22c464736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.