Contract Address Details

0x952eB191CFd11F28FDB429A4E111C43DF3555C8f

Contract Name
MessageBus
Creator
0x00778c–ec1c1f at 0x5ad0a6–fa15c3
Balance
0 mADA
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
36332981
Contract name:
MessageBus




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
800
Verified at
2022-12-23T10:13:12.227340Z

Constructor Arguments

000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c000000000000000000000000bb7684cc5408f4dd0921e5c2cadd547b8f1ad57300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b53d2c7b44d40be05fa5e2309ffeb6eb2492d88000000000000000000000000b51541df05de07be38dcfc4a80c05389a54502bb

Arg [0] (address) : 0x841ce48f9446c8e281d3f1444cb859b4a6d0738c
Arg [1] (address) : 0x841ce48f9446c8e281d3f1444cb859b4a6d0738c
Arg [2] (address) : 0xbb7684cc5408f4dd0921e5c2cadd547b8f1ad573
Arg [3] (address) : 0x0000000000000000000000000000000000000000
Arg [4] (address) : 0x3b53d2c7b44d40be05fa5e2309ffeb6eb2492d88
Arg [5] (address) : 0xb51541df05de07be38dcfc4a80c05389a54502bb

              

./contracts/message/messagebus/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);
    }
}
        

./contracts/interfaces/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;
}
          

./contracts/interfaces/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);
}
          

./contracts/interfaces/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);
}
          

./contracts/interfaces/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);
}
          

./contracts/interfaces/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);
}
          

./contracts/interfaces/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;
}
          

./contracts/message/interfaces/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);
}
          

./contracts/message/libraries/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;
    }
}
          

./contracts/message/messagebus/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;
    }
}
          

./contracts/message/messagebus/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);
    }
}
          

./contracts/safeguard/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);
    }
}
          

Contract ABI

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

Deployed ByteCode

0x6080604052600436106101fe5760003560e01c806382980dc41161011d578063ccf2683b116100b0578063dfa2dbaf1161007f578063f2fde38b11610064578063f2fde38b146105bd578063f60bbe2a146105dd578063f83b0fb9146105f357600080fd5b8063dfa2dbaf1461057d578063e2c1ed251461059d57600080fd5b8063ccf2683b146104d9578063cd2abd661461050d578063d8257d171461054a578063db2c20c81461056a57600080fd5b806395e911a8116100ec57806395e911a8146104705780639b05a775146104865780639f3ce55a146104a6578063c66a9c5a146104b957600080fd5b806382980dc4146103da57806382efd502146104125780638da5cb5b1461043257806395b12c271461045057600080fd5b8063468a2d04116101955780635b3e5f50116101645780635b3e5f5014610367578063723d0a9d146103945780637b80ab20146103b45780637d7a101d146103c757600080fd5b8063468a2d04146102eb5780635335dca2146102fe578063584e45e114610331578063588be02b1461034757600080fd5b80633f395aff116101d15780633f395aff1461028557806340d0d026146102985780634289fbb3146102b85780634586f331146102cb57600080fd5b806303cbfe661461020357806306c28bd6146102255780632ff4c41114610245578063359ef75b14610265575b600080fd5b34801561020f57600080fd5b5061022361021e366004612f40565b610613565b005b34801561023157600080fd5b50610223610240366004612f5b565b61070c565b34801561025157600080fd5b50610223610260366004612fc0565b610798565b34801561027157600080fd5b50610223610280366004613074565b610a33565b61022361029336600461311b565b610a4f565b3480156102a457600080fd5b506102236102b3366004613224565b610d3f565b6102236102c6366004613290565b610d97565b3480156102d757600080fd5b506102236102e6366004612f5b565b610e7f565b6102236102f9366004613308565b610edb565b34801561030a57600080fd5b5061031e6103193660046133cd565b610f3b565b6040519081526020015b60405180910390f35b34801561033d57600080fd5b5061031e600a5481565b34801561035357600080fd5b50610223610362366004612f40565b610f61565b34801561037357600080fd5b5061031e610382366004612f40565b60036020526000908152604090205481565b3480156103a057600080fd5b506102236103af366004613224565b61104e565b6102236103c236600461311b565b61109c565b6102236103d536600461340f565b6112a9565b3480156103e657600080fd5b506005546103fa906001600160a01b031681565b6040516001600160a01b039091168152602001610328565b34801561041e57600080fd5b5061022361042d366004612f40565b611306565b34801561043e57600080fd5b506000546001600160a01b03166103fa565b34801561045c57600080fd5b506008546103fa906001600160a01b031681565b34801561047c57600080fd5b5061031e60015481565b34801561049257600080fd5b506102236104a1366004612f40565b6113f3565b6102236104b4366004613489565b6114e0565b3480156104c557600080fd5b506009546103fa906001600160a01b031681565b3480156104e557600080fd5b506103fa7f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c81565b34801561051957600080fd5b5061053d610528366004612f5b565b60046020526000908152604090205460ff1681565b604051610328919061350d565b34801561055657600080fd5b506007546103fa906001600160a01b031681565b61022361057836600461351b565b61153a565b34801561058957600080fd5b506006546103fa906001600160a01b031681565b3480156105a957600080fd5b506102236105b8366004612f5b565b61158e565b3480156105c957600080fd5b506102236105d8366004612f40565b61161a565b3480156105e957600080fd5b5061031e60025481565b3480156105ff57600080fd5b5061022361060e366004612f40565b6116f9565b336106266000546001600160a01b031690565b6001600160a01b03161461066f5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec383398151915260448201526064015b60405180910390fd5b6001600160a01b0381166106b75760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fd60e9ceb4f54f1bfb1741a4b35fc9d806d7ed48200b523203b92248ea38fa17d906020015b60405180910390a150565b3361071f6000546001600160a01b031690565b6001600160a01b0316146107635760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60018190556040518181527f892dfdc99ecd3bb4f2f2cb118dca02f0bd16640ff156d3c6459d4282e336a5f290602001610701565b600046306040516020016107e992919091825260601b6001600160601b03191660208201527f77697468647261774665650000000000000000000000000000000000000000006034820152603f0190565b60408051808303601f19018152828252805160209182012090830181905260608c901b6001600160601b0319168383015260548084018c9052825180850390910181526074840192839052633416de1160e11b90925292507f000000000000000000000000841ce48f9446c8e281d3f1444cb859b4a6d0738c6001600160a01b03169163682dbc229161088a918b908b908b908b908b908b9060780161377f565b60006040518083038186803b1580156108a257600080fd5b505afa1580156108b6573d6000803e3d6000fd5b505050506001600160a01b0389166000908152600360205260408120546108dd908a6137f3565b90506000811161092f5760405162461bcd60e51b815260206004820152601960248201527f4e6f206e657720616d6f756e7420746f207769746864726177000000000000006044820152606401610666565b6001600160a01b038a166000818152600360205260408082208c90555190919061c35090849084818181858888f193505050503d806000811461098e576040519150601f19603f3d011682016040523d82523d6000602084013e610993565b606091505b50509050806109e45760405162461bcd60e51b815260206004820152601660248201527f6661696c656420746f20776974686472617720666565000000000000000000006044820152606401610666565b604080516001600160a01b038d168152602081018490527f78473f3f373f7673597f4f0fa5873cb4d375fea6d4339ad6b56dbd411513cb3f910160405180910390a15050505050505050505050565b610a3b6117e6565b610a48858585858561184a565b5050505050565b6000610a5a88611902565b90506000808281526004602081905260409091205460ff1690811115610a8257610a826134e3565b14610acf5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572000000000000000000000000006054820152606701604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e6101000135604051602001610b8e959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401610bc5979695949392919061377f565b60006040518083038186803b158015610bdd57600080fd5b505afa158015610bf1573d6000803e3d6000fd5b50505050600080610c038b8e8e61216b565b90506001816002811115610c1957610c196134e3565b03610c275760019150610cef565b6002816002811115610c3b57610c3b6134e3565b03610cbb576000848152600460205260408120805460ff19166001835b02179055507fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c6000858d60c0016020810190610c949190613828565b8e6101000135604051610caa9493929190613862565b60405180910390a150505050610d34565b610cc68b8e8e6122a6565b90506001816002811115610cdc57610cdc6134e3565b03610cea5760039150610cef565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115610d1f57610d1f6134e3565b0217905550610d2f84838d6122e1565b505050505b505050505050505050565b610d58610d526040830160208401613895565b83612353565b610d93610d6582806138b6565b60208401610d776101408601866138fd565b610d856101608801886138fd565b6103c26101808a018a6138fd565b5050565b468503610dd85760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b6000610de48383610f3b565b905080341015610e295760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b336001600160a01b03167f172762498a59a3bc4fed3f2b63f94f17ea0193cffdc304fe7d3eaf4d342d2f6688888888888834604051610e6e9796959493929190613947565b60405180910390a250505050505050565b33610e926000546001600160a01b031690565b6001600160a01b031614610ed65760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b600a55565b6000610ee68861259d565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600781526020017f4d65737361676500000000000000000000000000000000000000000000000000815250612654565b50505050505050505050565b600254600090610f4b9083613994565b600154610f5891906139ab565b90505b92915050565b33610f746000546001600160a01b031690565b6001600160a01b031614610fb85760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166110005760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527fbf9977180dc6e6cff25598c8e59150cecd7f8e448e092633d38ab7ee223ae05890602001610701565b611061610d526040830160208401613895565b610d9361106e82806138b6565b602084016110806101408601866138fd565b61108e6101608801886138fd565b6102936101808a018a6138fd565b60006110a788611902565b90506000808281526004602081905260409091205460ff16908111156110cf576110cf6134e3565b1461111c5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572526566756e64000000000000006054820152606d01604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e61010001356040516020016111db959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401611212979695949392919061377f565b60006040518083038186803b15801561122a57600080fd5b505afa15801561123e573d6000803e3d6000fd5b505050506000806112508b8e8e6128a8565b90506001816002811115611266576112666134e3565b036112745760019150610cef565b6002816002811115611288576112886134e3565b03610cea576000848152600460205260408120805460ff1916600183610c58565b6112b48383836128ff565b336001600160a01b03167fe66fbe37d84ca73c589f782ac278844918ea6c56a4917f58707f715588080df28686868686346040516112f7969594939291906139be565b60405180910390a25050505050565b336113196000546001600160a01b031690565b6001600160a01b03161461135d5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166113a55760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb337a6c76476534518d5816caeb86263972470fedccfd047a35eb1825eaa9e890602001610701565b336114066000546001600160a01b031690565b6001600160a01b03161461144a5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166114925760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527fa9db0c32d9c6c2f75f3b95047a9e67cc1c010eab792a4e6ca777ce918ad94aad90602001610701565b6114eb8383836128ff565b336001600160a01b03167fce3972bfffe49d317e1d128047a97a3d86b25c94f6f04409f988ef854d25e0e4858585853460405161152c9594939291906139ff565b60405180910390a250505050565b600061154588612997565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600881526020017f4d65737361676532000000000000000000000000000000000000000000000000815250612654565b336115a16000546001600160a01b031690565b6001600160a01b0316146115e55760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60028190556040518181527f210d4d5d2d36d571207dac98e383e2441c684684c885fb2d7c54f8d24422074c90602001610701565b3361162d6000546001600160a01b031690565b6001600160a01b0316146116715760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166116ed5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610666565b6116f681612a2d565b50565b3361170c6000546001600160a01b031690565b6001600160a01b0316146117505760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166117985760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527f918a691a2a82482a10e11f43d7b627b2ba220dd08f251cb61933c42560f6fcb590602001610701565b6000546001600160a01b03161561183f5760405162461bcd60e51b815260206004820152601160248201527f6f776e657220616c7265616479207365740000000000000000000000000000006044820152606401610666565b61184833612a2d565b565b6005546001600160a01b0316156118a35760405162461bcd60e51b815260206004820152601b60248201527f6c697175696469747942726964676520616c72656164792073657400000000006044820152606401610666565b600580546001600160a01b03199081166001600160a01b03978816179091556006805482169587169590951790945560078054851693861693909317909255600880548416918516919091179055600980549092169216919091179055565b6000808060016119156020860186613895565b6006811115611926576119266134e3565b03611ab15761193b6040850160208601612f40565b61194b6060860160408701612f40565b61195b6080870160608801612f40565b608087013561197060e0890160c08a01613828565b6040516001600160601b0319606096871b8116602083015294861b851660348201529290941b9092166048820152605c8101919091526001600160c01b031960c092831b8116607c8301524690921b909116608482015260e0850135608c82015260ac0160408051808303601f19018152908290528051602090910120600554633c64f04b60e01b8352600483018290529093506001600160a01b031691508190633c64f04b90602401602060405180830381865afa158015611a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5b9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601660248201527f6272696467652072656c6179206e6f74206578697374000000000000000000006044820152606401610666565b612136565b6002611ac06020860186613895565b6006811115611ad157611ad16134e3565b03611c2e5746611ae760c0860160a08701613828565b611af76060870160408801612f40565b611b076080880160608901612f40565b6040516001600160c01b031960c095861b811660208301529390941b90921660288401526001600160601b0319606091821b8116603085015291901b1660448201526080850135605882015260780160408051808303601f19018152908290528051602090910120600554631c13568560e31b8352600483018290529093506001600160a01b03169150819063e09ab42890602401602060405180830381865afa158015611bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdd9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f627269646765207769746864726177206e6f74206578697374000000000000006044820152606401610666565b6003611c3d6020860186613895565b6006811115611c4e57611c4e6134e3565b1480611c7757506004611c646020860186613895565b6006811115611c7557611c756134e3565b145b15611eda57611c8c6060850160408601612f40565b611c9c6080860160608701612f40565b6080860135611cb16040880160208901612f40565b611cc160e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b851660348201526048810193909352931b909116606882015260c09190911b6001600160c01b031916607c82015260e0850135608482015260a40160408051601f19818403018152919052805160209091012091506003611d416020860186613895565b6006811115611d5257611d526134e3565b03611e1957506006546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e64725906024015b602060405180830381865afa158015611da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc89190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601560248201527f6d696e74207265636f7264206e6f7420657869737400000000000000000000006044820152606401610666565b506007546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e6472590602401602060405180830381865afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6005611ee96020860186613895565b6006811115611efa57611efa6134e3565b1480611f2357506006611f106020860186613895565b6006811115611f2157611f216134e3565b145b15612136576005611f376020860186613895565b6006811115611f4857611f486134e3565b03611f5f57506008546001600160a01b0316611f6d565b506009546001600160a01b03165b611f7d6060850160408601612f40565b611f8d6080860160608701612f40565b6080860135611fa26040880160208901612f40565b611fb260e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b85166034820152604881019390935290841b8316606883015260c01b6001600160c01b031916607c82015260e087013560848201529183901b1660a482015260b80160408051601f198184030181529190528051602090910120915060056120396020860186613895565b600681111561204a5761204a6134e3565b0361207c576040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401611d87565b6040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401602060405180830381865afa1580156120c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e59190613a3a565b15156001146121365760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6000818360405160200161214c93929190613a73565b6040516020818303038152906040528051906020012092505050919050565b6000805a90506000806121846060880160408901612f40565b6001600160a01b031634631f34afff60e21b6121a660408b0160208c01612f40565b6121b660808c0160608d01612f40565b60808c01356121cb60e08e0160c08f01613828565b8c8c336040516024016121e49796959493929190613a9f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122229190613af8565b60006040518083038185875af1925050503d806000811461225f576040519150601f19603f3d011682016040523d82523d6000602084013e612264565b606091505b5091509150811561228d57808060200190518101906122839190613b14565b935050505061229f565b6122978382612a7d565b600093505050505b9392505050565b6000805a90506000806122bf6060880160408901612f40565b6001600160a01b031634632d5bd7e360e11b6121a660408b0160208c01612f40565b6122f16060820160408301612f40565b6001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6000858561232f60e0870160c08801613828565b866101000135604051612346959493929190613b35565b60405180910390a2505050565b6001826006811115612367576123676134e3565b03612407576005546001600160a01b031663cdd1b25d61238783806138b6565b61239460208601866138fd565b6123a160408801886138fd565b6123ae60608a018a6138fd565b6040518963ffffffff1660e01b81526004016123d1989796959493929190613b73565b600060405180830381600087803b1580156123eb57600080fd5b505af11580156123ff573d6000803e3d6000fd5b505050505050565b600282600681111561241b5761241b6134e3565b0361243b576005546001600160a01b031663a21a928061238783806138b6565b600382600681111561244f5761244f6134e3565b0361246f576006546001600160a01b031663f873430261238783806138b6565b6005826006811115612483576124836134e3565b03612535576008546001600160a01b031663f87343026124a383806138b6565b6124b060208601866138fd565b6124bd60408801886138fd565b6124ca60608a018a6138fd565b6040518963ffffffff1660e01b81526004016124ed989796959493929190613b73565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190613bd3565b505050565b6004826006811115612549576125496134e3565b03612569576007546001600160a01b031663a21a928061238783806138b6565b600682600681111561257d5761257d6134e3565b03610d93576009546001600160a01b031663a21a92806124a383806138b6565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a08101909152806125e26020850185612f40565b6001600160a01b031681526020016040518060200160405280600081525081526020018360200160208101906126189190612f40565b6001600160a01b031681526020016126366060850160408601613828565b67ffffffffffffffff16815260200183606001358152509050919050565b6000612661898c8c612b08565b90506000808281526004602081905260409091205460ff1690811115612689576126896134e3565b146126d65760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c726561647920657865637574656400000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff191690931790925590516127059146913091879101613bec565b60408051601f1981840301815282825280516020918201206005549184018190528383018690528251808503840181526060850193849052633416de1160e11b90935293506001600160a01b03169163682dbc2291612772918d908d908d908d908d908d9060640161377f565b60006040518083038186803b15801561278a57600080fd5b505afa15801561279e573d6000803e3d6000fd5b505050506000806127b08c8f8f612b9c565b905060018160028111156127c6576127c66134e3565b036127d45760019150612858565b60028160028111156127e8576127e86134e3565b036128535760008481526004602052604090819020805460ff1916905560608d015160808e015191517fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c9261284292600192899290613862565b60405180910390a150505050610f2f565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115612888576128886134e3565b021790555061289884838e612d7d565b5050505050505050505050505050565b6000805a90506000806128c16060880160408901612f40565b6001600160a01b0316346305e5a4c160e11b6128e360808b0160608c01612f40565b8a608001358a8a336040516024016121e4959493929190613c2b565b4683036129405760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b600061294c8383610f3b565b9050803410156129915760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b50505050565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a0810190915260008152602081016129e084806138b6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020908101906126189060408601908601612f40565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005a90506000600a5445612a9291906137f3565b90508084108015612aad5750612aa9604085613c6a565b8211155b15612ab457fe5b6000612abf84612dcb565b9050612aca81612e2a565b7fffdd6142bbb721f3400e3908b04b86f60649b2e4d191e3f4c50c32c3e6471d2f81604051612af99190613c8c565b60405180910390a15050505050565b60208301518051600091908203612b50578451604051612b3e919060200160609190911b6001600160601b031916815260140190565b60405160208183030381529060405290505b600181866040015187606001518860800151468989604051602001612b7c989796959493929190613c9f565b604051602081830303815290604052805190602001209150509392505050565b6000805a905060006060866020015151600003612c8c5786604001516001600160a01b0316346040518060600160405280602c8152602001613ee3602c91398051602090910120895160608b0151604051612c019291908c908c903390602401613d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c3f9190613af8565b60006040518083038185875af1925050503d8060008114612c7c576040519150601f19603f3d011682016040523d82523d6000602084013e612c81565b606091505b509092509050612d63565b86604001516001600160a01b0316346040518060600160405280602a8152602001613e99602a91398051906020012089602001518a606001518a8a33604051602401612cdc959493929190613d54565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612d1a9190613af8565b60006040518083038185875af1925050503d8060008114612d57576040519150601f19603f3d011682016040523d82523d6000602084013e612d5c565b606091505b5090925090505b811561228d57808060200190518101906122839190613b14565b80604001516001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6001858585606001518660800151604051612346959493929190613b35565b6060604482511015612e1057505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b60048201915081806020019051810190610f5b9190613dbc565b60408051808201909152600b8082527f4d53473a3a41424f52543a000000000000000000000000000000000000000000602083015282518391116125305760005b8251811015612f0957828181518110612e8657612e86613e69565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916828281518110612ec557612ec5613e69565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612ef75750505050565b80612f0181613e7f565b915050612e6b565b508260405162461bcd60e51b81526004016106669190613c8c565b80356001600160a01b0381168114612f3b57600080fd5b919050565b600060208284031215612f5257600080fd5b610f5882612f24565b600060208284031215612f6d57600080fd5b5035919050565b60008083601f840112612f8657600080fd5b50813567ffffffffffffffff811115612f9e57600080fd5b6020830191508360208260051b8501011115612fb957600080fd5b9250929050565b60008060008060008060008060a0898b031215612fdc57600080fd5b612fe589612f24565b975060208901359650604089013567ffffffffffffffff8082111561300957600080fd5b6130158c838d01612f74565b909850965060608b013591508082111561302e57600080fd5b61303a8c838d01612f74565b909650945060808b013591508082111561305357600080fd5b506130608b828c01612f74565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561308c57600080fd5b61309586612f24565b94506130a360208701612f24565b93506130b160408701612f24565b92506130bf60608701612f24565b91506130cd60808701612f24565b90509295509295909350565b60008083601f8401126130eb57600080fd5b50813567ffffffffffffffff81111561310357600080fd5b602083019150836020828501011115612fb957600080fd5b6000806000806000806000806000898b036101a081121561313b57600080fd5b8a3567ffffffffffffffff8082111561315357600080fd5b61315f8e838f016130d9565b909c509a508a9150610120601f198401121561317a57600080fd5b60208d0199506101408d013592508083111561319557600080fd5b6131a18e848f01612f74565b90995097506101608d01359250889150808311156131be57600080fd5b6131ca8e848f01612f74565b90975095506101808d01359250869150808311156131e757600080fd5b50506131f58c828d01612f74565b915080935050809150509295985092959850929598565b60006080828403121561321e57600080fd5b50919050565b6000806040838503121561323757600080fd5b823567ffffffffffffffff8082111561324f57600080fd5b61325b8683870161320c565b9350602085013591508082111561327157600080fd5b5083016101a0818603121561328557600080fd5b809150509250929050565b60008060008060008060a087890312156132a957600080fd5b6132b287612f24565b9550602087013594506132c760408801612f24565b935060608701359250608087013567ffffffffffffffff8111156132ea57600080fd5b6132f689828a016130d9565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c03121561332757600080fd5b893567ffffffffffffffff8082111561333f57600080fd5b61334b8d838e016130d9565b909b5099508991506133608d60208e0161320c565b985060a08c013591508082111561337657600080fd5b6133828d838e01612f74565b909850965060c08c013591508082111561339b57600080fd5b6133a78d838e01612f74565b909650945060e08c01359150808211156133c057600080fd5b506131f58c828d01612f74565b600080602083850312156133e057600080fd5b823567ffffffffffffffff8111156133f757600080fd5b613403858286016130d9565b90969095509350505050565b60008060008060006060868803121561342757600080fd5b853567ffffffffffffffff8082111561343f57600080fd5b61344b89838a016130d9565b909750955060208801359450604088013591508082111561346b57600080fd5b50613478888289016130d9565b969995985093965092949392505050565b6000806000806060858703121561349f57600080fd5b6134a885612f24565b935060208501359250604085013567ffffffffffffffff8111156134cb57600080fd5b6134d7878288016130d9565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b60058110613509576135096134e3565b9052565b60208101610f5b82846134f9565b600080600080600080600080600060a08a8c03121561353957600080fd5b893567ffffffffffffffff8082111561355157600080fd5b61355d8d838e016130d9565b909b50995060208c013591508082111561357657600080fd5b6135828d838e0161320c565b985060408c013591508082111561359857600080fd5b6135a48d838e01612f74565b909850965060608c01359150808211156135bd57600080fd5b6135c98d838e01612f74565b909650945060808c01359150808211156133c057600080fd5b60005b838110156135fd5781810151838201526020016135e5565b50506000910152565b6000815180845261361e8160208601602086016135e2565b601f01601f19169290920160200192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b81835260006020808501808196508560051b810191508460005b878110156136e05782840389528135601e1988360301811261369657600080fd5b8701858101903567ffffffffffffffff8111156136b257600080fd5b8036038213156136c157600080fd5b6136cc868284613632565b9a87019a9550505090840190600101613675565b5091979650505050505050565b8183526000602080850194508260005b85811015613729576001600160a01b0361371683612f24565b16875295820195908201906001016136fd565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561376657600080fd5b8260051b80836020870137939093016020019392505050565b608081526000613792608083018a613606565b82810360208401526137a581898b61365b565b905082810360408401526137ba8187896136ed565b905082810360608401526137cf818587613734565b9a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f5b57610f5b6137dd565b8581528460208201528284604083013760409201918201526060019392505050565b60006020828403121561383a57600080fd5b813567ffffffffffffffff8116811461229f57600080fd5b60028110613509576135096134e3565b608081016138708287613852565b84602083015267ffffffffffffffff8416604083015282606083015295945050505050565b6000602082840312156138a757600080fd5b81356007811061229f57600080fd5b6000808335601e198436030181126138cd57600080fd5b83018035915067ffffffffffffffff8211156138e857600080fd5b602001915036819003821315612fb957600080fd5b6000808335601e1984360301811261391457600080fd5b83018035915067ffffffffffffffff82111561392f57600080fd5b6020019150600581901b3603821315612fb957600080fd5b60006001600160a01b03808a16835288602084015280881660408401525085606083015260c0608083015261398060c083018587613632565b90508260a083015298975050505050505050565b8082028115828204841417610f5b57610f5b6137dd565b80820180821115610f5b57610f5b6137dd565b6080815260006139d260808301888a613632565b86602084015282810360408401526139eb818688613632565b915050826060830152979650505050505050565b6001600160a01b0386168152846020820152608060408201526000613a28608083018587613632565b90508260608301529695505050505050565b600060208284031215613a4c57600080fd5b8151801515811461229f57600080fd5b60028110613a6c57613a6c6134e3565b60f81b9052565b613a7d8185613a5c565b60609290921b6001600160601b03191660018301526015820152603501919050565b60006001600160a01b03808a168352808916602084015287604084015267ffffffffffffffff8716606084015260c06080840152613ae160c084018688613632565b915080841660a08401525098975050505050505050565b60008251613b0a8184602087016135e2565b9190910192915050565b600060208284031215613b2657600080fd5b81516003811061229f57600080fd5b60a08101613b438288613852565b856020830152613b5660408301866134f9565b67ffffffffffffffff939093166060820152608001529392505050565b608081526000613b87608083018a8c613632565b8281036020840152613b9a81898b61365b565b90508281036040840152613baf8187896136ed565b90508281036060840152613bc4818587613734565b9b9a5050505050505050505050565b600060208284031215613be557600080fd5b5051919050565b8381526bffffffffffffffffffffffff198360601b16602082015260008251613c1c8160348501602087016135e2565b91909101603401949350505050565b60006001600160a01b03808816835286602084015260806040840152613c55608084018688613632565b91508084166060840152509695505050505050565b600082613c8757634e487b7160e01b600052601260045260246000fd5b500490565b602081526000610f586020830184613606565b613ca9818a613a5c565b60008851613cbe816001850160208d016135e2565b80830190506bffffffffffffffffffffffff198960601b1660018201526001600160c01b0319808960c01b16601583015287601d830152808760c01b16603d830152508385604583013760009301604501928352509098975050505050505050565b60006001600160a01b03808816835267ffffffffffffffff8716602084015260806040840152613c55608084018688613632565b608081526000613d676080830188613606565b67ffffffffffffffff871660208401528281036040840152613d8a818688613632565b9150506001600160a01b03831660608301529695505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215613dce57600080fd5b815167ffffffffffffffff80821115613de657600080fd5b818401915084601f830112613dfa57600080fd5b815181811115613e0c57613e0c613da6565b604051601f8201601f19908116603f01168101908382118183101715613e3457613e34613da6565b81604052828152876020848701011115613e4d57600080fd5b613e5e8360208301602088016135e2565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613e9157613e916137dd565b506001019056fe657865637574654d6573736167652862797465732c75696e7436342c62797465732c61646472657373294f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572657865637574654d65737361676528616464726573732c75696e7436342c62797465732c6164647265737329a2646970667358221220006def5a78ed98e487079542720cb6f70211c18a567430956ef44d12536e22c464736f6c63430008110033