Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- MessageBus
- Optimization enabled
- true
- Compiler version
- v0.8.17+commit.8df45f5f
- Optimization runs
- 800
- Verified at
- 2023-03-02T06:07:48.684771Z
Constructor Arguments
0000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f0000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009bb46d5100d2db4608112026951c9c965b233f4d0000000000000000000000000000000000000000000000000000000000000000
Arg [0] (address) : 0x9b36f165bab9ebe611d491180418d8de4b8f3a1f
Arg [1] (address) : 0x9b36f165bab9ebe611d491180418d8de4b8f3a1f
Arg [2] (address) : 0x0000000000000000000000000000000000000000
Arg [3] (address) : 0x0000000000000000000000000000000000000000
Arg [4] (address) : 0x9bb46d5100d2db4608112026951c9c965b233f4d
Arg [5] (address) : 0x0000000000000000000000000000000000000000
./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/libraries/Utils.sol
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; library Utils { // 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) internal 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 } }
./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"; import "../../libraries/Utils.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 = Utils.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); } 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); } }
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"],"":["id","ast"]}},"optimizer":{"runs":800,"enabled":true},"metadata":{"useLiteralContent":true}}
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"}]}]
Contract Creation Code
0x60a06040523480156200001157600080fd5b50604051620041183803806200411883398101604081905262000034916200011d565b84848484848a6200004533620000b4565b6001600160a01b03908116608052600580546001600160a01b0319908116978316979097179055600680548716958216959095179094556007805486169385169390931790925560088054851691841691909117905560098054909316911617905550620001b1945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200011a57600080fd5b50565b60008060008060008060c087890312156200013757600080fd5b8651620001448162000104565b6020880151909650620001578162000104565b60408801519095506200016a8162000104565b60608801519094506200017d8162000104565b6080880151909350620001908162000104565b60a0880151909250620001a38162000104565b809150509295509295509295565b608051613f44620001d4600039600081816104eb01526108430152613f446000f3fe6080604052600436106101fe5760003560e01c806382980dc41161011d578063ccf2683b116100b0578063dfa2dbaf1161007f578063f2fde38b11610064578063f2fde38b146105bd578063f60bbe2a146105dd578063f83b0fb9146105f357600080fd5b8063dfa2dbaf1461057d578063e2c1ed251461059d57600080fd5b8063ccf2683b146104d9578063cd2abd661461050d578063d8257d171461054a578063db2c20c81461056a57600080fd5b806395e911a8116100ec57806395e911a8146104705780639b05a775146104865780639f3ce55a146104a6578063c66a9c5a146104b957600080fd5b806382980dc4146103da57806382efd502146104125780638da5cb5b1461043257806395b12c271461045057600080fd5b8063468a2d04116101955780635b3e5f50116101645780635b3e5f5014610367578063723d0a9d146103945780637b80ab20146103b45780637d7a101d146103c757600080fd5b8063468a2d04146102eb5780635335dca2146102fe578063584e45e114610331578063588be02b1461034757600080fd5b80633f395aff116101d15780633f395aff1461028557806340d0d026146102985780634289fbb3146102b85780634586f331146102cb57600080fd5b806303cbfe661461020357806306c28bd6146102255780632ff4c41114610245578063359ef75b14610265575b600080fd5b34801561020f57600080fd5b5061022361021e366004612f40565b610613565b005b34801561023157600080fd5b50610223610240366004612f5b565b61070c565b34801561025157600080fd5b50610223610260366004612fc0565b610798565b34801561027157600080fd5b50610223610280366004613074565b610a33565b61022361029336600461311b565b610a4f565b3480156102a457600080fd5b506102236102b3366004613224565b610d3f565b6102236102c6366004613290565b610d97565b3480156102d757600080fd5b506102236102e6366004612f5b565b610e7f565b6102236102f9366004613308565b610edb565b34801561030a57600080fd5b5061031e6103193660046133cd565b610f3b565b6040519081526020015b60405180910390f35b34801561033d57600080fd5b5061031e600a5481565b34801561035357600080fd5b50610223610362366004612f40565b610f61565b34801561037357600080fd5b5061031e610382366004612f40565b60036020526000908152604090205481565b3480156103a057600080fd5b506102236103af366004613224565b61104e565b6102236103c236600461311b565b61109c565b6102236103d536600461340f565b6112a9565b3480156103e657600080fd5b506005546103fa906001600160a01b031681565b6040516001600160a01b039091168152602001610328565b34801561041e57600080fd5b5061022361042d366004612f40565b611306565b34801561043e57600080fd5b506000546001600160a01b03166103fa565b34801561045c57600080fd5b506008546103fa906001600160a01b031681565b34801561047c57600080fd5b5061031e60015481565b34801561049257600080fd5b506102236104a1366004612f40565b6113f3565b6102236104b4366004613489565b6114e0565b3480156104c557600080fd5b506009546103fa906001600160a01b031681565b3480156104e557600080fd5b506103fa7f000000000000000000000000000000000000000000000000000000000000000081565b34801561051957600080fd5b5061053d610528366004612f5b565b60046020526000908152604090205460ff1681565b604051610328919061350d565b34801561055657600080fd5b506007546103fa906001600160a01b031681565b61022361057836600461351b565b61153a565b34801561058957600080fd5b506006546103fa906001600160a01b031681565b3480156105a957600080fd5b506102236105b8366004612f5b565b61158e565b3480156105c957600080fd5b506102236105d8366004612f40565b61161a565b3480156105e957600080fd5b5061031e60025481565b3480156105ff57600080fd5b5061022361060e366004612f40565b6116f9565b336106266000546001600160a01b031690565b6001600160a01b03161461066f5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec383398151915260448201526064015b60405180910390fd5b6001600160a01b0381166106b75760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fd60e9ceb4f54f1bfb1741a4b35fc9d806d7ed48200b523203b92248ea38fa17d906020015b60405180910390a150565b3361071f6000546001600160a01b031690565b6001600160a01b0316146107635760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60018190556040518181527f892dfdc99ecd3bb4f2f2cb118dca02f0bd16640ff156d3c6459d4282e336a5f290602001610701565b600046306040516020016107e992919091825260601b6001600160601b03191660208201527f77697468647261774665650000000000000000000000000000000000000000006034820152603f0190565b60408051808303601f19018152828252805160209182012090830181905260608c901b6001600160601b0319168383015260548084018c9052825180850390910181526074840192839052633416de1160e11b90925292507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163682dbc229161088a918b908b908b908b908b908b9060780161377f565b60006040518083038186803b1580156108a257600080fd5b505afa1580156108b6573d6000803e3d6000fd5b505050506001600160a01b0389166000908152600360205260408120546108dd908a6137f3565b90506000811161092f5760405162461bcd60e51b815260206004820152601960248201527f4e6f206e657720616d6f756e7420746f207769746864726177000000000000006044820152606401610666565b6001600160a01b038a166000818152600360205260408082208c90555190919061c35090849084818181858888f193505050503d806000811461098e576040519150601f19603f3d011682016040523d82523d6000602084013e610993565b606091505b50509050806109e45760405162461bcd60e51b815260206004820152601660248201527f6661696c656420746f20776974686472617720666565000000000000000000006044820152606401610666565b604080516001600160a01b038d168152602081018490527f78473f3f373f7673597f4f0fa5873cb4d375fea6d4339ad6b56dbd411513cb3f910160405180910390a15050505050505050505050565b610a3b6117e6565b610a48858585858561184a565b5050505050565b6000610a5a88611902565b90506000808281526004602081905260409091205460ff1690811115610a8257610a826134e3565b14610acf5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572000000000000000000000000006054820152606701604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e6101000135604051602001610b8e959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401610bc5979695949392919061377f565b60006040518083038186803b158015610bdd57600080fd5b505afa158015610bf1573d6000803e3d6000fd5b50505050600080610c038b8e8e61216b565b90506001816002811115610c1957610c196134e3565b03610c275760019150610cef565b6002816002811115610c3b57610c3b6134e3565b03610cbb576000848152600460205260408120805460ff19166001835b02179055507fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c6000858d60c0016020810190610c949190613828565b8e6101000135604051610caa9493929190613862565b60405180910390a150505050610d34565b610cc68b8e8e6122a6565b90506001816002811115610cdc57610cdc6134e3565b03610cea5760039150610cef565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115610d1f57610d1f6134e3565b0217905550610d2f84838d6122e1565b505050505b505050505050505050565b610d58610d526040830160208401613895565b83612353565b610d93610d6582806138b6565b60208401610d776101408601866138fd565b610d856101608801886138fd565b6103c26101808a018a6138fd565b5050565b468503610dd85760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b6000610de48383610f3b565b905080341015610e295760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b336001600160a01b03167f172762498a59a3bc4fed3f2b63f94f17ea0193cffdc304fe7d3eaf4d342d2f6688888888888834604051610e6e9796959493929190613947565b60405180910390a250505050505050565b33610e926000546001600160a01b031690565b6001600160a01b031614610ed65760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b600a55565b6000610ee68861259d565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600781526020017f4d65737361676500000000000000000000000000000000000000000000000000815250612654565b50505050505050505050565b600254600090610f4b9083613994565b600154610f5891906139ab565b90505b92915050565b33610f746000546001600160a01b031690565b6001600160a01b031614610fb85760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166110005760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527fbf9977180dc6e6cff25598c8e59150cecd7f8e448e092633d38ab7ee223ae05890602001610701565b611061610d526040830160208401613895565b610d9361106e82806138b6565b602084016110806101408601866138fd565b61108e6101608801886138fd565b6102936101808a018a6138fd565b60006110a788611902565b90506000808281526004602081905260409091205460ff16908111156110cf576110cf6134e3565b1461111c5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572526566756e64000000000000006054820152606d01604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e61010001356040516020016111db959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401611212979695949392919061377f565b60006040518083038186803b15801561122a57600080fd5b505afa15801561123e573d6000803e3d6000fd5b505050506000806112508b8e8e6128a8565b90506001816002811115611266576112666134e3565b036112745760019150610cef565b6002816002811115611288576112886134e3565b03610cea576000848152600460205260408120805460ff1916600183610c58565b6112b48383836128ff565b336001600160a01b03167fe66fbe37d84ca73c589f782ac278844918ea6c56a4917f58707f715588080df28686868686346040516112f7969594939291906139be565b60405180910390a25050505050565b336113196000546001600160a01b031690565b6001600160a01b03161461135d5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166113a55760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb337a6c76476534518d5816caeb86263972470fedccfd047a35eb1825eaa9e890602001610701565b336114066000546001600160a01b031690565b6001600160a01b03161461144a5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166114925760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527fa9db0c32d9c6c2f75f3b95047a9e67cc1c010eab792a4e6ca777ce918ad94aad90602001610701565b6114eb8383836128ff565b336001600160a01b03167fce3972bfffe49d317e1d128047a97a3d86b25c94f6f04409f988ef854d25e0e4858585853460405161152c9594939291906139ff565b60405180910390a250505050565b600061154588612997565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600881526020017f4d65737361676532000000000000000000000000000000000000000000000000815250612654565b336115a16000546001600160a01b031690565b6001600160a01b0316146115e55760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60028190556040518181527f210d4d5d2d36d571207dac98e383e2441c684684c885fb2d7c54f8d24422074c90602001610701565b3361162d6000546001600160a01b031690565b6001600160a01b0316146116715760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166116ed5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610666565b6116f681612a2d565b50565b3361170c6000546001600160a01b031690565b6001600160a01b0316146117505760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166117985760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527f918a691a2a82482a10e11f43d7b627b2ba220dd08f251cb61933c42560f6fcb590602001610701565b6000546001600160a01b03161561183f5760405162461bcd60e51b815260206004820152601160248201527f6f776e657220616c7265616479207365740000000000000000000000000000006044820152606401610666565b61184833612a2d565b565b6005546001600160a01b0316156118a35760405162461bcd60e51b815260206004820152601b60248201527f6c697175696469747942726964676520616c72656164792073657400000000006044820152606401610666565b600580546001600160a01b03199081166001600160a01b03978816179091556006805482169587169590951790945560078054851693861693909317909255600880548416918516919091179055600980549092169216919091179055565b6000808060016119156020860186613895565b6006811115611926576119266134e3565b03611ab15761193b6040850160208601612f40565b61194b6060860160408701612f40565b61195b6080870160608801612f40565b608087013561197060e0890160c08a01613828565b6040516001600160601b0319606096871b8116602083015294861b851660348201529290941b9092166048820152605c8101919091526001600160c01b031960c092831b8116607c8301524690921b909116608482015260e0850135608c82015260ac0160408051808303601f19018152908290528051602090910120600554633c64f04b60e01b8352600483018290529093506001600160a01b031691508190633c64f04b90602401602060405180830381865afa158015611a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5b9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601660248201527f6272696467652072656c6179206e6f74206578697374000000000000000000006044820152606401610666565b612136565b6002611ac06020860186613895565b6006811115611ad157611ad16134e3565b03611c2e5746611ae760c0860160a08701613828565b611af76060870160408801612f40565b611b076080880160608901612f40565b6040516001600160c01b031960c095861b811660208301529390941b90921660288401526001600160601b0319606091821b8116603085015291901b1660448201526080850135605882015260780160408051808303601f19018152908290528051602090910120600554631c13568560e31b8352600483018290529093506001600160a01b03169150819063e09ab42890602401602060405180830381865afa158015611bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdd9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f627269646765207769746864726177206e6f74206578697374000000000000006044820152606401610666565b6003611c3d6020860186613895565b6006811115611c4e57611c4e6134e3565b1480611c7757506004611c646020860186613895565b6006811115611c7557611c756134e3565b145b15611eda57611c8c6060850160408601612f40565b611c9c6080860160608701612f40565b6080860135611cb16040880160208901612f40565b611cc160e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b851660348201526048810193909352931b909116606882015260c09190911b6001600160c01b031916607c82015260e0850135608482015260a40160408051601f19818403018152919052805160209091012091506003611d416020860186613895565b6006811115611d5257611d526134e3565b03611e1957506006546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e64725906024015b602060405180830381865afa158015611da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc89190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601560248201527f6d696e74207265636f7264206e6f7420657869737400000000000000000000006044820152606401610666565b506007546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e6472590602401602060405180830381865afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6005611ee96020860186613895565b6006811115611efa57611efa6134e3565b1480611f2357506006611f106020860186613895565b6006811115611f2157611f216134e3565b145b15612136576005611f376020860186613895565b6006811115611f4857611f486134e3565b03611f5f57506008546001600160a01b0316611f6d565b506009546001600160a01b03165b611f7d6060850160408601612f40565b611f8d6080860160608701612f40565b6080860135611fa26040880160208901612f40565b611fb260e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b85166034820152604881019390935290841b8316606883015260c01b6001600160c01b031916607c82015260e087013560848201529183901b1660a482015260b80160408051601f198184030181529190528051602090910120915060056120396020860186613895565b600681111561204a5761204a6134e3565b0361207c576040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401611d87565b6040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401602060405180830381865afa1580156120c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e59190613a3a565b15156001146121365760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6000818360405160200161214c93929190613a73565b6040516020818303038152906040528051906020012092505050919050565b6000805a90506000806121846060880160408901612f40565b6001600160a01b031634631f34afff60e21b6121a660408b0160208c01612f40565b6121b660808c0160608d01612f40565b60808c01356121cb60e08e0160c08f01613828565b8c8c336040516024016121e49796959493929190613a9f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122229190613af8565b60006040518083038185875af1925050503d806000811461225f576040519150601f19603f3d011682016040523d82523d6000602084013e612264565b606091505b5091509150811561228d57808060200190518101906122839190613b14565b935050505061229f565b6122978382612a7d565b600093505050505b9392505050565b6000805a90506000806122bf6060880160408901612f40565b6001600160a01b031634632d5bd7e360e11b6121a660408b0160208c01612f40565b6122f16060820160408301612f40565b6001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6000858561232f60e0870160c08801613828565b866101000135604051612346959493929190613b35565b60405180910390a2505050565b6001826006811115612367576123676134e3565b03612407576005546001600160a01b031663cdd1b25d61238783806138b6565b61239460208601866138fd565b6123a160408801886138fd565b6123ae60608a018a6138fd565b6040518963ffffffff1660e01b81526004016123d1989796959493929190613b73565b600060405180830381600087803b1580156123eb57600080fd5b505af11580156123ff573d6000803e3d6000fd5b505050505050565b600282600681111561241b5761241b6134e3565b0361243b576005546001600160a01b031663a21a928061238783806138b6565b600382600681111561244f5761244f6134e3565b0361246f576006546001600160a01b031663f873430261238783806138b6565b6005826006811115612483576124836134e3565b03612535576008546001600160a01b031663f87343026124a383806138b6565b6124b060208601866138fd565b6124bd60408801886138fd565b6124ca60608a018a6138fd565b6040518963ffffffff1660e01b81526004016124ed989796959493929190613b73565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190613bd3565b505050565b6004826006811115612549576125496134e3565b03612569576007546001600160a01b031663a21a928061238783806138b6565b600682600681111561257d5761257d6134e3565b03610d93576009546001600160a01b031663a21a92806124a383806138b6565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a08101909152806125e26020850185612f40565b6001600160a01b031681526020016040518060200160405280600081525081526020018360200160208101906126189190612f40565b6001600160a01b031681526020016126366060850160408601613828565b67ffffffffffffffff16815260200183606001358152509050919050565b6000612661898c8c612b08565b90506000808281526004602081905260409091205460ff1690811115612689576126896134e3565b146126d65760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c726561647920657865637574656400000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff191690931790925590516127059146913091879101613bec565b60408051601f1981840301815282825280516020918201206005549184018190528383018690528251808503840181526060850193849052633416de1160e11b90935293506001600160a01b03169163682dbc2291612772918d908d908d908d908d908d9060640161377f565b60006040518083038186803b15801561278a57600080fd5b505afa15801561279e573d6000803e3d6000fd5b505050506000806127b08c8f8f612b9c565b905060018160028111156127c6576127c66134e3565b036127d45760019150612858565b60028160028111156127e8576127e86134e3565b036128535760008481526004602052604090819020805460ff1916905560608d015160808e015191517fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c9261284292600192899290613862565b60405180910390a150505050610f2f565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115612888576128886134e3565b021790555061289884838e612d7d565b5050505050505050505050505050565b6000805a90506000806128c16060880160408901612f40565b6001600160a01b0316346305e5a4c160e11b6128e360808b0160608c01612f40565b8a608001358a8a336040516024016121e4959493929190613c2b565b4683036129405760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b600061294c8383610f3b565b9050803410156129915760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b50505050565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a0810190915260008152602081016129e084806138b6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020908101906126189060408601908601612f40565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005a90506000600a5445612a9291906137f3565b90508084108015612aad5750612aa9604085613c6a565b8211155b15612ab457fe5b6000612abf84612dcb565b9050612aca81612e2a565b7fffdd6142bbb721f3400e3908b04b86f60649b2e4d191e3f4c50c32c3e6471d2f81604051612af99190613c8c565b60405180910390a15050505050565b60208301518051600091908203612b50578451604051612b3e919060200160609190911b6001600160601b031916815260140190565b60405160208183030381529060405290505b600181866040015187606001518860800151468989604051602001612b7c989796959493929190613c9f565b604051602081830303815290604052805190602001209150509392505050565b6000805a905060006060866020015151600003612c8c5786604001516001600160a01b0316346040518060600160405280602c8152602001613ee3602c91398051602090910120895160608b0151604051612c019291908c908c903390602401613d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c3f9190613af8565b60006040518083038185875af1925050503d8060008114612c7c576040519150601f19603f3d011682016040523d82523d6000602084013e612c81565b606091505b509092509050612d63565b86604001516001600160a01b0316346040518060600160405280602a8152602001613e99602a91398051906020012089602001518a606001518a8a33604051602401612cdc959493929190613d54565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612d1a9190613af8565b60006040518083038185875af1925050503d8060008114612d57576040519150601f19603f3d011682016040523d82523d6000602084013e612d5c565b606091505b5090925090505b811561228d57808060200190518101906122839190613b14565b80604001516001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6001858585606001518660800151604051612346959493929190613b35565b6060604482511015612e1057505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b60048201915081806020019051810190610f5b9190613dbc565b60408051808201909152600b8082527f4d53473a3a41424f52543a000000000000000000000000000000000000000000602083015282518391116125305760005b8251811015612f0957828181518110612e8657612e86613e69565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916828281518110612ec557612ec5613e69565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612ef75750505050565b80612f0181613e7f565b915050612e6b565b508260405162461bcd60e51b81526004016106669190613c8c565b80356001600160a01b0381168114612f3b57600080fd5b919050565b600060208284031215612f5257600080fd5b610f5882612f24565b600060208284031215612f6d57600080fd5b5035919050565b60008083601f840112612f8657600080fd5b50813567ffffffffffffffff811115612f9e57600080fd5b6020830191508360208260051b8501011115612fb957600080fd5b9250929050565b60008060008060008060008060a0898b031215612fdc57600080fd5b612fe589612f24565b975060208901359650604089013567ffffffffffffffff8082111561300957600080fd5b6130158c838d01612f74565b909850965060608b013591508082111561302e57600080fd5b61303a8c838d01612f74565b909650945060808b013591508082111561305357600080fd5b506130608b828c01612f74565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561308c57600080fd5b61309586612f24565b94506130a360208701612f24565b93506130b160408701612f24565b92506130bf60608701612f24565b91506130cd60808701612f24565b90509295509295909350565b60008083601f8401126130eb57600080fd5b50813567ffffffffffffffff81111561310357600080fd5b602083019150836020828501011115612fb957600080fd5b6000806000806000806000806000898b036101a081121561313b57600080fd5b8a3567ffffffffffffffff8082111561315357600080fd5b61315f8e838f016130d9565b909c509a508a9150610120601f198401121561317a57600080fd5b60208d0199506101408d013592508083111561319557600080fd5b6131a18e848f01612f74565b90995097506101608d01359250889150808311156131be57600080fd5b6131ca8e848f01612f74565b90975095506101808d01359250869150808311156131e757600080fd5b50506131f58c828d01612f74565b915080935050809150509295985092959850929598565b60006080828403121561321e57600080fd5b50919050565b6000806040838503121561323757600080fd5b823567ffffffffffffffff8082111561324f57600080fd5b61325b8683870161320c565b9350602085013591508082111561327157600080fd5b5083016101a0818603121561328557600080fd5b809150509250929050565b60008060008060008060a087890312156132a957600080fd5b6132b287612f24565b9550602087013594506132c760408801612f24565b935060608701359250608087013567ffffffffffffffff8111156132ea57600080fd5b6132f689828a016130d9565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c03121561332757600080fd5b893567ffffffffffffffff8082111561333f57600080fd5b61334b8d838e016130d9565b909b5099508991506133608d60208e0161320c565b985060a08c013591508082111561337657600080fd5b6133828d838e01612f74565b909850965060c08c013591508082111561339b57600080fd5b6133a78d838e01612f74565b909650945060e08c01359150808211156133c057600080fd5b506131f58c828d01612f74565b600080602083850312156133e057600080fd5b823567ffffffffffffffff8111156133f757600080fd5b613403858286016130d9565b90969095509350505050565b60008060008060006060868803121561342757600080fd5b853567ffffffffffffffff8082111561343f57600080fd5b61344b89838a016130d9565b909750955060208801359450604088013591508082111561346b57600080fd5b50613478888289016130d9565b969995985093965092949392505050565b6000806000806060858703121561349f57600080fd5b6134a885612f24565b935060208501359250604085013567ffffffffffffffff8111156134cb57600080fd5b6134d7878288016130d9565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b60058110613509576135096134e3565b9052565b60208101610f5b82846134f9565b600080600080600080600080600060a08a8c03121561353957600080fd5b893567ffffffffffffffff8082111561355157600080fd5b61355d8d838e016130d9565b909b50995060208c013591508082111561357657600080fd5b6135828d838e0161320c565b985060408c013591508082111561359857600080fd5b6135a48d838e01612f74565b909850965060608c01359150808211156135bd57600080fd5b6135c98d838e01612f74565b909650945060808c01359150808211156133c057600080fd5b60005b838110156135fd5781810151838201526020016135e5565b50506000910152565b6000815180845261361e8160208601602086016135e2565b601f01601f19169290920160200192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b81835260006020808501808196508560051b810191508460005b878110156136e05782840389528135601e1988360301811261369657600080fd5b8701858101903567ffffffffffffffff8111156136b257600080fd5b8036038213156136c157600080fd5b6136cc868284613632565b9a87019a9550505090840190600101613675565b5091979650505050505050565b8183526000602080850194508260005b85811015613729576001600160a01b0361371683612f24565b16875295820195908201906001016136fd565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561376657600080fd5b8260051b80836020870137939093016020019392505050565b608081526000613792608083018a613606565b82810360208401526137a581898b61365b565b905082810360408401526137ba8187896136ed565b905082810360608401526137cf818587613734565b9a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f5b57610f5b6137dd565b8581528460208201528284604083013760409201918201526060019392505050565b60006020828403121561383a57600080fd5b813567ffffffffffffffff8116811461229f57600080fd5b60028110613509576135096134e3565b608081016138708287613852565b84602083015267ffffffffffffffff8416604083015282606083015295945050505050565b6000602082840312156138a757600080fd5b81356007811061229f57600080fd5b6000808335601e198436030181126138cd57600080fd5b83018035915067ffffffffffffffff8211156138e857600080fd5b602001915036819003821315612fb957600080fd5b6000808335601e1984360301811261391457600080fd5b83018035915067ffffffffffffffff82111561392f57600080fd5b6020019150600581901b3603821315612fb957600080fd5b60006001600160a01b03808a16835288602084015280881660408401525085606083015260c0608083015261398060c083018587613632565b90508260a083015298975050505050505050565b8082028115828204841417610f5b57610f5b6137dd565b80820180821115610f5b57610f5b6137dd565b6080815260006139d260808301888a613632565b86602084015282810360408401526139eb818688613632565b915050826060830152979650505050505050565b6001600160a01b0386168152846020820152608060408201526000613a28608083018587613632565b90508260608301529695505050505050565b600060208284031215613a4c57600080fd5b8151801515811461229f57600080fd5b60028110613a6c57613a6c6134e3565b60f81b9052565b613a7d8185613a5c565b60609290921b6001600160601b03191660018301526015820152603501919050565b60006001600160a01b03808a168352808916602084015287604084015267ffffffffffffffff8716606084015260c06080840152613ae160c084018688613632565b915080841660a08401525098975050505050505050565b60008251613b0a8184602087016135e2565b9190910192915050565b600060208284031215613b2657600080fd5b81516003811061229f57600080fd5b60a08101613b438288613852565b856020830152613b5660408301866134f9565b67ffffffffffffffff939093166060820152608001529392505050565b608081526000613b87608083018a8c613632565b8281036020840152613b9a81898b61365b565b90508281036040840152613baf8187896136ed565b90508281036060840152613bc4818587613734565b9b9a5050505050505050505050565b600060208284031215613be557600080fd5b5051919050565b8381526bffffffffffffffffffffffff198360601b16602082015260008251613c1c8160348501602087016135e2565b91909101603401949350505050565b60006001600160a01b03808816835286602084015260806040840152613c55608084018688613632565b91508084166060840152509695505050505050565b600082613c8757634e487b7160e01b600052601260045260246000fd5b500490565b602081526000610f586020830184613606565b613ca9818a613a5c565b60008851613cbe816001850160208d016135e2565b80830190506bffffffffffffffffffffffff198960601b1660018201526001600160c01b0319808960c01b16601583015287601d830152808760c01b16603d830152508385604583013760009301604501928352509098975050505050505050565b60006001600160a01b03808816835267ffffffffffffffff8716602084015260806040840152613c55608084018688613632565b608081526000613d676080830188613606565b67ffffffffffffffff871660208401528281036040840152613d8a818688613632565b9150506001600160a01b03831660608301529695505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215613dce57600080fd5b815167ffffffffffffffff80821115613de657600080fd5b818401915084601f830112613dfa57600080fd5b815181811115613e0c57613e0c613da6565b604051601f8201601f19908116603f01168101908382118183101715613e3457613e34613da6565b81604052828152876020848701011115613e4d57600080fd5b613e5e8360208301602088016135e2565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613e9157613e916137dd565b506001019056fe657865637574654d6573736167652862797465732c75696e7436342c62797465732c61646472657373294f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572657865637574654d65737361676528616464726573732c75696e7436342c62797465732c6164647265737329a264697066735822122059397ddb441e07a9d7962df6708b6dab520de9f19a5724dc4a1f0612110e771a64736f6c634300081100330000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f0000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009bb46d5100d2db4608112026951c9c965b233f4d0000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x6080604052600436106101fe5760003560e01c806382980dc41161011d578063ccf2683b116100b0578063dfa2dbaf1161007f578063f2fde38b11610064578063f2fde38b146105bd578063f60bbe2a146105dd578063f83b0fb9146105f357600080fd5b8063dfa2dbaf1461057d578063e2c1ed251461059d57600080fd5b8063ccf2683b146104d9578063cd2abd661461050d578063d8257d171461054a578063db2c20c81461056a57600080fd5b806395e911a8116100ec57806395e911a8146104705780639b05a775146104865780639f3ce55a146104a6578063c66a9c5a146104b957600080fd5b806382980dc4146103da57806382efd502146104125780638da5cb5b1461043257806395b12c271461045057600080fd5b8063468a2d04116101955780635b3e5f50116101645780635b3e5f5014610367578063723d0a9d146103945780637b80ab20146103b45780637d7a101d146103c757600080fd5b8063468a2d04146102eb5780635335dca2146102fe578063584e45e114610331578063588be02b1461034757600080fd5b80633f395aff116101d15780633f395aff1461028557806340d0d026146102985780634289fbb3146102b85780634586f331146102cb57600080fd5b806303cbfe661461020357806306c28bd6146102255780632ff4c41114610245578063359ef75b14610265575b600080fd5b34801561020f57600080fd5b5061022361021e366004612f40565b610613565b005b34801561023157600080fd5b50610223610240366004612f5b565b61070c565b34801561025157600080fd5b50610223610260366004612fc0565b610798565b34801561027157600080fd5b50610223610280366004613074565b610a33565b61022361029336600461311b565b610a4f565b3480156102a457600080fd5b506102236102b3366004613224565b610d3f565b6102236102c6366004613290565b610d97565b3480156102d757600080fd5b506102236102e6366004612f5b565b610e7f565b6102236102f9366004613308565b610edb565b34801561030a57600080fd5b5061031e6103193660046133cd565b610f3b565b6040519081526020015b60405180910390f35b34801561033d57600080fd5b5061031e600a5481565b34801561035357600080fd5b50610223610362366004612f40565b610f61565b34801561037357600080fd5b5061031e610382366004612f40565b60036020526000908152604090205481565b3480156103a057600080fd5b506102236103af366004613224565b61104e565b6102236103c236600461311b565b61109c565b6102236103d536600461340f565b6112a9565b3480156103e657600080fd5b506005546103fa906001600160a01b031681565b6040516001600160a01b039091168152602001610328565b34801561041e57600080fd5b5061022361042d366004612f40565b611306565b34801561043e57600080fd5b506000546001600160a01b03166103fa565b34801561045c57600080fd5b506008546103fa906001600160a01b031681565b34801561047c57600080fd5b5061031e60015481565b34801561049257600080fd5b506102236104a1366004612f40565b6113f3565b6102236104b4366004613489565b6114e0565b3480156104c557600080fd5b506009546103fa906001600160a01b031681565b3480156104e557600080fd5b506103fa7f0000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f81565b34801561051957600080fd5b5061053d610528366004612f5b565b60046020526000908152604090205460ff1681565b604051610328919061350d565b34801561055657600080fd5b506007546103fa906001600160a01b031681565b61022361057836600461351b565b61153a565b34801561058957600080fd5b506006546103fa906001600160a01b031681565b3480156105a957600080fd5b506102236105b8366004612f5b565b61158e565b3480156105c957600080fd5b506102236105d8366004612f40565b61161a565b3480156105e957600080fd5b5061031e60025481565b3480156105ff57600080fd5b5061022361060e366004612f40565b6116f9565b336106266000546001600160a01b031690565b6001600160a01b03161461066f5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec383398151915260448201526064015b60405180910390fd5b6001600160a01b0381166106b75760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fd60e9ceb4f54f1bfb1741a4b35fc9d806d7ed48200b523203b92248ea38fa17d906020015b60405180910390a150565b3361071f6000546001600160a01b031690565b6001600160a01b0316146107635760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60018190556040518181527f892dfdc99ecd3bb4f2f2cb118dca02f0bd16640ff156d3c6459d4282e336a5f290602001610701565b600046306040516020016107e992919091825260601b6001600160601b03191660208201527f77697468647261774665650000000000000000000000000000000000000000006034820152603f0190565b60408051808303601f19018152828252805160209182012090830181905260608c901b6001600160601b0319168383015260548084018c9052825180850390910181526074840192839052633416de1160e11b90925292507f0000000000000000000000009b36f165bab9ebe611d491180418d8de4b8f3a1f6001600160a01b03169163682dbc229161088a918b908b908b908b908b908b9060780161377f565b60006040518083038186803b1580156108a257600080fd5b505afa1580156108b6573d6000803e3d6000fd5b505050506001600160a01b0389166000908152600360205260408120546108dd908a6137f3565b90506000811161092f5760405162461bcd60e51b815260206004820152601960248201527f4e6f206e657720616d6f756e7420746f207769746864726177000000000000006044820152606401610666565b6001600160a01b038a166000818152600360205260408082208c90555190919061c35090849084818181858888f193505050503d806000811461098e576040519150601f19603f3d011682016040523d82523d6000602084013e610993565b606091505b50509050806109e45760405162461bcd60e51b815260206004820152601660248201527f6661696c656420746f20776974686472617720666565000000000000000000006044820152606401610666565b604080516001600160a01b038d168152602081018490527f78473f3f373f7673597f4f0fa5873cb4d375fea6d4339ad6b56dbd411513cb3f910160405180910390a15050505050505050505050565b610a3b6117e6565b610a48858585858561184a565b5050505050565b6000610a5a88611902565b90506000808281526004602081905260409091205460ff1690811115610a8257610a826134e3565b14610acf5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572000000000000000000000000006054820152606701604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e6101000135604051602001610b8e959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401610bc5979695949392919061377f565b60006040518083038186803b158015610bdd57600080fd5b505afa158015610bf1573d6000803e3d6000fd5b50505050600080610c038b8e8e61216b565b90506001816002811115610c1957610c196134e3565b03610c275760019150610cef565b6002816002811115610c3b57610c3b6134e3565b03610cbb576000848152600460205260408120805460ff19166001835b02179055507fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c6000858d60c0016020810190610c949190613828565b8e6101000135604051610caa9493929190613862565b60405180910390a150505050610d34565b610cc68b8e8e6122a6565b90506001816002811115610cdc57610cdc6134e3565b03610cea5760039150610cef565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115610d1f57610d1f6134e3565b0217905550610d2f84838d6122e1565b505050505b505050505050505050565b610d58610d526040830160208401613895565b83612353565b610d93610d6582806138b6565b60208401610d776101408601866138fd565b610d856101608801886138fd565b6103c26101808a018a6138fd565b5050565b468503610dd85760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b6000610de48383610f3b565b905080341015610e295760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b336001600160a01b03167f172762498a59a3bc4fed3f2b63f94f17ea0193cffdc304fe7d3eaf4d342d2f6688888888888834604051610e6e9796959493929190613947565b60405180910390a250505050505050565b33610e926000546001600160a01b031690565b6001600160a01b031614610ed65760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b600a55565b6000610ee68861259d565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600781526020017f4d65737361676500000000000000000000000000000000000000000000000000815250612654565b50505050505050505050565b600254600090610f4b9083613994565b600154610f5891906139ab565b90505b92915050565b33610f746000546001600160a01b031690565b6001600160a01b031614610fb85760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166110005760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527fbf9977180dc6e6cff25598c8e59150cecd7f8e448e092633d38ab7ee223ae05890602001610701565b611061610d526040830160208401613895565b610d9361106e82806138b6565b602084016110806101408601866138fd565b61108e6101608801886138fd565b6102936101808a018a6138fd565b60006110a788611902565b90506000808281526004602081905260409091205460ff16908111156110cf576110cf6134e3565b1461111c5760405162461bcd60e51b815260206004820152601960248201527f7472616e7366657220616c7265616479206578656375746564000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff1916909317909255815146918101919091526001600160601b03193060601b16918101919091527f4d657373616765576974685472616e73666572526566756e64000000000000006054820152606d01604051602081830303815290604052805190602001209050600560009054906101000a90046001600160a01b03166001600160a01b031663682dbc2282848e8e8e61010001356040516020016111db959493929190613806565b6040516020818303038152906040528a8a8a8a8a8a6040518863ffffffff1660e01b8152600401611212979695949392919061377f565b60006040518083038186803b15801561122a57600080fd5b505afa15801561123e573d6000803e3d6000fd5b505050506000806112508b8e8e6128a8565b90506001816002811115611266576112666134e3565b036112745760019150610cef565b6002816002811115611288576112886134e3565b03610cea576000848152600460205260408120805460ff1916600183610c58565b6112b48383836128ff565b336001600160a01b03167fe66fbe37d84ca73c589f782ac278844918ea6c56a4917f58707f715588080df28686868686346040516112f7969594939291906139be565b60405180910390a25050505050565b336113196000546001600160a01b031690565b6001600160a01b03161461135d5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166113a55760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb337a6c76476534518d5816caeb86263972470fedccfd047a35eb1825eaa9e890602001610701565b336114066000546001600160a01b031690565b6001600160a01b03161461144a5760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166114925760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527fa9db0c32d9c6c2f75f3b95047a9e67cc1c010eab792a4e6ca777ce918ad94aad90602001610701565b6114eb8383836128ff565b336001600160a01b03167fce3972bfffe49d317e1d128047a97a3d86b25c94f6f04409f988ef854d25e0e4858585853460405161152c9594939291906139ff565b60405180910390a250505050565b600061154588612997565b9050610f2f8a8a838a8a8a8a8a8a6040518060400160405280600881526020017f4d65737361676532000000000000000000000000000000000000000000000000815250612654565b336115a16000546001600160a01b031690565b6001600160a01b0316146115e55760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b60028190556040518181527f210d4d5d2d36d571207dac98e383e2441c684684c885fb2d7c54f8d24422074c90602001610701565b3361162d6000546001600160a01b031690565b6001600160a01b0316146116715760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166116ed5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610666565b6116f681612a2d565b50565b3361170c6000546001600160a01b031690565b6001600160a01b0316146117505760405162461bcd60e51b81526020600482018190526024820152600080516020613ec38339815191526044820152606401610666565b6001600160a01b0381166117985760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b6044820152606401610666565b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527f918a691a2a82482a10e11f43d7b627b2ba220dd08f251cb61933c42560f6fcb590602001610701565b6000546001600160a01b03161561183f5760405162461bcd60e51b815260206004820152601160248201527f6f776e657220616c7265616479207365740000000000000000000000000000006044820152606401610666565b61184833612a2d565b565b6005546001600160a01b0316156118a35760405162461bcd60e51b815260206004820152601b60248201527f6c697175696469747942726964676520616c72656164792073657400000000006044820152606401610666565b600580546001600160a01b03199081166001600160a01b03978816179091556006805482169587169590951790945560078054851693861693909317909255600880548416918516919091179055600980549092169216919091179055565b6000808060016119156020860186613895565b6006811115611926576119266134e3565b03611ab15761193b6040850160208601612f40565b61194b6060860160408701612f40565b61195b6080870160608801612f40565b608087013561197060e0890160c08a01613828565b6040516001600160601b0319606096871b8116602083015294861b851660348201529290941b9092166048820152605c8101919091526001600160c01b031960c092831b8116607c8301524690921b909116608482015260e0850135608c82015260ac0160408051808303601f19018152908290528051602090910120600554633c64f04b60e01b8352600483018290529093506001600160a01b031691508190633c64f04b90602401602060405180830381865afa158015611a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5b9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601660248201527f6272696467652072656c6179206e6f74206578697374000000000000000000006044820152606401610666565b612136565b6002611ac06020860186613895565b6006811115611ad157611ad16134e3565b03611c2e5746611ae760c0860160a08701613828565b611af76060870160408801612f40565b611b076080880160608901612f40565b6040516001600160c01b031960c095861b811660208301529390941b90921660288401526001600160601b0319606091821b8116603085015291901b1660448201526080850135605882015260780160408051808303601f19018152908290528051602090910120600554631c13568560e31b8352600483018290529093506001600160a01b03169150819063e09ab42890602401602060405180830381865afa158015611bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdd9190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f627269646765207769746864726177206e6f74206578697374000000000000006044820152606401610666565b6003611c3d6020860186613895565b6006811115611c4e57611c4e6134e3565b1480611c7757506004611c646020860186613895565b6006811115611c7557611c756134e3565b145b15611eda57611c8c6060850160408601612f40565b611c9c6080860160608701612f40565b6080860135611cb16040880160208901612f40565b611cc160e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b851660348201526048810193909352931b909116606882015260c09190911b6001600160c01b031916607c82015260e0850135608482015260a40160408051601f19818403018152919052805160209091012091506003611d416020860186613895565b6006811115611d5257611d526134e3565b03611e1957506006546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e64725906024015b602060405180830381865afa158015611da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc89190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601560248201527f6d696e74207265636f7264206e6f7420657869737400000000000000000000006044820152606401610666565b506007546040516301e6472560e01b8152600481018390526001600160a01b039091169081906301e6472590602401602060405180830381865afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e899190613a3a565b1515600114611aac5760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6005611ee96020860186613895565b6006811115611efa57611efa6134e3565b1480611f2357506006611f106020860186613895565b6006811115611f2157611f216134e3565b145b15612136576005611f376020860186613895565b6006811115611f4857611f486134e3565b03611f5f57506008546001600160a01b0316611f6d565b506009546001600160a01b03165b611f7d6060850160408601612f40565b611f8d6080860160608701612f40565b6080860135611fa26040880160208901612f40565b611fb260e0890160c08a01613828565b604051606095861b6001600160601b0319908116602083015294861b85166034820152604881019390935290841b8316606883015260c01b6001600160c01b031916607c82015260e087013560848201529183901b1660a482015260b80160408051601f198184030181529190528051602090910120915060056120396020860186613895565b600681111561204a5761204a6134e3565b0361207c576040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401611d87565b6040516301e6472560e01b8152600481018390526001600160a01b038216906301e6472590602401602060405180830381865afa1580156120c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e59190613a3a565b15156001146121365760405162461bcd60e51b815260206004820152601960248201527f7769746864726177207265636f7264206e6f74206578697374000000000000006044820152606401610666565b6000818360405160200161214c93929190613a73565b6040516020818303038152906040528051906020012092505050919050565b6000805a90506000806121846060880160408901612f40565b6001600160a01b031634631f34afff60e21b6121a660408b0160208c01612f40565b6121b660808c0160608d01612f40565b60808c01356121cb60e08e0160c08f01613828565b8c8c336040516024016121e49796959493929190613a9f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122229190613af8565b60006040518083038185875af1925050503d806000811461225f576040519150601f19603f3d011682016040523d82523d6000602084013e612264565b606091505b5091509150811561228d57808060200190518101906122839190613b14565b935050505061229f565b6122978382612a7d565b600093505050505b9392505050565b6000805a90506000806122bf6060880160408901612f40565b6001600160a01b031634632d5bd7e360e11b6121a660408b0160208c01612f40565b6122f16060820160408301612f40565b6001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6000858561232f60e0870160c08801613828565b866101000135604051612346959493929190613b35565b60405180910390a2505050565b6001826006811115612367576123676134e3565b03612407576005546001600160a01b031663cdd1b25d61238783806138b6565b61239460208601866138fd565b6123a160408801886138fd565b6123ae60608a018a6138fd565b6040518963ffffffff1660e01b81526004016123d1989796959493929190613b73565b600060405180830381600087803b1580156123eb57600080fd5b505af11580156123ff573d6000803e3d6000fd5b505050505050565b600282600681111561241b5761241b6134e3565b0361243b576005546001600160a01b031663a21a928061238783806138b6565b600382600681111561244f5761244f6134e3565b0361246f576006546001600160a01b031663f873430261238783806138b6565b6005826006811115612483576124836134e3565b03612535576008546001600160a01b031663f87343026124a383806138b6565b6124b060208601866138fd565b6124bd60408801886138fd565b6124ca60608a018a6138fd565b6040518963ffffffff1660e01b81526004016124ed989796959493929190613b73565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190613bd3565b505050565b6004826006811115612549576125496134e3565b03612569576007546001600160a01b031663a21a928061238783806138b6565b600682600681111561257d5761257d6134e3565b03610d93576009546001600160a01b031663a21a92806124a383806138b6565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a08101909152806125e26020850185612f40565b6001600160a01b031681526020016040518060200160405280600081525081526020018360200160208101906126189190612f40565b6001600160a01b031681526020016126366060850160408601613828565b67ffffffffffffffff16815260200183606001358152509050919050565b6000612661898c8c612b08565b90506000808281526004602081905260409091205460ff1690811115612689576126896134e3565b146126d65760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c726561647920657865637574656400000000000000006044820152606401610666565b6000818152600460208181526040808420805460ff191690931790925590516127059146913091879101613bec565b60408051601f1981840301815282825280516020918201206005549184018190528383018690528251808503840181526060850193849052633416de1160e11b90935293506001600160a01b03169163682dbc2291612772918d908d908d908d908d908d9060640161377f565b60006040518083038186803b15801561278a57600080fd5b505afa15801561279e573d6000803e3d6000fd5b505050506000806127b08c8f8f612b9c565b905060018160028111156127c6576127c66134e3565b036127d45760019150612858565b60028160028111156127e8576127e86134e3565b036128535760008481526004602052604090819020805460ff1916905560608d015160808e015191517fe49c2c954d381d1448cf824743aeff9da7a1d82078a7c9e5817269cc359bd26c9261284292600192899290613862565b60405180910390a150505050610f2f565b600291505b60008481526004602081905260409091208054849260ff19909116906001908490811115612888576128886134e3565b021790555061289884838e612d7d565b5050505050505050505050505050565b6000805a90506000806128c16060880160408901612f40565b6001600160a01b0316346305e5a4c160e11b6128e360808b0160608c01612f40565b8a608001358a8a336040516024016121e4959493929190613c2b565b4683036129405760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a590818da185a5b9259608a1b6044820152606401610666565b600061294c8383610f3b565b9050803410156129915760405162461bcd60e51b815260206004820152601060248201526f496e73756666696369656e742066656560801b6044820152606401610666565b50505050565b6040805160a081018252600080825260606020830181905292820181905291810182905260808101919091526040805160a0810190915260008152602081016129e084806138b6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020908101906126189060408601908601612f40565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005a90506000600a5445612a9291906137f3565b90508084108015612aad5750612aa9604085613c6a565b8211155b15612ab457fe5b6000612abf84612dcb565b9050612aca81612e2a565b7fffdd6142bbb721f3400e3908b04b86f60649b2e4d191e3f4c50c32c3e6471d2f81604051612af99190613c8c565b60405180910390a15050505050565b60208301518051600091908203612b50578451604051612b3e919060200160609190911b6001600160601b031916815260140190565b60405160208183030381529060405290505b600181866040015187606001518860800151468989604051602001612b7c989796959493929190613c9f565b604051602081830303815290604052805190602001209150509392505050565b6000805a905060006060866020015151600003612c8c5786604001516001600160a01b0316346040518060600160405280602c8152602001613ee3602c91398051602090910120895160608b0151604051612c019291908c908c903390602401613d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c3f9190613af8565b60006040518083038185875af1925050503d8060008114612c7c576040519150601f19603f3d011682016040523d82523d6000602084013e612c81565b606091505b509092509050612d63565b86604001516001600160a01b0316346040518060600160405280602a8152602001613e99602a91398051906020012089602001518a606001518a8a33604051602401612cdc959493929190613d54565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612d1a9190613af8565b60006040518083038185875af1925050503d8060008114612d57576040519150601f19603f3d011682016040523d82523d6000602084013e612d5c565b606091505b5090925090505b811561228d57808060200190518101906122839190613b14565b80604001516001600160a01b03167fa635eb05143f74743822bbd96428928de4c8ee8cc578299749be9425c17bb34d6001858585606001518660800151604051612346959493929190613b35565b6060604482511015612e1057505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b60048201915081806020019051810190610f5b9190613dbc565b60408051808201909152600b8082527f4d53473a3a41424f52543a000000000000000000000000000000000000000000602083015282518391116125305760005b8251811015612f0957828181518110612e8657612e86613e69565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916828281518110612ec557612ec5613e69565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612ef75750505050565b80612f0181613e7f565b915050612e6b565b508260405162461bcd60e51b81526004016106669190613c8c565b80356001600160a01b0381168114612f3b57600080fd5b919050565b600060208284031215612f5257600080fd5b610f5882612f24565b600060208284031215612f6d57600080fd5b5035919050565b60008083601f840112612f8657600080fd5b50813567ffffffffffffffff811115612f9e57600080fd5b6020830191508360208260051b8501011115612fb957600080fd5b9250929050565b60008060008060008060008060a0898b031215612fdc57600080fd5b612fe589612f24565b975060208901359650604089013567ffffffffffffffff8082111561300957600080fd5b6130158c838d01612f74565b909850965060608b013591508082111561302e57600080fd5b61303a8c838d01612f74565b909650945060808b013591508082111561305357600080fd5b506130608b828c01612f74565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561308c57600080fd5b61309586612f24565b94506130a360208701612f24565b93506130b160408701612f24565b92506130bf60608701612f24565b91506130cd60808701612f24565b90509295509295909350565b60008083601f8401126130eb57600080fd5b50813567ffffffffffffffff81111561310357600080fd5b602083019150836020828501011115612fb957600080fd5b6000806000806000806000806000898b036101a081121561313b57600080fd5b8a3567ffffffffffffffff8082111561315357600080fd5b61315f8e838f016130d9565b909c509a508a9150610120601f198401121561317a57600080fd5b60208d0199506101408d013592508083111561319557600080fd5b6131a18e848f01612f74565b90995097506101608d01359250889150808311156131be57600080fd5b6131ca8e848f01612f74565b90975095506101808d01359250869150808311156131e757600080fd5b50506131f58c828d01612f74565b915080935050809150509295985092959850929598565b60006080828403121561321e57600080fd5b50919050565b6000806040838503121561323757600080fd5b823567ffffffffffffffff8082111561324f57600080fd5b61325b8683870161320c565b9350602085013591508082111561327157600080fd5b5083016101a0818603121561328557600080fd5b809150509250929050565b60008060008060008060a087890312156132a957600080fd5b6132b287612f24565b9550602087013594506132c760408801612f24565b935060608701359250608087013567ffffffffffffffff8111156132ea57600080fd5b6132f689828a016130d9565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c03121561332757600080fd5b893567ffffffffffffffff8082111561333f57600080fd5b61334b8d838e016130d9565b909b5099508991506133608d60208e0161320c565b985060a08c013591508082111561337657600080fd5b6133828d838e01612f74565b909850965060c08c013591508082111561339b57600080fd5b6133a78d838e01612f74565b909650945060e08c01359150808211156133c057600080fd5b506131f58c828d01612f74565b600080602083850312156133e057600080fd5b823567ffffffffffffffff8111156133f757600080fd5b613403858286016130d9565b90969095509350505050565b60008060008060006060868803121561342757600080fd5b853567ffffffffffffffff8082111561343f57600080fd5b61344b89838a016130d9565b909750955060208801359450604088013591508082111561346b57600080fd5b50613478888289016130d9565b969995985093965092949392505050565b6000806000806060858703121561349f57600080fd5b6134a885612f24565b935060208501359250604085013567ffffffffffffffff8111156134cb57600080fd5b6134d7878288016130d9565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b60058110613509576135096134e3565b9052565b60208101610f5b82846134f9565b600080600080600080600080600060a08a8c03121561353957600080fd5b893567ffffffffffffffff8082111561355157600080fd5b61355d8d838e016130d9565b909b50995060208c013591508082111561357657600080fd5b6135828d838e0161320c565b985060408c013591508082111561359857600080fd5b6135a48d838e01612f74565b909850965060608c01359150808211156135bd57600080fd5b6135c98d838e01612f74565b909650945060808c01359150808211156133c057600080fd5b60005b838110156135fd5781810151838201526020016135e5565b50506000910152565b6000815180845261361e8160208601602086016135e2565b601f01601f19169290920160200192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b81835260006020808501808196508560051b810191508460005b878110156136e05782840389528135601e1988360301811261369657600080fd5b8701858101903567ffffffffffffffff8111156136b257600080fd5b8036038213156136c157600080fd5b6136cc868284613632565b9a87019a9550505090840190600101613675565b5091979650505050505050565b8183526000602080850194508260005b85811015613729576001600160a01b0361371683612f24565b16875295820195908201906001016136fd565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561376657600080fd5b8260051b80836020870137939093016020019392505050565b608081526000613792608083018a613606565b82810360208401526137a581898b61365b565b905082810360408401526137ba8187896136ed565b905082810360608401526137cf818587613734565b9a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f5b57610f5b6137dd565b8581528460208201528284604083013760409201918201526060019392505050565b60006020828403121561383a57600080fd5b813567ffffffffffffffff8116811461229f57600080fd5b60028110613509576135096134e3565b608081016138708287613852565b84602083015267ffffffffffffffff8416604083015282606083015295945050505050565b6000602082840312156138a757600080fd5b81356007811061229f57600080fd5b6000808335601e198436030181126138cd57600080fd5b83018035915067ffffffffffffffff8211156138e857600080fd5b602001915036819003821315612fb957600080fd5b6000808335601e1984360301811261391457600080fd5b83018035915067ffffffffffffffff82111561392f57600080fd5b6020019150600581901b3603821315612fb957600080fd5b60006001600160a01b03808a16835288602084015280881660408401525085606083015260c0608083015261398060c083018587613632565b90508260a083015298975050505050505050565b8082028115828204841417610f5b57610f5b6137dd565b80820180821115610f5b57610f5b6137dd565b6080815260006139d260808301888a613632565b86602084015282810360408401526139eb818688613632565b915050826060830152979650505050505050565b6001600160a01b0386168152846020820152608060408201526000613a28608083018587613632565b90508260608301529695505050505050565b600060208284031215613a4c57600080fd5b8151801515811461229f57600080fd5b60028110613a6c57613a6c6134e3565b60f81b9052565b613a7d8185613a5c565b60609290921b6001600160601b03191660018301526015820152603501919050565b60006001600160a01b03808a168352808916602084015287604084015267ffffffffffffffff8716606084015260c06080840152613ae160c084018688613632565b915080841660a08401525098975050505050505050565b60008251613b0a8184602087016135e2565b9190910192915050565b600060208284031215613b2657600080fd5b81516003811061229f57600080fd5b60a08101613b438288613852565b856020830152613b5660408301866134f9565b67ffffffffffffffff939093166060820152608001529392505050565b608081526000613b87608083018a8c613632565b8281036020840152613b9a81898b61365b565b90508281036040840152613baf8187896136ed565b90508281036060840152613bc4818587613734565b9b9a5050505050505050505050565b600060208284031215613be557600080fd5b5051919050565b8381526bffffffffffffffffffffffff198360601b16602082015260008251613c1c8160348501602087016135e2565b91909101603401949350505050565b60006001600160a01b03808816835286602084015260806040840152613c55608084018688613632565b91508084166060840152509695505050505050565b600082613c8757634e487b7160e01b600052601260045260246000fd5b500490565b602081526000610f586020830184613606565b613ca9818a613a5c565b60008851613cbe816001850160208d016135e2565b80830190506bffffffffffffffffffffffff198960601b1660018201526001600160c01b0319808960c01b16601583015287601d830152808760c01b16603d830152508385604583013760009301604501928352509098975050505050505050565b60006001600160a01b03808816835267ffffffffffffffff8716602084015260806040840152613c55608084018688613632565b608081526000613d676080830188613606565b67ffffffffffffffff871660208401528281036040840152613d8a818688613632565b9150506001600160a01b03831660608301529695505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215613dce57600080fd5b815167ffffffffffffffff80821115613de657600080fd5b818401915084601f830112613dfa57600080fd5b815181811115613e0c57613e0c613da6565b604051601f8201601f19908116603f01168101908382118183101715613e3457613e34613da6565b81604052828152876020848701011115613e4d57600080fd5b613e5e8360208301602088016135e2565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613e9157613e916137dd565b506001019056fe657865637574654d6573736167652862797465732c75696e7436342c62797465732c61646472657373294f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572657865637574654d65737361676528616464726573732c75696e7436342c62797465732c6164647265737329a264697066735822122059397ddb441e07a9d7962df6708b6dab520de9f19a5724dc4a1f0612110e771a64736f6c63430008110033