- 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