Source Code
Latest 25 from a total of 1,152 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer With Sw... | 10869707 | 1283 days ago | IN | 0.0001158 ETH | 0.001042357393 | ||||
| Transfer With Sw... | 10739893 | 1284 days ago | IN | 0.0000534 ETH | 0.000435808141 | ||||
| Transfer With Sw... | 10735294 | 1284 days ago | IN | 0.0000534 ETH | 0.000361319798 | ||||
| Transfer With Sw... | 10735151 | 1284 days ago | IN | 0.0001206 ETH | 0.000388463124 | ||||
| Transfer With Sw... | 10734755 | 1284 days ago | IN | 2.543278891599682 ETH | 0.00025328307 | ||||
| Transfer With Sw... | 10734010 | 1284 days ago | IN | 0.0500534 ETH | 0.000415492995 | ||||
| Transfer With Sw... | 10733944 | 1284 days ago | IN | 0.0000534 ETH | 0.000419756928 | ||||
| Transfer With Sw... | 10733938 | 1284 days ago | IN | 0.0001206 ETH | 0.000709374678 | ||||
| Transfer With Sw... | 10733798 | 1284 days ago | IN | 0.0001158 ETH | 0.000556308407 | ||||
| Transfer With Sw... | 10733741 | 1284 days ago | IN | 0.0001206 ETH | 0.000452649537 | ||||
| Transfer With Sw... | 10733114 | 1284 days ago | IN | 0.090615029073349 ETH | 0.000520200822 | ||||
| Transfer With Sw... | 10733017 | 1284 days ago | IN | 0.0500534 ETH | 0.000343521615 | ||||
| Transfer With Sw... | 10732346 | 1284 days ago | IN | 0.0500534 ETH | 0.000248182611 | ||||
| Transfer With Sw... | 10731849 | 1284 days ago | IN | 2.997906859288805 ETH | 0.000326197571 | ||||
| Transfer With Sw... | 10731591 | 1284 days ago | IN | 0.0500534 ETH | 0.000451197353 | ||||
| Transfer With Sw... | 10730729 | 1284 days ago | IN | 0.049442008955759 ETH | 0.000348160955 | ||||
| Transfer With Sw... | 10730396 | 1284 days ago | IN | 0.0001206 ETH | 0.000526561938 | ||||
| Transfer With Sw... | 10730274 | 1284 days ago | IN | 0.0000534 ETH | 0.00039082927 | ||||
| Transfer With Sw... | 10730166 | 1284 days ago | IN | 0.0001206 ETH | 0.000512286843 | ||||
| Transfer With Sw... | 10729937 | 1284 days ago | IN | 0.0000534 ETH | 0.000471175327 | ||||
| Transfer With Sw... | 10729765 | 1284 days ago | IN | 0.0601206 ETH | 0.000602829749 | ||||
| Transfer With Sw... | 10729346 | 1284 days ago | IN | 0.0000534 ETH | 0.000307108383 | ||||
| Transfer With Sw... | 10728953 | 1284 days ago | IN | 0.0112206 ETH | 0.000567547026 | ||||
| Transfer With Sw... | 10728788 | 1284 days ago | IN | 0.5751158 ETH | 0.000460352102 | ||||
| Transfer With Sw... | 10728773 | 1284 days ago | IN | 0.0001254 ETH | 0.000437148097 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 10869707 | 1283 days ago | 0.0001158 ETH | ||||
| 10739893 | 1284 days ago | 0.0000534 ETH | ||||
| 10735294 | 1284 days ago | 0.0000534 ETH | ||||
| 10735151 | 1284 days ago | 0.0001206 ETH | ||||
| 10734755 | 1284 days ago | 0.0000534 ETH | ||||
| 10734755 | 1284 days ago | 2.543225491599682 ETH | ||||
| 10734010 | 1284 days ago | 0.0000534 ETH | ||||
| 10734010 | 1284 days ago | 0.05 ETH | ||||
| 10733944 | 1284 days ago | 0.0000534 ETH | ||||
| 10733938 | 1284 days ago | 0.0001206 ETH | ||||
| 10733798 | 1284 days ago | 0.0001158 ETH | ||||
| 10733114 | 1284 days ago | 0.0001158 ETH | ||||
| 10733114 | 1284 days ago | 0.090499229073349 ETH | ||||
| 10733017 | 1284 days ago | 0.0000534 ETH | ||||
| 10733017 | 1284 days ago | 0.05 ETH | ||||
| 10732848 | 1284 days ago | 0.020226597818774 ETH | ||||
| 10732848 | 1284 days ago | 0.020226597818774 ETH | ||||
| 10732847 | 1284 days ago | 0.096739159866501 ETH | ||||
| 10732847 | 1284 days ago | 0.096739159866501 ETH | ||||
| 10732346 | 1284 days ago | 0.0000534 ETH | ||||
| 10732346 | 1284 days ago | 0.05 ETH | ||||
| 10731849 | 1284 days ago | 0.0000534 ETH | ||||
| 10731849 | 1284 days ago | 2.997853459288805 ETH | ||||
| 10731591 | 1284 days ago | 0.0000534 ETH | ||||
| 10731591 | 1284 days ago | 0.05 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
TransferSwapper
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./lib/MessageSenderLib.sol";
import "./lib/MessageReceiverApp.sol";
import "./lib/MsgDataTypes.sol";
import "./FeeOperator.sol";
import "./SigVerifier.sol";
import "./Swapper.sol";
import "./interfaces/ICodec.sol";
/**
* @author Chainhop Dex Team
* @author Padoriku
* @title An app that enables swapping on a chain, transferring to another chain and swapping
* another time on the destination chain before sending the result tokens to a user
*/
contract TransferSwapper is MessageReceiverApp, Swapper, SigVerifier, FeeOperator, ReentrancyGuard {
using SafeERC20 for IERC20;
using ECDSA for bytes32;
struct TransferDescription {
address receiver; // the receiving party (the user) of the final output token
uint64 dstChainId; // destination chain id
uint32 maxBridgeSlippage; // user defined maximum allowed slippage (pip) at bridge
MsgDataTypes.BridgeSendType bridgeType; // type of the bridge to use
uint64 nonce; // nonce is needed for de-dup tx at this contract and bridge
bool nativeIn; // whether to check msg.value and wrap token before swapping/sending
bool nativeOut; // whether to unwrap before sending the final token to user
uint256 fee; // this fee is only executor fee. it does not include msg bridge fee
uint256 feeDeadline; // the unix timestamp before which the fee is valid
// sig of sha3("executor fee", srcChainId, dstChainId, amountIn, tokenIn, feeDeadline, fee)
// see _verifyFee()
bytes feeSig;
// IMPORTANT: amountIn and tokenIn are completely ignored if src chain has a swap
// these two fields are only meant for the scenario where no swaps are needed on src chain
uint256 amountIn;
address tokenIn;
address dstTokenOut; // the final output token, emitted in event for display purpose only
// in case of multi route swaps, whether to allow the successful swaps to go through
// and sending the amountIn of the failed swaps back to user
bool allowPartialFill;
}
struct Request {
bytes32 id; // see _computeId()
ICodec.SwapDescription[] swaps; // the swaps need to happen on the destination chain
address receiver; // see TransferDescription.receiver
bool nativeOut; // see TransferDescription.nativeOut
uint256 fee; // see TransferDescription.fee
bool allowPartialFill; // see TransferDescription.allowPartialFill
}
/**
* @notice Denotes the status of a cross-chain transfer/swap request
* @dev Partially filled requests are considered 'Succeeded'. There is no 'Failed' state as
* it's only possible if everything reverts and there is no successful transaction
* @param Null An empty status that should never be reached
* @param Succeeded Transfer/swap has succeeded and funds are received by the receiver
* @param Fallback Swaps have failed on the dst chain, and bridge tokens are refunded to receiver
*/
enum RequestStatus {
Null,
Succeeded,
Fallback
}
event NativeWrapUpdated(address nativeWrap);
/**
* @notice Emitted when requested dstChainId == srcChainId, no bridging
* @param id see _computeId()
* @param amountIn the input amount approved by the sender
* @param tokenIn the input token approved by the sender
* @param amountOut the output amount gained after swapping using the input tokens
* @param tokenOut the output token gained after swapping using the input tokens
*/
event DirectSwap(bytes32 id, uint256 amountIn, address tokenIn, uint256 amountOut, address tokenOut);
/**
* @notice Emitted when operations on src chain is done, the transfer is sent through the bridge
* @param id see _computeId()
* @param transferId the src transfer id produced by MessageSenderLib.sendMessageWithTransfer()
* @param dstChainId destination chain id
* @param srcAmount input amount approved by the sender
* @param srcToken the input token approved by the sender
* @param dstToken the final output token (after bridging and swapping) desired by the sender
* @param bridgeOutReceiver the receiver (user or dst TransferSwapper) of the bridge token
*/
event RequestSent(
bytes32 id,
bytes32 transferId,
uint64 dstChainId,
uint256 srcAmount,
address srcToken,
address dstToken,
address bridgeOutReceiver
);
// emitted when operations on dst chain is done.
// dstAmount is denominated by dstToken, refundAmount is denominated by bridge out token.
// if refundAmount is a non-zero number, it means the "allow partial fill" option is turned on.
/**
* @notice Emitted when operations on dst chain is done.
* @param id see _computeId()
* @param dstAmount the final output token (after bridging and swapping) desired by the sender
* @param refundAmount the amount refunded to the receiver in bridge token
* @dev refundAmount may be fill by either a complete refund or when allowPartialFill is on and
* some swaps fails in the swap routes
* @param refundToken bridge out token
* @param feeCollected the fee chainhop deducts from bridge out token
* @param status see RequestStatus
*/
event RequestDone(
bytes32 id,
uint256 dstAmount,
uint256 refundAmount,
address refundToken,
uint256 feeCollected,
RequestStatus status
);
/// @notice erc20 wrap of the gas token of this chain, e.g. WETH
address public nativeWrap;
/// @dev saves the sender addresses of direct bridge transfers so that when refund happens, this contract
/// knows who to refund the tokens to
mapping(bytes32 => address) public directBridgeSenders;
constructor(
address _messageBus,
address _nativeWrap,
address _signer,
address _feeCollector,
string[] memory _funcSigs,
address[] memory _codecs,
address[] memory _supportedDexList,
string[] memory _supportedDexFuncs
)
Swapper(_funcSigs, _codecs, _supportedDexList, _supportedDexFuncs)
FeeOperator(_feeCollector)
SigVerifier(_signer)
{
messageBus = _messageBus;
nativeWrap = _nativeWrap;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Source chain functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @notice swaps if needed, then transfer the token to another chain along with an instruction on how to swap
* on that chain
* @param _dstTransferSwapper the address of the receiving party of the bridge token (TransferSwapper) on the destination chain
* @dev this field has no effect if the there is no dst swaps as the bridged tokens are sent directly to _desc.receiver
*/
function transferWithSwap(
address _dstTransferSwapper,
TransferDescription calldata _desc,
ICodec.SwapDescription[] calldata _srcSwaps,
ICodec.SwapDescription[] calldata _dstSwaps
) external payable nonReentrant {
// a request needs to incur a swap, a transfer, or both. otherwise it's a nop and we revert early to save gas
require(_srcSwaps.length != 0 || _desc.dstChainId != uint64(block.chainid), "nop");
require(_srcSwaps.length != 0 || (_desc.amountIn != 0 && _desc.tokenIn != address(0)), "nop");
uint256 amountIn = _desc.amountIn;
address tokenIn = _desc.tokenIn;
address tokenOut = _desc.tokenIn;
ICodec[] memory codecs;
if (_srcSwaps.length != 0) {
(amountIn, tokenIn, tokenOut, codecs) = sanitizeSwaps(_srcSwaps);
require(tokenIn == _desc.tokenIn, "tkin mm");
}
if (_desc.nativeIn) {
require(tokenIn == nativeWrap, "tkin no nativeWrap");
require(msg.value >= amountIn, "insfcnt amt"); // insufficient amount
IWETH(nativeWrap).deposit{value: amountIn}();
} else {
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
}
_swapAndSend(_dstTransferSwapper, amountIn, tokenIn, tokenOut, _srcSwaps, _dstSwaps, _desc, codecs);
}
function _swapAndSend(
address _dstTransferSwapper,
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
ICodec.SwapDescription[] memory _srcSwaps,
ICodec.SwapDescription[] memory _dstSwaps,
TransferDescription memory _desc,
ICodec[] memory _codecs
) private {
// swap if needed
uint256 amountOut = _amountIn;
if (_srcSwaps.length != 0) {
bool ok;
(ok, amountOut) = executeSwaps(_srcSwaps, _codecs);
require(ok, "swap fail");
}
bytes32 id = _computeId(_desc.receiver, _desc.nonce);
// direct send if needed
if (_desc.dstChainId == uint64(block.chainid)) {
emit DirectSwap(id, _amountIn, _tokenIn, amountOut, _tokenOut);
_sendToken(_tokenOut, amountOut, _desc.receiver, _desc.nativeOut);
return;
}
_verifyFee(_desc, _amountIn, _tokenIn);
uint256 msgFee = msg.value;
if (_desc.nativeIn) {
msgFee = msg.value - _amountIn;
}
// transfer through bridge
address bridgeOutReceiver = _dstSwaps.length > 0 ? _dstTransferSwapper : _desc.receiver;
bytes32 transferId = _transfer(id, bridgeOutReceiver, _desc, _dstSwaps, amountOut, _tokenOut, msgFee);
emit RequestSent(id, transferId, _desc.dstChainId, _amountIn, _tokenIn, _desc.dstTokenOut, bridgeOutReceiver);
}
function _transfer(
bytes32 _id,
address _bridgeOutReceiver,
TransferDescription memory _desc,
ICodec.SwapDescription[] memory _dstSwaps,
uint256 _amount,
address _token,
uint256 _msgFee
) private returns (bytes32 transferId) {
bytes memory requestMessage = _encodeRequestMessage(_id, _desc, _dstSwaps);
transferId = MessageSenderLib.sendMessageWithTransfer(
_bridgeOutReceiver,
_token,
_amount,
_desc.dstChainId,
_desc.nonce,
_desc.maxBridgeSlippage,
requestMessage,
_desc.bridgeType,
messageBus,
_msgFee
);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Destination chain functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @notice Executes a swap if needed, then sends the output token to the receiver
* @dev If allowPartialFill is off, this function reverts as soon as one swap in swap routes fails
* @dev This function is called and is only callable by MessageBus. The transaction of such call is triggered by executor.
* @param _token the token received by this contract
* @param _amount the amount of token received by this contract
* @return ok whether the processing is successful
*/
function executeMessageWithTransfer(
address, // _sender
address _token,
uint256 _amount,
uint64, // _srcChainId
bytes memory _message,
address // _executor
) external payable override onlyMessageBus nonReentrant returns (ExecutionStatus) {
Request memory m = abi.decode((_message), (Request));
// handle the case where amount received is not enough to pay fee
if (_amount < m.fee) {
m.fee = _amount;
emit RequestDone(m.id, 0, 0, _token, m.fee, RequestStatus.Succeeded);
return ExecutionStatus.Success;
} else {
_amount = _amount - m.fee;
}
address tokenOut = _token;
bool nativeOut = m.nativeOut;
uint256 sumAmtOut = _amount;
uint256 sumAmtFailed;
if (m.swaps.length != 0) {
ICodec[] memory codecs;
address tokenIn;
// swap first before sending the token out to user
(, tokenIn, tokenOut, codecs) = sanitizeSwaps(m.swaps);
require(tokenIn == _token, "tkin mm"); // tokenIn mismatch
(sumAmtOut, sumAmtFailed) = executeSwapsWithOverride(m.swaps, codecs, _amount, m.allowPartialFill);
// if at this stage the tx is not reverted, it means at least 1 swap in routes succeeded
}
if (sumAmtFailed > 0) {
_sendToken(_token, sumAmtFailed, m.receiver, false);
}
_sendToken(tokenOut, sumAmtOut, m.receiver, nativeOut);
// status is always success as long as this function call doesn't revert. partial fill is also considered success
emit RequestDone(m.id, sumAmtOut, sumAmtFailed, _token, m.fee, RequestStatus.Succeeded);
return ExecutionStatus.Success;
}
/**
* @notice Sends the received token to the receiver
* @dev Only called if executeMessageWithTransfer reverts
* @param _token the token received by this contract
* @param _amount the amount of token received by this contract
* @return ok whether the processing is successful
*/
function executeMessageWithTransferFallback(
address, // _sender
address _token,
uint256 _amount,
uint64, // _srcChainId
bytes memory _message,
address // _executor
) external payable override onlyMessageBus nonReentrant returns (ExecutionStatus) {
Request memory m = abi.decode((_message), (Request));
uint256 refundAmount = _amount - m.fee; // no need to check amount >= fee as it's already checked before
_sendToken(_token, refundAmount, m.receiver, false);
emit RequestDone(m.id, 0, refundAmount, _token, m.fee, RequestStatus.Fallback);
return ExecutionStatus.Success;
}
/**
* @notice Used to trigger refund when bridging fails due to large slippage
* @dev only MessageBus can call this function, this requires the user to get sigs of the message from SGN
* @param _token the token received by this contract
* @param _amount the amount of token received by this contract
* @return ok whether the processing is successful
*/
function executeMessageWithTransferRefund(
address _token,
uint256 _amount,
bytes calldata _message,
address // _executor
) external payable override onlyMessageBus nonReentrant returns (ExecutionStatus) {
Request memory m = abi.decode((_message), (Request));
_sendToken(_token, _amount, m.receiver, false);
emit RequestDone(m.id, 0, _amount, _token, m.fee, RequestStatus.Fallback);
return ExecutionStatus.Success;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Misc
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function _computeId(address _receiver, uint64 _nonce) private view returns (bytes32) {
return keccak256(abi.encodePacked(msg.sender, _receiver, uint64(block.chainid), _nonce));
}
function _sendToken(
address _token,
uint256 _amount,
address _receiver,
bool _nativeOut
) private {
if (_nativeOut) {
require(_token == nativeWrap, "tk no native");
IWETH(nativeWrap).withdraw(_amount);
(bool sent, ) = _receiver.call{value: _amount, gas: 50000}("");
require(sent, "send fail");
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
function _encodeRequestMessage(
bytes32 _id,
TransferDescription memory _desc,
ICodec.SwapDescription[] memory _swaps
) private pure returns (bytes memory message) {
message = abi.encode(
Request({
id: _id,
swaps: _swaps,
receiver: _desc.receiver,
nativeOut: _desc.nativeOut,
fee: _desc.fee,
allowPartialFill: _desc.allowPartialFill
})
);
}
function _verifyFee(
TransferDescription memory _desc,
uint256 _amountIn,
address _tokenIn
) private view {
bytes32 hash = keccak256(
abi.encodePacked(
"executor fee",
uint64(block.chainid),
_desc.dstChainId,
_amountIn,
_tokenIn,
_desc.feeDeadline,
_desc.fee
)
);
bytes32 signHash = hash.toEthSignedMessageHash();
verifySig(signHash, _desc.feeSig);
require(_desc.feeDeadline > block.timestamp, "deadline exceeded");
}
function setNativeWrap(address _nativeWrap) external onlyOwner {
nativeWrap = _nativeWrap;
emit NativeWrapUpdated(_nativeWrap);
}
// This is needed to receive ETH when calling `IWETH.withdraw`
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IBridge.sol";
import "../interfaces/IOriginalTokenVault.sol";
import "../interfaces/IOriginalTokenVaultV2.sol";
import "../interfaces/IPeggedTokenBridge.sol";
import "../interfaces/IPeggedTokenBridgeV2.sol";
import "../interfaces/IMessageBus.sol";
import "./MsgDataTypes.sol";
library MessageSenderLib {
using SafeERC20 for IERC20;
// ============== Internal library functions called by apps ==============
/**
* @notice Sends a message to an app on another chain via MessageBus without an associated transfer.
* @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.
* @param _messageBus The address of the MessageBus on this chain.
* @param _fee The fee amount to pay to MessageBus.
*/
function sendMessage(
address _receiver,
uint64 _dstChainId,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal {
IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message);
}
/**
* @notice Sends a message to an app on another chain via MessageBus with an associated transfer.
* @param _receiver The address of the destination app contract.
* @param _token The address of the token to be sent.
* @param _amount The amount of tokens to be sent.
* @param _dstChainId The destination chain ID.
* @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice.
* @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
* Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
* transfer can be refunded. Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}.
* @param _message Arbitrary message bytes to be decoded by the destination app contract.
* @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum.
* @param _messageBus The address of the MessageBus on this chain.
* @param _fee The fee amount to pay to MessageBus.
* @return The transfer ID.
*/
function sendMessageWithTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
bytes memory _message,
MsgDataTypes.BridgeSendType _bridgeSendType,
address _messageBus,
uint256 _fee
) internal returns (bytes32) {
(bytes32 transferId, address bridge) = sendTokenTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
_bridgeSendType,
_messageBus
);
if (_message.length > 0) {
IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
_receiver,
_dstChainId,
bridge,
transferId,
_message
);
}
return transferId;
}
/**
* @notice Sends a token transfer via a bridge.
* @param _receiver The address of the destination app contract.
* @param _token The address of the token to be sent.
* @param _amount The amount of tokens to be sent.
* @param _dstChainId The destination chain ID.
* @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice.
* @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
* Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
* transfer can be refunded.
* @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum.
*/
function sendTokenTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
MsgDataTypes.BridgeSendType _bridgeSendType,
address _messageBus
) internal returns (bytes32 transferId, address bridge) {
if (_bridgeSendType == MsgDataTypes.BridgeSendType.Liquidity) {
bridge = IMessageBus(_messageBus).liquidityBridge();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IBridge(bridge).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
transferId = computeLiqBridgeTransferId(_receiver, _token, _amount, _dstChainId, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) {
bridge = IMessageBus(_messageBus).pegVault();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IOriginalTokenVault(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
transferId = computePegV1DepositId(_receiver, _token, _amount, _dstChainId, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) {
bridge = IMessageBus(_messageBus).pegBridge();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IPeggedTokenBridge(bridge).burn(_token, _amount, _receiver, _nonce);
// handle cases where certain tokens do not spend allowance for role-based burn
IERC20(_token).safeApprove(bridge, 0);
transferId = computePegV1BurnId(_receiver, _token, _amount, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Deposit) {
bridge = IMessageBus(_messageBus).pegVaultV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IOriginalTokenVaultV2(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn) {
bridge = IMessageBus(_messageBus).pegBridgeV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IPeggedTokenBridgeV2(bridge).burn(_token, _amount, _dstChainId, _receiver, _nonce);
// handle cases where certain tokens do not spend allowance for role-based burn
IERC20(_token).safeApprove(bridge, 0);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2BurnFrom) {
bridge = IMessageBus(_messageBus).pegBridgeV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IPeggedTokenBridgeV2(bridge).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce);
// handle cases where certain tokens do not spend allowance for role-based burn
IERC20(_token).safeApprove(bridge, 0);
} else {
revert("bridge type not supported");
}
}
function computeLiqBridgeTransferId(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce
) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid))
);
}
function computePegV1DepositId(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce
) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid))
);
}
function computePegV1BurnId(
address _receiver,
address _token,
uint256 _amount,
uint64 _nonce
) internal view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid)));
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.12;
import "../interfaces/IMessageReceiverApp.sol";
import "./MessageBusAddress.sol";
abstract contract MessageReceiverApp is IMessageReceiverApp, MessageBusAddress {
modifier onlyMessageBus() {
require(msg.sender == messageBus, "caller is not message bus");
_;
}
/**
* @notice Called by MessageBus (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s
* sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address.
* @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.
* the contract that implements this contract can safely assume that the tokens will arrive before this
* function is called.
* @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 virtual override onlyMessageBus returns (ExecutionStatus) {}
/**
* @notice Only called by MessageBus (MessageBusReceiver) if
* 1. executeMessageWithTransfer reverts, or
* 2. executeMessageWithTransfer returns ExecutionStatus.Fail
* @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.
* the contract that implements this contract can safely assume that the tokens will arrive before this
* function is called.
* @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 virtual override onlyMessageBus returns (ExecutionStatus) {}
/**
* @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract
* @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 virtual override onlyMessageBus returns (ExecutionStatus) {}
/**
* @notice Called by MessageBus (MessageBusReceiver)
* @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 virtual override onlyMessageBus returns (ExecutionStatus) {}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.12;
library MsgDataTypes {
// 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
}
struct MsgWithTransferExecutionParams {
bytes message;
TransferInfo transfer;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
struct BridgeTransferParams {
bytes request;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Allows the owner to set fee collector and allows fee collectors to collect fees
* @author Padoriku
*/
abstract contract FeeOperator is Ownable {
using SafeERC20 for IERC20;
address public feeCollector;
event FeeCollectorUpdated(address from, address to);
modifier onlyFeeCollector() {
require(msg.sender == feeCollector, "not fee collector");
_;
}
constructor(address _feeCollector) {
feeCollector = _feeCollector;
}
function collectFee(address[] calldata _tokens, address _to) external onlyFeeCollector {
for (uint256 i = 0; i < _tokens.length; i++) {
uint256 balance = IERC20(_tokens[i]).balanceOf(address(this));
IERC20(_tokens[i]).safeTransfer(_to, balance);
}
}
function setFeeCollector(address _feeCollector) external onlyOwner {
address oldFeeCollector = feeCollector;
feeCollector = _feeCollector;
emit FeeCollectorUpdated(oldFeeCollector, _feeCollector);
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Allows owner to set signer, and verifies signatures
* @author Padoriku
*/
contract SigVerifier is Ownable {
using ECDSA for bytes32;
address public signer;
event SignerUpdated(address from, address to);
constructor(address _signer) {
signer = _signer;
}
function setSigner(address _signer) public onlyOwner {
address oldSigner = signer;
signer = _signer;
emit SignerUpdated(oldSigner, _signer);
}
function verifySig(bytes32 _hash, bytes memory _feeSig) internal view {
address _signer = _hash.recover(_feeSig);
require(_signer == signer, "invalid signer");
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./CodecRegistry.sol";
import "./interfaces/ICodec.sol";
import "./interfaces/IWETH.sol";
import "./DexRegistry.sol";
/**
* @title Loads codecs for the swaps and performs swap actions
* @author Padoriku
*/
contract Swapper is CodecRegistry, DexRegistry {
using SafeERC20 for IERC20;
constructor(
string[] memory _funcSigs,
address[] memory _codecs,
address[] memory _supportedDexList,
string[] memory _supportedDexFuncs
) DexRegistry(_supportedDexList, _supportedDexFuncs) CodecRegistry(_funcSigs, _codecs) {}
/**
* @dev Checks the input swaps for that tokenIn and tokenOut for every swap should be the same
* @param _swaps the swaps the check
* @return sumAmtIn the sum of all amountIns in the swaps
* @return tokenIn the input token of the swaps
* @return tokenOut the desired output token of the swaps
* @return codecs a list of codecs which each of them corresponds to a swap
*/
function sanitizeSwaps(ICodec.SwapDescription[] memory _swaps)
internal
view
returns (
uint256 sumAmtIn,
address tokenIn,
address tokenOut,
ICodec[] memory codecs // _codecs[i] is for _swaps[i]
)
{
address prevTokenIn;
address prevTokenOut;
codecs = loadCodecs(_swaps);
for (uint256 i = 0; i < _swaps.length; i++) {
require(dexRegistry[_swaps[i].dex][bytes4(_swaps[i].data)], "unsupported dex");
(uint256 _amountIn, address _tokenIn, address _tokenOut) = codecs[i].decodeCalldata(_swaps[i]);
require(prevTokenIn == address(0) || prevTokenIn == _tokenIn, "tkin mismatch");
prevTokenIn = _tokenIn;
require(prevTokenOut == address(0) || prevTokenOut == _tokenOut, "tko mismatch");
prevTokenOut = _tokenOut;
sumAmtIn += _amountIn;
tokenIn = _tokenIn;
tokenOut = _tokenOut;
}
}
/**
* @notice Executes the swaps, decode their return values and sums the returned amount
* @dev This function is intended to be used on src chain only
* @dev This function immediately fails (return false) if any swaps fail. There is no "partial fill" on src chain
* @param _swaps swaps. this function assumes that the swaps are already sanitized
* @param _codecs the codecs for each swap
* @return ok whether the operation is successful
* @return sumAmtOut the sum of all amounts gained from swapping
*/
function executeSwaps(
ICodec.SwapDescription[] memory _swaps,
ICodec[] memory _codecs // _codecs[i] is for _swaps[i]
) internal returns (bool ok, uint256 sumAmtOut) {
for (uint256 i = 0; i < _swaps.length; i++) {
(uint256 amountIn, address tokenIn, address tokenOut) = _codecs[i].decodeCalldata(_swaps[i]);
bytes memory data = _codecs[i].encodeCalldataWithOverride(_swaps[i].data, amountIn, address(this));
IERC20(tokenIn).safeIncreaseAllowance(_swaps[i].dex, amountIn);
uint256 balBefore = IERC20(tokenOut).balanceOf(address(this));
(ok, ) = _swaps[i].dex.call(data);
if (!ok) {
return (false, 0);
}
uint256 balAfter = IERC20(tokenOut).balanceOf(address(this));
sumAmtOut += balAfter - balBefore;
}
}
/**
* @notice Executes the swaps with override, redistributes amountIns for each swap route,
* decode their return values and sums the returned amount
* @dev This function is intended to be used on dst chain only
* @param _swaps swaps to execute. this function assumes that the swaps are already sanitized
* @param _codecs the codecs for each swap
* @param _amountInOverride the amountIn to substitute the amountIns in swaps for
* @dev _amountInOverride serves the purpose of correcting the estimated amountIns to actual bridge outs
* @dev _amountInOverride is also distributed according to the weight of each original amountIn
* @return sumAmtOut the sum of all amounts gained from swapping
* @return sumAmtFailed the sum of all amounts that fails to swap
*/
function executeSwapsWithOverride(
ICodec.SwapDescription[] memory _swaps,
ICodec[] memory _codecs, // _codecs[i] is for _swaps[i]
uint256 _amountInOverride,
bool _allowPartialFill
) internal returns (uint256 sumAmtOut, uint256 sumAmtFailed) {
(uint256[] memory amountIns, address tokenIn, address tokenOut) = _redistributeAmountIn(
_swaps,
_amountInOverride,
_codecs
);
uint256 balBefore = IERC20(tokenOut).balanceOf(address(this));
// execute the swaps with adjusted amountIns
for (uint256 i = 0; i < _swaps.length; i++) {
bytes memory swapCalldata = _codecs[i].encodeCalldataWithOverride(
_swaps[i].data,
amountIns[i],
address(this)
);
IERC20(tokenIn).safeIncreaseAllowance(_swaps[i].dex, amountIns[i]);
(bool ok, ) = _swaps[i].dex.call(swapCalldata);
require(ok || _allowPartialFill, "swap failed");
if (!ok) {
sumAmtFailed += amountIns[i];
}
}
uint256 balAfter = IERC20(tokenOut).balanceOf(address(this));
sumAmtOut = balAfter - balBefore;
require(sumAmtOut > 0, "all swaps failed");
}
/// @notice distributes the _amountInOverride to the swaps base on how much each original amountIns weight
function _redistributeAmountIn(
ICodec.SwapDescription[] memory _swaps,
uint256 _amountInOverride,
ICodec[] memory _codecs
)
private
view
returns (
uint256[] memory amountIns,
address tokenIn,
address tokenOut
)
{
uint256 sumAmtIn;
amountIns = new uint256[](_swaps.length);
// compute sumAmtIn and collect amountIns
for (uint256 i = 0; i < _swaps.length; i++) {
uint256 amountIn;
(amountIn, tokenIn, tokenOut) = _codecs[i].decodeCalldata(_swaps[i]);
sumAmtIn += amountIn;
amountIns[i] = amountIn;
}
// compute adjusted amountIns with regard to the weight of each amountIns in total amountIn
for (uint256 i = 0; i < amountIns.length; i++) {
amountIns[i] = (_amountInOverride * amountIns[i]) / sumAmtIn;
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;
interface ICodec {
struct SwapDescription {
address dex; // the DEX to use for the swap, zero address implies no swap needed
bytes data; // the data to call the dex with
}
function decodeCalldata(SwapDescription calldata swap)
external
view
returns (
uint256 amountIn,
address tokenIn,
address tokenOut
);
function encodeCalldataWithOverride(
bytes calldata data,
uint256 amountInOverride,
address receiverOverride
) external pure returns (bytes memory swapCalldata);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// 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 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;
}// 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;
function records(bytes32 recordId) external view returns (bool);
}// 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);
function records(bytes32 recordId) external view returns (bool);
}// 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;
function records(bytes32 recordId) external view returns (bool);
}// 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);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;
import "../lib/MsgDataTypes.sol";
interface IMessageBus {
function liquidityBridge() external view returns (address);
function pegBridge() external view returns (address);
function pegBridgeV2() external view returns (address);
function pegVault() external view returns (address);
function pegVaultV2() external view returns (address);
/**
* @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) external view returns (uint256);
/**
* @notice Sends a message to an app on another chain via MessageBus without an associated transfer.
* 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;
/**
* @notice Sends a message associated with a transfer to an app on another chain via MessageBus without an associated transfer.
* 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;
/**
* @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;
/**
* @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
) external payable;
/**
* @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
) external payable;
/**
* @notice Execute a message not associated with a transfer.
* @param _message Arbitrary message bytes originated from and encoded by the source app contract
* @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;
}// 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 (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s
* sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address.
* @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.
* the contract that implements this contract can safely assume that the tokens will arrive before this
* function is called.
* @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 (MessageBusReceiver) if
* 1. executeMessageWithTransfer reverts, or
* 2. executeMessageWithTransfer returns ExecutionStatus.Fail
* @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.
* the contract that implements this contract can safely assume that the tokens will arrive before this
* function is called.
* @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 (MessageBusReceiver) to process refund of the original transfer from this contract
* @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);
/**
* @notice Called by MessageBus (MessageBusReceiver)
* @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);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.12;
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract MessageBusAddress is Ownable {
event MessageBusUpdated(address messageBus);
address public messageBus;
function setMessageBus(address _messageBus) public onlyOwner {
messageBus = _messageBus;
emit MessageBusUpdated(messageBus);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @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.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/ICodec.sol";
/**
* @title A codec registry that maps swap function selectors to corresponding codec addresses
* @author Padoriku
*/
abstract contract CodecRegistry is Ownable {
// Initially supported swap functions
// 0x3df02124 exchange(int128,int128,uint256,uint256)
// 0xa6417ed6 exchange_underlying(int128,int128,uint256,uint256)
// 0x44ee1986 exchange_underlying(int128,int128,uint256,uint256,address)
// 0x38ed1739 swapExactTokensForTokens(uint256,uint256,address[],address,uint256)
// 0xc04b8d59 exactInput((bytes,address,uint256,uint256,uint256))
mapping(bytes4 => ICodec) public selector2codec;
// not used programmatically, but added for contract transparency
address[] public codecs;
event CodecUpdated(bytes4 selector, address codec);
constructor(string[] memory _funcSigs, address[] memory _codecs) {
require(_funcSigs.length == _codecs.length, "len mm");
for (uint256 i = 0; i < _funcSigs.length; i++) {
bytes4 selector = bytes4(keccak256(bytes(_funcSigs[i])));
_setCodec(selector, _codecs[i]);
}
}
function setCodec(string calldata _funcSig, address _codec) public onlyOwner {
bytes4 selector = bytes4(keccak256(bytes(_funcSig)));
_setCodec(selector, _codec);
emit CodecUpdated(selector, _codec);
}
function _setCodec(bytes4 _selector, address _codec) private {
selector2codec[_selector] = ICodec(_codec);
codecs.push(_codec);
}
function loadCodecs(ICodec.SwapDescription[] memory _swaps) internal view returns (ICodec[] memory) {
ICodec[] memory _codecs = new ICodec[](_swaps.length);
for (uint256 i = 0; i < _swaps.length; i++) {
bytes4 selector = bytes4(_swaps[i].data);
_codecs[i] = selector2codec[selector];
require(address(_codecs[i]) != address(0), "cdc no found");
}
return (_codecs);
}
function getCodec(
bytes4[] memory _selectors,
ICodec[] memory _codecs,
bytes4 _selector
) internal pure returns (ICodec) {
for (uint256 i = 0; i < _codecs.length; i++) {
if (_selector == _selectors[i]) {
return _codecs[i];
}
}
revert("cdc no found");
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.12;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Manages a list supported dex
* @author Padoriku
*/
abstract contract DexRegistry is Ownable {
event SupportedDexUpdated(address dex, bytes4 selector, bool enabled);
mapping(address => mapping(bytes4 => bool)) public dexRegistry;
constructor(address[] memory _supportedDexList, string[] memory _supportedFuncs) {
for (uint256 i = 0; i < _supportedDexList.length; i++) {
bytes4 selector = bytes4(keccak256(bytes(_supportedFuncs[i])));
_setSupportedDex(_supportedDexList[i], selector, true);
}
}
function setSupportedDex(
address _dex,
bytes4 _selector,
bool _enabled
) external onlyOwner {
_setSupportedDex(_dex, _selector, _enabled);
emit SupportedDexUpdated(_dex, _selector, _enabled);
}
function _setSupportedDex(
address _dex,
bytes4 _selector,
bool _enabled
) private {
bool enabled = dexRegistry[_dex][_selector];
require(enabled != _enabled, "nop");
dexRegistry[_dex][_selector] = _enabled;
}
}{
"optimizer": {
"enabled": true,
"runs": 800,
"details": {
"yul": false
}
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_messageBus","type":"address"},{"internalType":"address","name":"_nativeWrap","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"string[]","name":"_funcSigs","type":"string[]"},{"internalType":"address[]","name":"_codecs","type":"address[]"},{"internalType":"address[]","name":"_supportedDexList","type":"address[]"},{"internalType":"string[]","name":"_supportedDexFuncs","type":"string[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"address","name":"codec","type":"address"}],"name":"CodecUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"}],"name":"DirectSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FeeCollectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"messageBus","type":"address"}],"name":"MessageBusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nativeWrap","type":"address"}],"name":"NativeWrapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"dstAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeCollected","type":"uint256"},{"indexed":false,"internalType":"enum TransferSwapper.RequestStatus","name":"status","type":"uint8"}],"name":"RequestDone","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"dstChainId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"srcAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"srcToken","type":"address"},{"indexed":false,"internalType":"address","name":"dstToken","type":"address"},{"indexed":false,"internalType":"address","name":"bridgeOutReceiver","type":"address"}],"name":"RequestSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"dex","type":"address"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SupportedDexUpdated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"codecs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"address","name":"_to","type":"address"}],"name":"collectFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"dexRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"directBridgeSenders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessageWithTransfer","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessageWithTransferFallback","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessageWithTransferRefund","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageBus","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeWrap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"selector2codec","outputs":[{"internalType":"contract ICodec","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_funcSig","type":"string"},{"internalType":"address","name":"_codec","type":"address"}],"name":"setCodec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_messageBus","type":"address"}],"name":"setMessageBus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nativeWrap","type":"address"}],"name":"setNativeWrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dex","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"},{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setSupportedDex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dstTransferSwapper","type":"address"},{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"internalType":"uint32","name":"maxBridgeSlippage","type":"uint32"},{"internalType":"enum MsgDataTypes.BridgeSendType","name":"bridgeType","type":"uint8"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"nativeIn","type":"bool"},{"internalType":"bool","name":"nativeOut","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"feeDeadline","type":"uint256"},{"internalType":"bytes","name":"feeSig","type":"bytes"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"dstTokenOut","type":"address"},{"internalType":"bool","name":"allowPartialFill","type":"bool"}],"internalType":"struct TransferSwapper.TransferDescription","name":"_desc","type":"tuple"},{"components":[{"internalType":"address","name":"dex","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ICodec.SwapDescription[]","name":"_srcSwaps","type":"tuple[]"},{"components":[{"internalType":"address","name":"dex","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ICodec.SwapDescription[]","name":"_dstSwaps","type":"tuple[]"}],"name":"transferWithSwap","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b50604051620056f5380380620056f58339810160408190526200003491620005fa565b848685858585818185856200004933620001d5565b8051825114620000765760405162461bcd60e51b81526004016200006d906200074f565b60405180910390fd5b60005b8251811015620000ef5760008382815181106200009a576200009a62000761565b6020026020010151805190602001209050620000d981848481518110620000c557620000c562000761565b60200260200101516200022560201b60201c565b5080620000e6816200078d565b91505062000079565b50505060005b82518110156200016d57600082828151811062000116576200011662000761565b60200260200101518051906020012090506200015784838151811062000140576200014062000761565b60200260200101518260016200029760201b60201c565b508062000164816200078d565b915050620000f5565b5050600580546001600160a01b03199081166001600160a01b039889161790915560068054821698881698909817909755505060016007819055805486169d85169d909d17909c5550506008805490921698169790971790965550620007d895505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff168015158215151415620002ef5760405162461bcd60e51b81526004016200006d90620007c6565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b60006001600160a01b0382165b92915050565b6200034f8162000331565b81146200035b57600080fd5b50565b80516200033e8162000344565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715620003a957620003a96200036b565b6040525050565b6000620003bc60405190565b9050620003ca828262000381565b919050565b60006001600160401b03821115620003eb57620003eb6200036b565b5060209081020190565b60006001600160401b038211156200041157620004116200036b565b601f19601f83011660200192915050565b60005b838110156200043f57818101518382015260200162000425565b838111156200044f576000848401525b50505050565b60006200046c6200046684620003f5565b620003b0565b905082815260208101848484011115620004895762000489600080fd5b6200049684828562000422565b509392505050565b600082601f830112620004b457620004b4600080fd5b8151620004c684826020860162000455565b949350505050565b6000620004df6200046684620003cf565b83815290506020808201908402830185811115620005005762000500600080fd5b835b81811015620005465780516001600160401b03811115620005265762000526600080fd5b8086016200053589826200049e565b855250506020928301920162000502565b5050509392505050565b600082601f830112620005665762000566600080fd5b8151620004c6848260208601620004ce565b6000620005896200046684620003cf565b83815290506020808201908402830185811115620005aa57620005aa600080fd5b835b81811015620005465780620005c288826200035e565b84525060209283019201620005ac565b600082601f830112620005e857620005e8600080fd5b8151620004c684826020860162000578565b600080600080600080600080610100898b0312156200061c576200061c600080fd5b60006200062a8b8b6200035e565b98505060206200063d8b828c016200035e565b9750506040620006508b828c016200035e565b9650506060620006638b828c016200035e565b95505060808901516001600160401b03811115620006845762000684600080fd5b620006928b828c0162000550565b94505060a08901516001600160401b03811115620006b357620006b3600080fd5b620006c18b828c01620005d2565b93505060c08901516001600160401b03811115620006e257620006e2600080fd5b620006f08b828c01620005d2565b92505060e08901516001600160401b03811115620007115762000711600080fd5b6200071f8b828c0162000550565b9150509295985092959890939650565b60068152600060208201656c656e206d6d60d01b815291505b5060200190565b602080825281016200033e816200072f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620007a457620007a462000777565b5060010190565b600381526000602082016206e6f760ec1b8152915062000748565b602080825281016200033e81620007ab565b614f0d80620007e86000396000f3fe6080604052600436106101845760003560e01c80638da5cb5b116100d6578063c415b95c1161007f578063efcfd8f511610059578063efcfd8f514610425578063f2fde38b14610445578063fbf5d7631461046557600080fd5b8063c415b95c146103d2578063c5bccca3146103f2578063d8318ae51461041257600080fd5b8063a1a227fa116100b0578063a1a227fa1461035c578063a1c9d41e1461037c578063a42dce80146103b257600080fd5b80638da5cb5b146102e357806391ec04b5146103015780639c649fdf1461034957600080fd5b80635b5a66a711610138578063715018a611610112578063715018a61461029b5780637cd2bffc146102b057806382665a8f146102c357600080fd5b80635b5a66a71461023b578063675df7591461025b5780636c19e7831461027b57600080fd5b8063457bfa2f11610169578063457bfa2f146101e6578063547cad12146102065780635ab7afc61461022857600080fd5b80630bcb498214610190578063238ac933146101b957600080fd5b3661018b57005b600080fd5b6101a361019e366004612fc2565b6104a8565b6040516101b09190613095565b60405180910390f35b3480156101c557600080fd5b506005546101d9906001600160a01b031681565b6040516101b091906130ac565b3480156101f257600080fd5b506008546101d9906001600160a01b031681565b34801561021257600080fd5b506102266102213660046130ba565b610585565b005b6101a36102363660046131e4565b610606565b34801561024757600080fd5b506102266102563660046130ba565b6106fb565b34801561026757600080fd5b506102266102763660046132b7565b610770565b34801561028757600080fd5b506102266102963660046130ba565b6107e5565b3480156102a757600080fd5b5061022661086e565b6101a36102be3660046131e4565b6108a4565b3480156102cf57600080fd5b506101d96102de366004613307565b610a86565b3480156102ef57600080fd5b506000546001600160a01b03166101d9565b34801561030d57600080fd5b5061033c61031c366004613328565b600460209081526000928352604080842090915290825290205460ff1681565b6040516101b0919061336d565b6101a361035736600461337b565b610ab0565b34801561036857600080fd5b506001546101d9906001600160a01b031681565b34801561038857600080fd5b506101d9610397366004613307565b6009602052600090815260409020546001600160a01b031681565b3480156103be57600080fd5b506102266103cd3660046130ba565b610ae6565b3480156103de57600080fd5b506006546101d9906001600160a01b031681565b3480156103fe57600080fd5b5061022661040d3660046133b3565b610b63565b61022661042036600461346b565b610c5f565b34801561043157600080fd5b50610226610440366004613528565b610ee1565b34801561045157600080fd5b506102266104603660046130ba565b611002565b34801561047157600080fd5b5061049b610480366004613566565b6002602052600090815260409020546001600160a01b031681565b6040516101b091906135c9565b6001546000906001600160a01b031633146104de5760405162461bcd60e51b81526004016104d59061360e565b60405180910390fd5b600260075414156105015760405162461bcd60e51b81526004016104d590613652565b600260075560006105148486018661383c565b905061052787878360400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24581600001516000888a8560800151600260405161056a96959493929190613892565b60405180910390a16001915050600160075595945050505050565b6000546001600160a01b031633146105af5760405162461bcd60e51b81526004016104d59061391e565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f3f8223bcd8b3b875473e9f9e14e1ad075451a2b5ffd31591655da9a01516bf5e916105fb916130ac565b60405180910390a150565b6001546000906001600160a01b031633146106335760405162461bcd60e51b81526004016104d59061360e565b600260075414156106565760405162461bcd60e51b81526004016104d590613652565b600260075582516000906106739085016020908101908601613b67565b905060008160800151876106879190613bb8565b905061069a88828460400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24582600001516000838b866080015160026040516106dd96959493929190613892565b60405180910390a16001925050505b60016007559695505050505050565b6000546001600160a01b031633146107255760405162461bcd60e51b81526004016104d59061391e565b600880546001600160a01b0319166001600160a01b0383161790556040517fb878cd71628ac64b2df1872301925e01164824535b02e8601077749eeeb88c3d906105fb9083906130ac565b6000546001600160a01b0316331461079a5760405162461bcd60e51b81526004016104d59061391e565b6107a583838361118e565b7f5e20184b00709d9f103306958e9fb9d509f78bec1829ca7080f2c43eb2ff21a88383836040516107d893929190613bdf565b60405180910390a1505050565b6000546001600160a01b0316331461080f5760405162461bcd60e51b81526004016104d59061391e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb906108629083908590613c07565b60405180910390a15050565b6000546001600160a01b031633146108985760405162461bcd60e51b81526004016104d59061391e565b6108a26000611225565b565b6001546000906001600160a01b031633146108d15760405162461bcd60e51b81526004016104d59061360e565b600260075414156108f45760405162461bcd60e51b81526004016104d590613652565b600260075582516000906109119085016020908101908601613b67565b90508060800151861015610974576080810186905280516040517f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245916109629160009081908c908c90600190613c22565b60405180910390a160019150506106ec565b60808101516109839087613bb8565b955060608101516020820151518891908890600090156109fd57606060006109ae8760200151611275565b90985093509150506001600160a01b03808216908e16146109e15760405162461bcd60e51b81526004016104d590613c7e565b6109f58760200151838e8a60a001516114a3565b909450925050505b8015610a1457610a148b828760400151600061105e565b610a24848387604001518661105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245856000015183838e89608001516001604051610a6696959493929190613c8e565b60405180910390a160019550505050505060016007559695505050505050565b60038181548110610a9657600080fd5b6000918252602090912001546001600160a01b0316905081565b6001546000906001600160a01b03163314610add5760405162461bcd60e51b81526004016104d59061360e565b95945050505050565b6000546001600160a01b03163314610b105760405162461bcd60e51b81526004016104d59061391e565b600680546001600160a01b038381166001600160a01b03198316179092556040519116907f5d16ad41baeb009cd23eb8f6c7cde5c2e0cd5acf4a33926ab488875c37c37f38906108629083908590613c07565b6000546001600160a01b03163314610b8d5760405162461bcd60e51b81526004016104d59061391e565b60008383604051610b9f929190613cbc565b60405180910390209050610c2081836001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b7f58ddcdb40971f55ad1b6a8a28067274a4ffc7e9d77c3ea14a17652faa705e1978183604051610c51929190613cc9565b60405180910390a150505050565b60026007541415610c825760405162461bcd60e51b81526004016104d590613652565b600260075582151580610cb8575067ffffffffffffffff4616610cab6040870160208801613cd7565b67ffffffffffffffff1614155b610cd45760405162461bcd60e51b81526004016104d590613d12565b82151580610d0c575061014085013515801590610d0c57506000610d00610180870161016088016130ba565b6001600160a01b031614155b610d285760405162461bcd60e51b81526004016104d590613d12565b6101408501356000610d42610180880161016089016130ba565b90506000610d5861018089016101608a016130ba565b905060608615610dc057610d74610d6f888a613d22565b611275565b92965090945092509050610d906101808a016101608b016130ba565b6001600160a01b0316836001600160a01b031614610dc05760405162461bcd60e51b81526004016104d590613c7e565b610dd060c08a0160a08b01613d2f565b15610e90576008546001600160a01b03848116911614610e025760405162461bcd60e51b81526004016104d590613d84565b83341015610e225760405162461bcd60e51b81526004016104d590613dc8565b600860009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b5050505050610ea5565b610ea56001600160a01b0384163330876117e6565b610ed08a858585610eb68c8e613d22565b610ec08b8d613d22565b8f610eca90613f6a565b88611853565b505060016007555050505050505050565b6006546001600160a01b03163314610f0b5760405162461bcd60e51b81526004016104d590613faa565b60005b82811015610ffc576000848483818110610f2a57610f2a613fba565b9050602002016020810190610f3f91906130ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f6a91906130ac565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190613fd0565b9050610fe98382878786818110610fc457610fc4613fba565b9050602002016020810190610fd991906130ba565b6001600160a01b031691906119c3565b5080610ff481613ff1565b915050610f0e565b50505050565b6000546001600160a01b0316331461102c5760405162461bcd60e51b81526004016104d59061391e565b6001600160a01b0381166110525760405162461bcd60e51b81526004016104d590614069565b61105b81611225565b50565b801561117a576008546001600160a01b038581169116146110915760405162461bcd60e51b81526004016104d5906140ad565b600854604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906110c19086906004016140bd565b600060405180830381600087803b1580156110db57600080fd5b505af11580156110ef573d6000803e3d6000fd5b505050506000826001600160a01b03168461c35090604051611110906140cb565b600060405180830381858888f193505050503d806000811461114e576040519150601f19603f3d011682016040523d82523d6000602084013e611153565b606091505b50509050806111745760405162461bcd60e51b81526004016104d59061410a565b50610ffc565b610ffc6001600160a01b03851683856119c3565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff1680151582151514156111e35760405162461bcd60e51b81526004016104d590613d12565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060006060600080611288876119e7565b925060005b875181101561149957600460008983815181106112ac576112ac613fba565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008983815181106112ec576112ec613fba565b6020026020010151602001516113019061412e565b6001600160e01b031916815260208101919091526040016000205460ff1661133b5760405162461bcd60e51b81526004016104d5906141a7565b600080600086848151811061135257611352613fba565b60200260200101516001600160a01b031663358f0e1c8c868151811061137a5761137a613fba565b60200260200101516040518263ffffffff1660e01b815260040161139e9190614215565b606060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190614226565b919450925090506001600160a01b038616158061140d5750816001600160a01b0316866001600160a01b0316145b6114295760405162461bcd60e51b81526004016104d5906142a0565b90945084906001600160a01b03851615806114555750806001600160a01b0316856001600160a01b0316145b6114715760405162461bcd60e51b81526004016104d5906142e4565b93508361147e838b6142f4565b9950909750955081905061149181613ff1565b91505061128d565b5050509193509193565b60008060008060006114b689888a611b27565b9250925092506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114ea91906130ac565b602060405180830381865afa158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190613fd0565b905060005b8a518110156117395760008a828151811061154d5761154d613fba565b60200260200101516001600160a01b0316634c6da2698d848151811061157557611575613fba565b60200260200101516020015188858151811061159357611593613fba565b6020026020010151306040518463ffffffff1660e01b81526004016115ba9392919061430c565b600060405180830381865afa1580156115d7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115ff9190810190614339565b90506116558c838151811061161657611616613fba565b60200260200101516000015187848151811061163457611634613fba565b6020026020010151876001600160a01b0316611cdc9092919063ffffffff16565b60008c838151811061166957611669613fba565b6020026020010151600001516001600160a01b03168260405161168c9190614396565b6000604051808303816000865af19150503d80600081146116c9576040519150601f19603f3d011682016040523d82523d6000602084013e6116ce565b606091505b5050905080806116db5750895b6116f75760405162461bcd60e51b81526004016104d5906143d6565b806117245786838151811061170e5761170e613fba565b60200260200101518861172191906142f4565b97505b5050808061173190613ff1565b915050611530565b506040516370a0823160e01b81526000906001600160a01b038416906370a08231906117699030906004016130ac565b602060405180830381865afa158015611786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117aa9190613fd0565b90506117b68282613bb8565b9650600087116117d85760405162461bcd60e51b81526004016104d59061441a565b505050505094509492505050565b610ffc846323b872dd60e01b8585856040516024016118079392919061442a565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152611d79565b835187901561188b5760006118688684611e08565b92509050806118895760405162461bcd60e51b81526004016104d590614486565b505b600061189f84600001518560800151612152565b90504667ffffffffffffffff16846020015167ffffffffffffffff16141561191b577f0e248ac8be20725176a5f0ab093c5fbb964634d4675012f3d3ad66e69e56d5b7818a8a858b6040516118f8959493929190614496565b60405180910390a1611914878386600001518760c0015161105e565b50506119b9565b611926848a8a61218a565b60a084015134901561193f5761193c8a34613bb8565b90505b600080875111611950578551611952565b8b5b905060006119658483898b898f89612213565b90507fbac7d3515b47f762d5edcc83b041c8ad43133089d06f60e3b8f307a66fcb6221848289602001518f8f8c6101800151886040516119ab97969594939291906144f2565b60405180910390a150505050505b5050505050505050565b6119e28363a9059cbb60e01b848460405160240161180792919061455a565b505050565b60606000825167ffffffffffffffff811115611a0557611a056130f6565b604051908082528060200260200182016040528015611a2e578160200160208202803683370190505b50905060005b8351811015611b20576000848281518110611a5157611a51613fba565b602002602001015160200151611a669061412e565b6001600160e01b0319811660009081526002602052604090205484519192506001600160a01b031690849084908110611aa157611aa1613fba565b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b0316838381518110611ade57611ade613fba565b60200260200101516001600160a01b03161415611b0d5760405162461bcd60e51b81526004016104d5906145a9565b5080611b1881613ff1565b915050611a34565b5092915050565b60606000806000865167ffffffffffffffff811115611b4857611b486130f6565b604051908082528060200260200182016040528015611b71578160200160208202803683370190505b50935060005b8751811015611c65576000868281518110611b9457611b94613fba565b60200260200101516001600160a01b031663358f0e1c8a8481518110611bbc57611bbc613fba565b60200260200101516040518263ffffffff1660e01b8152600401611be09190614215565b606060405180830381865afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c219190614226565b90965094509050611c3281846142f4565b925080868381518110611c4757611c47613fba565b60209081029190910101525080611c5d81613ff1565b915050611b77565b5060005b8451811015611cd15781858281518110611c8557611c85613fba565b602002602001015188611c9891906145b9565b611ca291906145ee565b858281518110611cb457611cb4613fba565b602090810291909101015280611cc981613ff1565b915050611c69565b505093509350939050565b600081846001600160a01b031663dd62ed3e30866040518363ffffffff1660e01b8152600401611d0d929190613c07565b602060405180830381865afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613fd0565b611d5891906142f4565b9050610ffc8463095ea7b360e01b858460405160240161180792919061455a565b6000611dce826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122679092919063ffffffff16565b8051909150156119e25780806020019051810190611dec9190614602565b6119e25760405162461bcd60e51b81526004016104d59061467d565b60008060005b8451811015612149576000806000868481518110611e2e57611e2e613fba565b60200260200101516001600160a01b031663358f0e1c898681518110611e5657611e56613fba565b60200260200101516040518263ffffffff1660e01b8152600401611e7a9190614215565b606060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190614226565b9250925092506000878581518110611ed557611ed5613fba565b60200260200101516001600160a01b0316634c6da2698a8781518110611efd57611efd613fba565b60200260200101516020015186306040518463ffffffff1660e01b8152600401611f299392919061430c565b600060405180830381865afa158015611f46573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f6e9190810190614339565b9050611fa2898681518110611f8557611f85613fba565b6020908102919091010151516001600160a01b0385169086611cdc565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611fd19030906004016130ac565b602060405180830381865afa158015611fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120129190613fd0565b905089868151811061202657612026613fba565b6020026020010151600001516001600160a01b0316826040516120499190614396565b6000604051808303816000865af19150503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b505080985050876120a8576000809750975050505050505061214b565b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906120d79030906004016130ac565b602060405180830381865afa1580156120f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121189190613fd0565b90506121248282613bb8565b61212e90896142f4565b9750505050505050808061214190613ff1565b915050611e0e565b505b9250929050565b60003383468460405160200161216b94939291906146d4565b6040516020818303038152906040528051906020012090505b92915050565b600046846020015184848761010001518860e001516040516020016121b49695949392919061471c565b60405160208183030381529060405280519060200120905060006121d782612280565b90506121e8818661012001516122b0565b428561010001511161220c5760405162461bcd60e51b81526004016104d5906147e0565b5050505050565b6000806122218988886122ec565b905061225a8885878a602001518b608001518c60400151878e60600151600160009054906101000a90046001600160a01b03168c612361565b9998505050505050505050565b606061227684846000856123fa565b90505b9392505050565b60008160405160200161229391906147f0565b604051602081830303815290604052805190602001209050919050565b60006122bc83836124be565b6005549091506001600160a01b038083169116146119e25760405162461bcd60e51b81526004016104d59061485f565b60606040518060c0016040528085815260200183815260200184600001516001600160a01b031681526020018460c00151151581526020018460e001518152602001846101a001511515815250604051602001612349919061495b565b60405160208183030381529060405290509392505050565b60008060006123768d8d8d8d8d8d8c8c6124e2565b88519193509150156123ea57846001600160a01b0316634289fbb3858f8d85878d6040518763ffffffff1660e01b81526004016123b795949392919061498b565b6000604051808303818588803b1580156123d057600080fd5b505af11580156123e4573d6000803e3d6000fd5b50505050505b509b9a5050505050505050505050565b60608247101561241c5760405162461bcd60e51b81526004016104d590614a2c565b6001600160a01b0385163b6124435760405162461bcd60e51b81526004016104d590614a70565b600080866001600160a01b0316858760405161245f9190614396565b60006040518083038185875af1925050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50915091506124b1828286612b29565b925050505b949350505050565b60008060006124cd8585612b62565b915091506124da81612bcf565b509392505050565b60008060018460068111156124f9576124f9613046565b14156125f357826001600160a01b03166382980dc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190614a80565b90506125776001600160a01b038a16828a611cdc565b60405163a5977fbb60e01b81526001600160a01b0382169063a5977fbb906125ad908d908d908d908d908d908d90600401614aad565b600060405180830381600087803b1580156125c757600080fd5b505af11580156125db573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cb4565b9150612b1c565b600284600681111561260757612607613046565b14156126f857826001600160a01b031663d8257d176040518163ffffffff1660e01b8152600401602060405180830381865afa15801561264b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266f9190614a80565b90506126856001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016126b9959493929190614afc565b600060405180830381600087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cf4565b600384600681111561270c5761270c613046565b141561281057826001600160a01b031663dfa2dbaf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127749190614a80565b905061278a6001600160a01b038a16828a611cdc565b604051636f3c863f60e11b81526001600160a01b0382169063de790c7e906127bc908c908c908f908c90600401614b3e565b600060405180830381600087803b1580156127d657600080fd5b505af11580156127ea573d6000803e3d6000fd5b50612804925050506001600160a01b038a16826000612d13565b6125ec8a8a8a89612dc7565b600484600681111561282457612824613046565b141561291957826001600160a01b031663c66a9c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288c9190614a80565b90506128a26001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016128d6959493929190614afc565b6020604051808303816000875af11580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190613fd0565b600584600681111561292d5761292d613046565b1415612a3e57826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129959190614a80565b90506129ab6001600160a01b038a16828a611cdc565b806001600160a01b031663a00293018a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b6020604051808303816000875af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190613fd0565b9150612a396001600160a01b038a16826000612d13565b612b1c565b6006846006811115612a5257612a52613046565b1415612b0457826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aba9190614a80565b9050612ad06001600160a01b038a16828a611cdc565b806001600160a01b0316639e422c338a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b60405162461bcd60e51b81526004016104d590614ba7565b9850989650505050505050565b60608315612b38575081612279565b825115612b485782518084602001fd5b8160405162461bcd60e51b81526004016104d59190614bb7565b600080825160411415612b995760208301516040840151606085015160001a612b8d87828585612e04565b9450945050505061214b565b825160401415612bc35760208301516040840151612bb8868383612ee4565b93509350505061214b565b5060009050600261214b565b6000816004811115612be357612be3613046565b1415612bec5750565b6001816004811115612c0057612c00613046565b1415612c1e5760405162461bcd60e51b81526004016104d590614bfc565b6002816004811115612c3257612c32613046565b1415612c505760405162461bcd60e51b81526004016104d590614c40565b6003816004811115612c6457612c64613046565b1415612c825760405162461bcd60e51b81526004016104d590614c8f565b6004816004811115612c9657612c96613046565b141561105b5760405162461bcd60e51b81526004016104d590614cde565b600030868686868646604051602001612cd39796959493929190614cee565b60405160208183030381529060405280519060200120905095945050505050565b600030858585898646604051602001612cd39796959493929190614d69565b801580612d8c5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612d499030908690600401613c07565b602060405180830381865afa158015612d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8a9190613fd0565b155b612da85760405162461bcd60e51b81526004016104d590614e1f565b6119e28363095ea7b360e01b848460405160240161180792919061455a565b6000308484878546604051602001612de496959493929190614e2f565b604051602081830303815290604052805190602001209050949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e3b5750600090506003612edb565b8460ff16601b14158015612e5357508460ff16601c14155b15612e645750600090506004612edb565b600060018787878760405160008152602001604052604051612e899493929190614ea2565b6020604051602081039080840390855afa158015612eab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ed457600060019250925050612edb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681612f1a60ff86901c601b6142f4565b9050612f2887828885612e04565b935093505050935093915050565b60006001600160a01b038216612184565b612f5081612f36565b811461105b57600080fd5b803561218481612f47565b80612f50565b803561218481612f66565b60008083601f840112612f8c57612f8c600080fd5b50813567ffffffffffffffff811115612fa757612fa7600080fd5b60208301915083600182028301111561214b5761214b600080fd5b600080600080600060808688031215612fdd57612fdd600080fd5b6000612fe98888612f5b565b9550506020612ffa88828901612f6c565b945050604086013567ffffffffffffffff81111561301a5761301a600080fd5b61302688828901612f77565b9350935050606061303988828901612f5b565b9150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6003811061105b5761105b613046565b806130768161305c565b919050565b60006121848261306c565b61308f8161307b565b82525050565b602081016121848284613086565b61308f81612f36565b6020810161218482846130a3565b6000602082840312156130cf576130cf600080fd5b60006124b68484612f5b565b67ffffffffffffffff8116612f50565b8035612184816130db565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613132576131326130f6565b6040525050565b600061314460405190565b9050613076828261310c565b600067ffffffffffffffff82111561316a5761316a6130f6565b601f19601f83011660200192915050565b82818337506000910152565b600061319a61319584613150565b613139565b9050828152602081018484840111156131b5576131b5600080fd5b6124da84828561317b565b600082601f8301126131d4576131d4600080fd5b81356124b6848260208601613187565b60008060008060008060c0878903121561320057613200600080fd5b600061320c8989612f5b565b965050602061321d89828a01612f5b565b955050604061322e89828a01612f6c565b945050606061323f89828a016130eb565b935050608087013567ffffffffffffffff81111561325f5761325f600080fd5b61326b89828a016131c0565b92505060a061327c89828a01612f5b565b9150509295509295509295565b6001600160e01b03198116612f50565b803561218481613289565b801515612f50565b8035612184816132a4565b6000806000606084860312156132cf576132cf600080fd5b60006132db8686612f5b565b93505060206132ec86828701613299565b92505060406132fd868287016132ac565b9150509250925092565b60006020828403121561331c5761331c600080fd5b60006124b68484612f6c565b6000806040838503121561333e5761333e600080fd5b600061334a8585612f5b565b925050602061335b85828601613299565b9150509250929050565b80151561308f565b602081016121848284613365565b60008060008060006080868803121561339657613396600080fd5b60006133a28888612f5b565b9550506020612ffa888289016130eb565b6000806000604084860312156133cb576133cb600080fd5b833567ffffffffffffffff8111156133e5576133e5600080fd5b6133f186828701612f77565b935093505060206132fd86828701612f5b565b60006101c0828403121561341a5761341a600080fd5b50919050565b60008083601f84011261343557613435600080fd5b50813567ffffffffffffffff81111561345057613450600080fd5b60208301915083602082028301111561214b5761214b600080fd5b6000806000806000806080878903121561348757613487600080fd5b60006134938989612f5b565b965050602087013567ffffffffffffffff8111156134b3576134b3600080fd5b6134bf89828a01613404565b955050604087013567ffffffffffffffff8111156134df576134df600080fd5b6134eb89828a01613420565b9450945050606087013567ffffffffffffffff81111561350d5761350d600080fd5b61351989828a01613420565b92509250509295509295509295565b60008060006040848603121561354057613540600080fd5b833567ffffffffffffffff81111561355a5761355a600080fd5b6133f186828701613420565b60006020828403121561357b5761357b600080fd5b60006124b68484613299565b60006121846001600160a01b03831661359e565b90565b6001600160a01b031690565b600061218482613587565b6000612184826135aa565b61308f816135b5565b6020810161218482846135c0565b601981526000602082017f63616c6c6572206973206e6f74206d6573736167652062757300000000000000815291505b5060200190565b60208082528101612184816135d7565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150613607565b602080825281016121848161361e565b600067ffffffffffffffff82111561367c5761367c6130f6565b5060209081020190565b60006040828403121561369b5761369b600080fd5b6136a56040613139565b905060006136b38484612f5b565b825250602082013567ffffffffffffffff8111156136d3576136d3600080fd5b6136df848285016131c0565b60208301525092915050565b60006136f961319584613662565b8381529050602080820190840283018581111561371857613718600080fd5b835b8181101561375957803567ffffffffffffffff81111561373c5761373c600080fd5b8086016137498982613686565b855250506020928301920161371a565b5050509392505050565b600082601f83011261377757613777600080fd5b81356124b68482602086016136eb565b600060c0828403121561379c5761379c600080fd5b6137a660c0613139565b905060006137b48484612f6c565b825250602082013567ffffffffffffffff8111156137d4576137d4600080fd5b6137e084828501613763565b60208301525060406137f484828501612f5b565b6040830152506060613808848285016132ac565b606083015250608061381c84828501612f6c565b60808301525060a0613830848285016132ac565b60a08301525092915050565b60006020828403121561385157613851600080fd5b813567ffffffffffffffff81111561386b5761386b600080fd5b6124b684828501613787565b8061308f565b600061218461359b8381565b61308f8161387d565b60c081016138a08289613877565b6138ad6020830188613889565b6138ba6040830187613877565b6138c760608301866130a3565b6138d46080830185613877565b6138e160a0830184613086565b979650505050505050565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613607565b60208082528101612184816138ec565b805161218481612f66565b805161218481612f47565b60005b8381101561395f578181015183820152602001613947565b83811115610ffc5750506000910152565b600061397e61319584613150565b90508281526020810184848401111561399957613999600080fd5b6124da848285613944565b600082601f8301126139b8576139b8600080fd5b81516124b6848260208601613970565b6000604082840312156139dd576139dd600080fd5b6139e76040613139565b905060006139f58484613939565b825250602082015167ffffffffffffffff811115613a1557613a15600080fd5b6136df848285016139a4565b6000613a2f61319584613662565b83815290506020808201908402830185811115613a4e57613a4e600080fd5b835b8181101561375957805167ffffffffffffffff811115613a7257613a72600080fd5b808601613a7f89826139c8565b8552505060209283019201613a50565b600082601f830112613aa357613aa3600080fd5b81516124b6848260208601613a21565b8051612184816132a4565b600060c08284031215613ad357613ad3600080fd5b613add60c0613139565b90506000613aeb848461392e565b825250602082015167ffffffffffffffff811115613b0b57613b0b600080fd5b613b1784828501613a8f565b6020830152506040613b2b84828501613939565b6040830152506060613b3f84828501613ab3565b6060830152506080613b538482850161392e565b60808301525060a061383084828501613ab3565b600060208284031215613b7c57613b7c600080fd5b815167ffffffffffffffff811115613b9657613b96600080fd5b6124b684828501613abe565b634e487b7160e01b600052601160045260246000fd5b600082821015613bca57613bca613ba2565b500390565b6001600160e01b0319811661308f565b60608101613bed82866130a3565b613bfa6020830185613bcf565b6124b66040830184613365565b60408101613c1582856130a3565b61227960208301846130a3565b60c08101613c308289613877565b613c3d6020830188613889565b6138ba6040830187613889565b600781526000602082017f746b696e206d6d0000000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481613c4a565b60c08101613c9c8289613877565b6138ad6020830188613877565b6000613cb683858461317b565b50500190565b60006124b6828486613ca9565b60408101613c158285613bcf565b600060208284031215613cec57613cec600080fd5b60006124b684846130eb565b600381526000602082016206e6f760ec1b81529150613607565b6020808252810161218481613cf8565b60006122793684846136eb565b600060208284031215613d4457613d44600080fd5b60006124b684846132ac565b601281526000602082017f746b696e206e6f206e617469766557726170000000000000000000000000000081529150613607565b6020808252810161218481613d50565b600b81526000602082017f696e7366636e7420616d7400000000000000000000000000000000000000000081529150613607565b6020808252810161218481613d94565b63ffffffff8116612f50565b803561218481613dd8565b6007811061105b57600080fd5b803561218481613def565b60006101c08284031215613e1d57613e1d600080fd5b613e286101c0613139565b90506000613e368484612f5b565b8252506020613e47848483016130eb565b6020830152506040613e5b84828501613de4565b6040830152506060613e6f84828501613dfc565b6060830152506080613e83848285016130eb565b60808301525060a0613e97848285016132ac565b60a08301525060c0613eab848285016132ac565b60c08301525060e0613ebf84828501612f6c565b60e083015250610100613ed484828501612f6c565b6101008301525061012082013567ffffffffffffffff811115613ef957613ef9600080fd5b613f05848285016131c0565b61012083015250610140613f1b84828501612f6c565b61014083015250610160613f3184828501612f5b565b61016083015250610180613f4784828501612f5b565b610180830152506101a0613f5d848285016132ac565b6101a08301525092915050565b60006121843683613e07565b601181526000602082017f6e6f742066656520636f6c6c6563746f7200000000000000000000000000000081529150613607565b6020808252810161218481613f76565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613fe557613fe5600080fd5b60006124b6848461392e565b600060001982141561400557614005613ba2565b5060010190565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015291505b5060400190565b602080825281016121848161400c565b600c81526000602082017f746b206e6f206e6174697665000000000000000000000000000000000000000081529150613607565b6020808252810161218481614079565b602081016121848284613877565b60006121848261359b565b600981526000602082017f73656e64206661696c000000000000000000000000000000000000000000000081529150613607565b60208082528101612184816140d6565b600061218482516001600160e01b03191690565b6000614138825190565b602083016141458161411a565b9250600482101561416c576141676001600160e01b0319836004036008021b90565b831692505b5050919050565b600f81526000602082017f756e737570706f7274656420646578000000000000000000000000000000000081529150613607565b6020808252810161218481614173565b60006141c1825190565b8084526020840193506141d8818560208601613944565b601f01601f19169290920192915050565b805160009060408401906141fd85826130a3565b5060208301518482036020860152610add82826141b7565b6020808252810161227981846141e9565b60008060006060848603121561423e5761423e600080fd5b600061424a868661392e565b935050602061425b86828701613939565b92505060406132fd86828701613939565b600d81526000602082017f746b696e206d69736d617463680000000000000000000000000000000000000081529150613607565b602080825281016121848161426c565b600c81526000602082017f746b6f206d69736d61746368000000000000000000000000000000000000000081529150613607565b60208082528101612184816142b0565b6000821982111561430757614307613ba2565b500190565b6060808252810161431d81866141b7565b905061432c6020830185613877565b6124b660408301846130a3565b60006020828403121561434e5761434e600080fd5b815167ffffffffffffffff81111561436857614368600080fd5b6124b6848285016139a4565b600061437e825190565b61438c818560208601613944565b9290920192915050565b60006122798284614374565b600b81526000602082017f73776170206661696c656400000000000000000000000000000000000000000081529150613607565b60208082528101612184816143a2565b601081526000602082017f616c6c207377617073206661696c65640000000000000000000000000000000081529150613607565b60208082528101612184816143e6565b6060810161443882866130a3565b61444560208301856130a3565b6124b66040830184613877565b600981526000602082017f73776170206661696c000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481614452565b60a081016144a48288613877565b6144b16020830187613877565b6144be60408301866130a3565b6144cb6060830185613877565b6144d860808301846130a3565b9695505050505050565b67ffffffffffffffff811661308f565b60e08101614500828a613877565b61450d6020830189613877565b61451a60408301886144e2565b6145276060830187613877565b61453460808301866130a3565b61454160a08301856130a3565b61454e60c08301846130a3565b98975050505050505050565b6040810161456882856130a3565b6122796020830184613877565b600c81526000602082017f636463206e6f20666f756e64000000000000000000000000000000000000000081529150613607565b6020808252810161218481614575565b60008160001904831182151516156145d3576145d3613ba2565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145fd576145fd6145d8565b500490565b60006020828403121561461757614617600080fd5b60006124b68484613ab3565b602a81526000602082017f5361666545524332303a204552433230206f7065726174696f6e20646964206e81527f6f7420737563636565640000000000000000000000000000000000000000000060208201529150614062565b6020808252810161218481614623565b60006121848260601b90565b60006121848261468d565b61308f6146b082612f36565b614699565b60006121848260c01b90565b61308f67ffffffffffffffff82166146b5565b60006146e082876146a4565b6014820191506146f082866146a4565b60148201915061470082856146c1565b60088201915061471082846146c1565b50600801949350505050565b7f6578656375746f722066656500000000000000000000000000000000000000008152600c01600061474e82896146c1565b60088201915061475e82886146c1565b60088201915061476e8287613877565b60208201915061477e82866146a4565b60148201915061478e8285613877565b60208201915061479e8284613877565b506020019695505050505050565b601181526000602082017f646561646c696e6520657863656564656400000000000000000000000000000081529150613607565b60208082528101612184816147ac565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0160006148228284613877565b50602001919050565b600e81526000602082017f696e76616c6964207369676e657200000000000000000000000000000000000081529150613607565b602080825281016121848161482b565b600061227983836141e9565b6000614885825190565b8084526020840193508360208202850161489f8560200190565b8060005b858110156148d457848403895281516148bc858261486f565b94506020830160209a909a01999250506001016148a3565b5091979650505050505050565b805160009060c08401906148f58582613877565b506020830151848203602086015261490d828261487b565b915050604083015161492260408601826130a3565b5060608301516149356060860182613365565b5060808301516149486080860182613877565b5060a08301516124da60a0860182613365565b6020808252810161227981846148e1565b600061218461359b67ffffffffffffffff841681565b61308f8161496c565b60a0810161499982886130a3565b6149a66020830187614982565b6149b360408301866130a3565b6149c06060830185613877565b81810360808301526138e181846141b7565b602681526000602082017f416464726573733a20696e73756666696369656e742062616c616e636520666f81527f722063616c6c000000000000000000000000000000000000000000000000000060208201529150614062565b60208082528101612184816149d2565b601d81526000602082017f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081529150613607565b6020808252810161218481614a3c565b600060208284031215614a9557614a95600080fd5b60006124b68484613939565b63ffffffff811661308f565b60c08101614abb82896130a3565b614ac860208301886130a3565b614ad56040830187613877565b614ae260608301866144e2565b614aef60808301856144e2565b6138e160a0830184614aa1565b60a08101614b0a82886130a3565b614b176020830187613877565b614b2460408301866144e2565b614b3160608301856130a3565b6144d860808301846144e2565b60808101614b4c82876130a3565b614b596020830186613877565b614b6660408301856130a3565b610add60608301846144e2565b601981526000602082017f6272696467652074797065206e6f7420737570706f727465640000000000000081529150613607565b6020808252810161218481614b73565b6020808252810161227981846141b7565b601881526000602082017f45434453413a20696e76616c6964207369676e6174757265000000000000000081529150613607565b6020808252810161218481614bc8565b601f81526000602082017f45434453413a20696e76616c6964207369676e6174757265206c656e6774680081529150613607565b6020808252810161218481614c0c565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c50565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c9f565b6000614cfa828a6146a4565b601482019150614d0a82896146a4565b601482019150614d1a82886146a4565b601482019150614d2a8287613877565b602082019150614d3a82866146c1565b600882019150614d4a82856146c1565b600882019150614d5a82846146c1565b50600801979650505050505050565b6000614d75828a6146a4565b601482019150614d8582896146a4565b601482019150614d958288613877565b602082019150614da582876146c1565b600882019150614db582866146a4565b601482019150614d4a82856146c1565b603681526000602082017f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060208201529150614062565b6020808252810161218481614dc5565b6000614e3b82896146a4565b601482019150614e4b82886146a4565b601482019150614e5b8287613877565b602082019150614e6b82866146a4565b601482019150614e7b82856146c1565b600882019150614e8b82846146c1565b506008019695505050505050565b60ff811661308f565b60808101614eb08287613877565b614ebd6020830186614e99565b614eca6040830185613877565b610add606083018461387756fea2646970667358221220eae1c3b25d0ff199671cc0ccdeb5ab9d13b1454bc5f6ee971c30f3211cf9448d64736f6c634300080c00330000000000000000000000000d71d18126e03646eb09fec929e2ae87b7cae69d000000000000000000000000420000000000000000000000000000000000000600000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d8000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e743235362929000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000db7e4d4dd546a6df6f9a312761e1b63c2036a7820000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000
Deployed Bytecode
0x6080604052600436106101845760003560e01c80638da5cb5b116100d6578063c415b95c1161007f578063efcfd8f511610059578063efcfd8f514610425578063f2fde38b14610445578063fbf5d7631461046557600080fd5b8063c415b95c146103d2578063c5bccca3146103f2578063d8318ae51461041257600080fd5b8063a1a227fa116100b0578063a1a227fa1461035c578063a1c9d41e1461037c578063a42dce80146103b257600080fd5b80638da5cb5b146102e357806391ec04b5146103015780639c649fdf1461034957600080fd5b80635b5a66a711610138578063715018a611610112578063715018a61461029b5780637cd2bffc146102b057806382665a8f146102c357600080fd5b80635b5a66a71461023b578063675df7591461025b5780636c19e7831461027b57600080fd5b8063457bfa2f11610169578063457bfa2f146101e6578063547cad12146102065780635ab7afc61461022857600080fd5b80630bcb498214610190578063238ac933146101b957600080fd5b3661018b57005b600080fd5b6101a361019e366004612fc2565b6104a8565b6040516101b09190613095565b60405180910390f35b3480156101c557600080fd5b506005546101d9906001600160a01b031681565b6040516101b091906130ac565b3480156101f257600080fd5b506008546101d9906001600160a01b031681565b34801561021257600080fd5b506102266102213660046130ba565b610585565b005b6101a36102363660046131e4565b610606565b34801561024757600080fd5b506102266102563660046130ba565b6106fb565b34801561026757600080fd5b506102266102763660046132b7565b610770565b34801561028757600080fd5b506102266102963660046130ba565b6107e5565b3480156102a757600080fd5b5061022661086e565b6101a36102be3660046131e4565b6108a4565b3480156102cf57600080fd5b506101d96102de366004613307565b610a86565b3480156102ef57600080fd5b506000546001600160a01b03166101d9565b34801561030d57600080fd5b5061033c61031c366004613328565b600460209081526000928352604080842090915290825290205460ff1681565b6040516101b0919061336d565b6101a361035736600461337b565b610ab0565b34801561036857600080fd5b506001546101d9906001600160a01b031681565b34801561038857600080fd5b506101d9610397366004613307565b6009602052600090815260409020546001600160a01b031681565b3480156103be57600080fd5b506102266103cd3660046130ba565b610ae6565b3480156103de57600080fd5b506006546101d9906001600160a01b031681565b3480156103fe57600080fd5b5061022661040d3660046133b3565b610b63565b61022661042036600461346b565b610c5f565b34801561043157600080fd5b50610226610440366004613528565b610ee1565b34801561045157600080fd5b506102266104603660046130ba565b611002565b34801561047157600080fd5b5061049b610480366004613566565b6002602052600090815260409020546001600160a01b031681565b6040516101b091906135c9565b6001546000906001600160a01b031633146104de5760405162461bcd60e51b81526004016104d59061360e565b60405180910390fd5b600260075414156105015760405162461bcd60e51b81526004016104d590613652565b600260075560006105148486018661383c565b905061052787878360400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24581600001516000888a8560800151600260405161056a96959493929190613892565b60405180910390a16001915050600160075595945050505050565b6000546001600160a01b031633146105af5760405162461bcd60e51b81526004016104d59061391e565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f3f8223bcd8b3b875473e9f9e14e1ad075451a2b5ffd31591655da9a01516bf5e916105fb916130ac565b60405180910390a150565b6001546000906001600160a01b031633146106335760405162461bcd60e51b81526004016104d59061360e565b600260075414156106565760405162461bcd60e51b81526004016104d590613652565b600260075582516000906106739085016020908101908601613b67565b905060008160800151876106879190613bb8565b905061069a88828460400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24582600001516000838b866080015160026040516106dd96959493929190613892565b60405180910390a16001925050505b60016007559695505050505050565b6000546001600160a01b031633146107255760405162461bcd60e51b81526004016104d59061391e565b600880546001600160a01b0319166001600160a01b0383161790556040517fb878cd71628ac64b2df1872301925e01164824535b02e8601077749eeeb88c3d906105fb9083906130ac565b6000546001600160a01b0316331461079a5760405162461bcd60e51b81526004016104d59061391e565b6107a583838361118e565b7f5e20184b00709d9f103306958e9fb9d509f78bec1829ca7080f2c43eb2ff21a88383836040516107d893929190613bdf565b60405180910390a1505050565b6000546001600160a01b0316331461080f5760405162461bcd60e51b81526004016104d59061391e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb906108629083908590613c07565b60405180910390a15050565b6000546001600160a01b031633146108985760405162461bcd60e51b81526004016104d59061391e565b6108a26000611225565b565b6001546000906001600160a01b031633146108d15760405162461bcd60e51b81526004016104d59061360e565b600260075414156108f45760405162461bcd60e51b81526004016104d590613652565b600260075582516000906109119085016020908101908601613b67565b90508060800151861015610974576080810186905280516040517f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245916109629160009081908c908c90600190613c22565b60405180910390a160019150506106ec565b60808101516109839087613bb8565b955060608101516020820151518891908890600090156109fd57606060006109ae8760200151611275565b90985093509150506001600160a01b03808216908e16146109e15760405162461bcd60e51b81526004016104d590613c7e565b6109f58760200151838e8a60a001516114a3565b909450925050505b8015610a1457610a148b828760400151600061105e565b610a24848387604001518661105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245856000015183838e89608001516001604051610a6696959493929190613c8e565b60405180910390a160019550505050505060016007559695505050505050565b60038181548110610a9657600080fd5b6000918252602090912001546001600160a01b0316905081565b6001546000906001600160a01b03163314610add5760405162461bcd60e51b81526004016104d59061360e565b95945050505050565b6000546001600160a01b03163314610b105760405162461bcd60e51b81526004016104d59061391e565b600680546001600160a01b038381166001600160a01b03198316179092556040519116907f5d16ad41baeb009cd23eb8f6c7cde5c2e0cd5acf4a33926ab488875c37c37f38906108629083908590613c07565b6000546001600160a01b03163314610b8d5760405162461bcd60e51b81526004016104d59061391e565b60008383604051610b9f929190613cbc565b60405180910390209050610c2081836001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b7f58ddcdb40971f55ad1b6a8a28067274a4ffc7e9d77c3ea14a17652faa705e1978183604051610c51929190613cc9565b60405180910390a150505050565b60026007541415610c825760405162461bcd60e51b81526004016104d590613652565b600260075582151580610cb8575067ffffffffffffffff4616610cab6040870160208801613cd7565b67ffffffffffffffff1614155b610cd45760405162461bcd60e51b81526004016104d590613d12565b82151580610d0c575061014085013515801590610d0c57506000610d00610180870161016088016130ba565b6001600160a01b031614155b610d285760405162461bcd60e51b81526004016104d590613d12565b6101408501356000610d42610180880161016089016130ba565b90506000610d5861018089016101608a016130ba565b905060608615610dc057610d74610d6f888a613d22565b611275565b92965090945092509050610d906101808a016101608b016130ba565b6001600160a01b0316836001600160a01b031614610dc05760405162461bcd60e51b81526004016104d590613c7e565b610dd060c08a0160a08b01613d2f565b15610e90576008546001600160a01b03848116911614610e025760405162461bcd60e51b81526004016104d590613d84565b83341015610e225760405162461bcd60e51b81526004016104d590613dc8565b600860009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b5050505050610ea5565b610ea56001600160a01b0384163330876117e6565b610ed08a858585610eb68c8e613d22565b610ec08b8d613d22565b8f610eca90613f6a565b88611853565b505060016007555050505050505050565b6006546001600160a01b03163314610f0b5760405162461bcd60e51b81526004016104d590613faa565b60005b82811015610ffc576000848483818110610f2a57610f2a613fba565b9050602002016020810190610f3f91906130ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f6a91906130ac565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190613fd0565b9050610fe98382878786818110610fc457610fc4613fba565b9050602002016020810190610fd991906130ba565b6001600160a01b031691906119c3565b5080610ff481613ff1565b915050610f0e565b50505050565b6000546001600160a01b0316331461102c5760405162461bcd60e51b81526004016104d59061391e565b6001600160a01b0381166110525760405162461bcd60e51b81526004016104d590614069565b61105b81611225565b50565b801561117a576008546001600160a01b038581169116146110915760405162461bcd60e51b81526004016104d5906140ad565b600854604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906110c19086906004016140bd565b600060405180830381600087803b1580156110db57600080fd5b505af11580156110ef573d6000803e3d6000fd5b505050506000826001600160a01b03168461c35090604051611110906140cb565b600060405180830381858888f193505050503d806000811461114e576040519150601f19603f3d011682016040523d82523d6000602084013e611153565b606091505b50509050806111745760405162461bcd60e51b81526004016104d59061410a565b50610ffc565b610ffc6001600160a01b03851683856119c3565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff1680151582151514156111e35760405162461bcd60e51b81526004016104d590613d12565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060006060600080611288876119e7565b925060005b875181101561149957600460008983815181106112ac576112ac613fba565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008983815181106112ec576112ec613fba565b6020026020010151602001516113019061412e565b6001600160e01b031916815260208101919091526040016000205460ff1661133b5760405162461bcd60e51b81526004016104d5906141a7565b600080600086848151811061135257611352613fba565b60200260200101516001600160a01b031663358f0e1c8c868151811061137a5761137a613fba565b60200260200101516040518263ffffffff1660e01b815260040161139e9190614215565b606060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190614226565b919450925090506001600160a01b038616158061140d5750816001600160a01b0316866001600160a01b0316145b6114295760405162461bcd60e51b81526004016104d5906142a0565b90945084906001600160a01b03851615806114555750806001600160a01b0316856001600160a01b0316145b6114715760405162461bcd60e51b81526004016104d5906142e4565b93508361147e838b6142f4565b9950909750955081905061149181613ff1565b91505061128d565b5050509193509193565b60008060008060006114b689888a611b27565b9250925092506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114ea91906130ac565b602060405180830381865afa158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190613fd0565b905060005b8a518110156117395760008a828151811061154d5761154d613fba565b60200260200101516001600160a01b0316634c6da2698d848151811061157557611575613fba565b60200260200101516020015188858151811061159357611593613fba565b6020026020010151306040518463ffffffff1660e01b81526004016115ba9392919061430c565b600060405180830381865afa1580156115d7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115ff9190810190614339565b90506116558c838151811061161657611616613fba565b60200260200101516000015187848151811061163457611634613fba565b6020026020010151876001600160a01b0316611cdc9092919063ffffffff16565b60008c838151811061166957611669613fba565b6020026020010151600001516001600160a01b03168260405161168c9190614396565b6000604051808303816000865af19150503d80600081146116c9576040519150601f19603f3d011682016040523d82523d6000602084013e6116ce565b606091505b5050905080806116db5750895b6116f75760405162461bcd60e51b81526004016104d5906143d6565b806117245786838151811061170e5761170e613fba565b60200260200101518861172191906142f4565b97505b5050808061173190613ff1565b915050611530565b506040516370a0823160e01b81526000906001600160a01b038416906370a08231906117699030906004016130ac565b602060405180830381865afa158015611786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117aa9190613fd0565b90506117b68282613bb8565b9650600087116117d85760405162461bcd60e51b81526004016104d59061441a565b505050505094509492505050565b610ffc846323b872dd60e01b8585856040516024016118079392919061442a565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152611d79565b835187901561188b5760006118688684611e08565b92509050806118895760405162461bcd60e51b81526004016104d590614486565b505b600061189f84600001518560800151612152565b90504667ffffffffffffffff16846020015167ffffffffffffffff16141561191b577f0e248ac8be20725176a5f0ab093c5fbb964634d4675012f3d3ad66e69e56d5b7818a8a858b6040516118f8959493929190614496565b60405180910390a1611914878386600001518760c0015161105e565b50506119b9565b611926848a8a61218a565b60a084015134901561193f5761193c8a34613bb8565b90505b600080875111611950578551611952565b8b5b905060006119658483898b898f89612213565b90507fbac7d3515b47f762d5edcc83b041c8ad43133089d06f60e3b8f307a66fcb6221848289602001518f8f8c6101800151886040516119ab97969594939291906144f2565b60405180910390a150505050505b5050505050505050565b6119e28363a9059cbb60e01b848460405160240161180792919061455a565b505050565b60606000825167ffffffffffffffff811115611a0557611a056130f6565b604051908082528060200260200182016040528015611a2e578160200160208202803683370190505b50905060005b8351811015611b20576000848281518110611a5157611a51613fba565b602002602001015160200151611a669061412e565b6001600160e01b0319811660009081526002602052604090205484519192506001600160a01b031690849084908110611aa157611aa1613fba565b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b0316838381518110611ade57611ade613fba565b60200260200101516001600160a01b03161415611b0d5760405162461bcd60e51b81526004016104d5906145a9565b5080611b1881613ff1565b915050611a34565b5092915050565b60606000806000865167ffffffffffffffff811115611b4857611b486130f6565b604051908082528060200260200182016040528015611b71578160200160208202803683370190505b50935060005b8751811015611c65576000868281518110611b9457611b94613fba565b60200260200101516001600160a01b031663358f0e1c8a8481518110611bbc57611bbc613fba565b60200260200101516040518263ffffffff1660e01b8152600401611be09190614215565b606060405180830381865afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c219190614226565b90965094509050611c3281846142f4565b925080868381518110611c4757611c47613fba565b60209081029190910101525080611c5d81613ff1565b915050611b77565b5060005b8451811015611cd15781858281518110611c8557611c85613fba565b602002602001015188611c9891906145b9565b611ca291906145ee565b858281518110611cb457611cb4613fba565b602090810291909101015280611cc981613ff1565b915050611c69565b505093509350939050565b600081846001600160a01b031663dd62ed3e30866040518363ffffffff1660e01b8152600401611d0d929190613c07565b602060405180830381865afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613fd0565b611d5891906142f4565b9050610ffc8463095ea7b360e01b858460405160240161180792919061455a565b6000611dce826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122679092919063ffffffff16565b8051909150156119e25780806020019051810190611dec9190614602565b6119e25760405162461bcd60e51b81526004016104d59061467d565b60008060005b8451811015612149576000806000868481518110611e2e57611e2e613fba565b60200260200101516001600160a01b031663358f0e1c898681518110611e5657611e56613fba565b60200260200101516040518263ffffffff1660e01b8152600401611e7a9190614215565b606060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190614226565b9250925092506000878581518110611ed557611ed5613fba565b60200260200101516001600160a01b0316634c6da2698a8781518110611efd57611efd613fba565b60200260200101516020015186306040518463ffffffff1660e01b8152600401611f299392919061430c565b600060405180830381865afa158015611f46573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f6e9190810190614339565b9050611fa2898681518110611f8557611f85613fba565b6020908102919091010151516001600160a01b0385169086611cdc565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611fd19030906004016130ac565b602060405180830381865afa158015611fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120129190613fd0565b905089868151811061202657612026613fba565b6020026020010151600001516001600160a01b0316826040516120499190614396565b6000604051808303816000865af19150503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b505080985050876120a8576000809750975050505050505061214b565b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906120d79030906004016130ac565b602060405180830381865afa1580156120f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121189190613fd0565b90506121248282613bb8565b61212e90896142f4565b9750505050505050808061214190613ff1565b915050611e0e565b505b9250929050565b60003383468460405160200161216b94939291906146d4565b6040516020818303038152906040528051906020012090505b92915050565b600046846020015184848761010001518860e001516040516020016121b49695949392919061471c565b60405160208183030381529060405280519060200120905060006121d782612280565b90506121e8818661012001516122b0565b428561010001511161220c5760405162461bcd60e51b81526004016104d5906147e0565b5050505050565b6000806122218988886122ec565b905061225a8885878a602001518b608001518c60400151878e60600151600160009054906101000a90046001600160a01b03168c612361565b9998505050505050505050565b606061227684846000856123fa565b90505b9392505050565b60008160405160200161229391906147f0565b604051602081830303815290604052805190602001209050919050565b60006122bc83836124be565b6005549091506001600160a01b038083169116146119e25760405162461bcd60e51b81526004016104d59061485f565b60606040518060c0016040528085815260200183815260200184600001516001600160a01b031681526020018460c00151151581526020018460e001518152602001846101a001511515815250604051602001612349919061495b565b60405160208183030381529060405290509392505050565b60008060006123768d8d8d8d8d8d8c8c6124e2565b88519193509150156123ea57846001600160a01b0316634289fbb3858f8d85878d6040518763ffffffff1660e01b81526004016123b795949392919061498b565b6000604051808303818588803b1580156123d057600080fd5b505af11580156123e4573d6000803e3d6000fd5b50505050505b509b9a5050505050505050505050565b60608247101561241c5760405162461bcd60e51b81526004016104d590614a2c565b6001600160a01b0385163b6124435760405162461bcd60e51b81526004016104d590614a70565b600080866001600160a01b0316858760405161245f9190614396565b60006040518083038185875af1925050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50915091506124b1828286612b29565b925050505b949350505050565b60008060006124cd8585612b62565b915091506124da81612bcf565b509392505050565b60008060018460068111156124f9576124f9613046565b14156125f357826001600160a01b03166382980dc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190614a80565b90506125776001600160a01b038a16828a611cdc565b60405163a5977fbb60e01b81526001600160a01b0382169063a5977fbb906125ad908d908d908d908d908d908d90600401614aad565b600060405180830381600087803b1580156125c757600080fd5b505af11580156125db573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cb4565b9150612b1c565b600284600681111561260757612607613046565b14156126f857826001600160a01b031663d8257d176040518163ffffffff1660e01b8152600401602060405180830381865afa15801561264b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266f9190614a80565b90506126856001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016126b9959493929190614afc565b600060405180830381600087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cf4565b600384600681111561270c5761270c613046565b141561281057826001600160a01b031663dfa2dbaf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127749190614a80565b905061278a6001600160a01b038a16828a611cdc565b604051636f3c863f60e11b81526001600160a01b0382169063de790c7e906127bc908c908c908f908c90600401614b3e565b600060405180830381600087803b1580156127d657600080fd5b505af11580156127ea573d6000803e3d6000fd5b50612804925050506001600160a01b038a16826000612d13565b6125ec8a8a8a89612dc7565b600484600681111561282457612824613046565b141561291957826001600160a01b031663c66a9c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288c9190614a80565b90506128a26001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016128d6959493929190614afc565b6020604051808303816000875af11580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190613fd0565b600584600681111561292d5761292d613046565b1415612a3e57826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129959190614a80565b90506129ab6001600160a01b038a16828a611cdc565b806001600160a01b031663a00293018a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b6020604051808303816000875af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190613fd0565b9150612a396001600160a01b038a16826000612d13565b612b1c565b6006846006811115612a5257612a52613046565b1415612b0457826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aba9190614a80565b9050612ad06001600160a01b038a16828a611cdc565b806001600160a01b0316639e422c338a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b60405162461bcd60e51b81526004016104d590614ba7565b9850989650505050505050565b60608315612b38575081612279565b825115612b485782518084602001fd5b8160405162461bcd60e51b81526004016104d59190614bb7565b600080825160411415612b995760208301516040840151606085015160001a612b8d87828585612e04565b9450945050505061214b565b825160401415612bc35760208301516040840151612bb8868383612ee4565b93509350505061214b565b5060009050600261214b565b6000816004811115612be357612be3613046565b1415612bec5750565b6001816004811115612c0057612c00613046565b1415612c1e5760405162461bcd60e51b81526004016104d590614bfc565b6002816004811115612c3257612c32613046565b1415612c505760405162461bcd60e51b81526004016104d590614c40565b6003816004811115612c6457612c64613046565b1415612c825760405162461bcd60e51b81526004016104d590614c8f565b6004816004811115612c9657612c96613046565b141561105b5760405162461bcd60e51b81526004016104d590614cde565b600030868686868646604051602001612cd39796959493929190614cee565b60405160208183030381529060405280519060200120905095945050505050565b600030858585898646604051602001612cd39796959493929190614d69565b801580612d8c5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612d499030908690600401613c07565b602060405180830381865afa158015612d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8a9190613fd0565b155b612da85760405162461bcd60e51b81526004016104d590614e1f565b6119e28363095ea7b360e01b848460405160240161180792919061455a565b6000308484878546604051602001612de496959493929190614e2f565b604051602081830303815290604052805190602001209050949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e3b5750600090506003612edb565b8460ff16601b14158015612e5357508460ff16601c14155b15612e645750600090506004612edb565b600060018787878760405160008152602001604052604051612e899493929190614ea2565b6020604051602081039080840390855afa158015612eab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ed457600060019250925050612edb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681612f1a60ff86901c601b6142f4565b9050612f2887828885612e04565b935093505050935093915050565b60006001600160a01b038216612184565b612f5081612f36565b811461105b57600080fd5b803561218481612f47565b80612f50565b803561218481612f66565b60008083601f840112612f8c57612f8c600080fd5b50813567ffffffffffffffff811115612fa757612fa7600080fd5b60208301915083600182028301111561214b5761214b600080fd5b600080600080600060808688031215612fdd57612fdd600080fd5b6000612fe98888612f5b565b9550506020612ffa88828901612f6c565b945050604086013567ffffffffffffffff81111561301a5761301a600080fd5b61302688828901612f77565b9350935050606061303988828901612f5b565b9150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6003811061105b5761105b613046565b806130768161305c565b919050565b60006121848261306c565b61308f8161307b565b82525050565b602081016121848284613086565b61308f81612f36565b6020810161218482846130a3565b6000602082840312156130cf576130cf600080fd5b60006124b68484612f5b565b67ffffffffffffffff8116612f50565b8035612184816130db565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613132576131326130f6565b6040525050565b600061314460405190565b9050613076828261310c565b600067ffffffffffffffff82111561316a5761316a6130f6565b601f19601f83011660200192915050565b82818337506000910152565b600061319a61319584613150565b613139565b9050828152602081018484840111156131b5576131b5600080fd5b6124da84828561317b565b600082601f8301126131d4576131d4600080fd5b81356124b6848260208601613187565b60008060008060008060c0878903121561320057613200600080fd5b600061320c8989612f5b565b965050602061321d89828a01612f5b565b955050604061322e89828a01612f6c565b945050606061323f89828a016130eb565b935050608087013567ffffffffffffffff81111561325f5761325f600080fd5b61326b89828a016131c0565b92505060a061327c89828a01612f5b565b9150509295509295509295565b6001600160e01b03198116612f50565b803561218481613289565b801515612f50565b8035612184816132a4565b6000806000606084860312156132cf576132cf600080fd5b60006132db8686612f5b565b93505060206132ec86828701613299565b92505060406132fd868287016132ac565b9150509250925092565b60006020828403121561331c5761331c600080fd5b60006124b68484612f6c565b6000806040838503121561333e5761333e600080fd5b600061334a8585612f5b565b925050602061335b85828601613299565b9150509250929050565b80151561308f565b602081016121848284613365565b60008060008060006080868803121561339657613396600080fd5b60006133a28888612f5b565b9550506020612ffa888289016130eb565b6000806000604084860312156133cb576133cb600080fd5b833567ffffffffffffffff8111156133e5576133e5600080fd5b6133f186828701612f77565b935093505060206132fd86828701612f5b565b60006101c0828403121561341a5761341a600080fd5b50919050565b60008083601f84011261343557613435600080fd5b50813567ffffffffffffffff81111561345057613450600080fd5b60208301915083602082028301111561214b5761214b600080fd5b6000806000806000806080878903121561348757613487600080fd5b60006134938989612f5b565b965050602087013567ffffffffffffffff8111156134b3576134b3600080fd5b6134bf89828a01613404565b955050604087013567ffffffffffffffff8111156134df576134df600080fd5b6134eb89828a01613420565b9450945050606087013567ffffffffffffffff81111561350d5761350d600080fd5b61351989828a01613420565b92509250509295509295509295565b60008060006040848603121561354057613540600080fd5b833567ffffffffffffffff81111561355a5761355a600080fd5b6133f186828701613420565b60006020828403121561357b5761357b600080fd5b60006124b68484613299565b60006121846001600160a01b03831661359e565b90565b6001600160a01b031690565b600061218482613587565b6000612184826135aa565b61308f816135b5565b6020810161218482846135c0565b601981526000602082017f63616c6c6572206973206e6f74206d6573736167652062757300000000000000815291505b5060200190565b60208082528101612184816135d7565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150613607565b602080825281016121848161361e565b600067ffffffffffffffff82111561367c5761367c6130f6565b5060209081020190565b60006040828403121561369b5761369b600080fd5b6136a56040613139565b905060006136b38484612f5b565b825250602082013567ffffffffffffffff8111156136d3576136d3600080fd5b6136df848285016131c0565b60208301525092915050565b60006136f961319584613662565b8381529050602080820190840283018581111561371857613718600080fd5b835b8181101561375957803567ffffffffffffffff81111561373c5761373c600080fd5b8086016137498982613686565b855250506020928301920161371a565b5050509392505050565b600082601f83011261377757613777600080fd5b81356124b68482602086016136eb565b600060c0828403121561379c5761379c600080fd5b6137a660c0613139565b905060006137b48484612f6c565b825250602082013567ffffffffffffffff8111156137d4576137d4600080fd5b6137e084828501613763565b60208301525060406137f484828501612f5b565b6040830152506060613808848285016132ac565b606083015250608061381c84828501612f6c565b60808301525060a0613830848285016132ac565b60a08301525092915050565b60006020828403121561385157613851600080fd5b813567ffffffffffffffff81111561386b5761386b600080fd5b6124b684828501613787565b8061308f565b600061218461359b8381565b61308f8161387d565b60c081016138a08289613877565b6138ad6020830188613889565b6138ba6040830187613877565b6138c760608301866130a3565b6138d46080830185613877565b6138e160a0830184613086565b979650505050505050565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613607565b60208082528101612184816138ec565b805161218481612f66565b805161218481612f47565b60005b8381101561395f578181015183820152602001613947565b83811115610ffc5750506000910152565b600061397e61319584613150565b90508281526020810184848401111561399957613999600080fd5b6124da848285613944565b600082601f8301126139b8576139b8600080fd5b81516124b6848260208601613970565b6000604082840312156139dd576139dd600080fd5b6139e76040613139565b905060006139f58484613939565b825250602082015167ffffffffffffffff811115613a1557613a15600080fd5b6136df848285016139a4565b6000613a2f61319584613662565b83815290506020808201908402830185811115613a4e57613a4e600080fd5b835b8181101561375957805167ffffffffffffffff811115613a7257613a72600080fd5b808601613a7f89826139c8565b8552505060209283019201613a50565b600082601f830112613aa357613aa3600080fd5b81516124b6848260208601613a21565b8051612184816132a4565b600060c08284031215613ad357613ad3600080fd5b613add60c0613139565b90506000613aeb848461392e565b825250602082015167ffffffffffffffff811115613b0b57613b0b600080fd5b613b1784828501613a8f565b6020830152506040613b2b84828501613939565b6040830152506060613b3f84828501613ab3565b6060830152506080613b538482850161392e565b60808301525060a061383084828501613ab3565b600060208284031215613b7c57613b7c600080fd5b815167ffffffffffffffff811115613b9657613b96600080fd5b6124b684828501613abe565b634e487b7160e01b600052601160045260246000fd5b600082821015613bca57613bca613ba2565b500390565b6001600160e01b0319811661308f565b60608101613bed82866130a3565b613bfa6020830185613bcf565b6124b66040830184613365565b60408101613c1582856130a3565b61227960208301846130a3565b60c08101613c308289613877565b613c3d6020830188613889565b6138ba6040830187613889565b600781526000602082017f746b696e206d6d0000000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481613c4a565b60c08101613c9c8289613877565b6138ad6020830188613877565b6000613cb683858461317b565b50500190565b60006124b6828486613ca9565b60408101613c158285613bcf565b600060208284031215613cec57613cec600080fd5b60006124b684846130eb565b600381526000602082016206e6f760ec1b81529150613607565b6020808252810161218481613cf8565b60006122793684846136eb565b600060208284031215613d4457613d44600080fd5b60006124b684846132ac565b601281526000602082017f746b696e206e6f206e617469766557726170000000000000000000000000000081529150613607565b6020808252810161218481613d50565b600b81526000602082017f696e7366636e7420616d7400000000000000000000000000000000000000000081529150613607565b6020808252810161218481613d94565b63ffffffff8116612f50565b803561218481613dd8565b6007811061105b57600080fd5b803561218481613def565b60006101c08284031215613e1d57613e1d600080fd5b613e286101c0613139565b90506000613e368484612f5b565b8252506020613e47848483016130eb565b6020830152506040613e5b84828501613de4565b6040830152506060613e6f84828501613dfc565b6060830152506080613e83848285016130eb565b60808301525060a0613e97848285016132ac565b60a08301525060c0613eab848285016132ac565b60c08301525060e0613ebf84828501612f6c565b60e083015250610100613ed484828501612f6c565b6101008301525061012082013567ffffffffffffffff811115613ef957613ef9600080fd5b613f05848285016131c0565b61012083015250610140613f1b84828501612f6c565b61014083015250610160613f3184828501612f5b565b61016083015250610180613f4784828501612f5b565b610180830152506101a0613f5d848285016132ac565b6101a08301525092915050565b60006121843683613e07565b601181526000602082017f6e6f742066656520636f6c6c6563746f7200000000000000000000000000000081529150613607565b6020808252810161218481613f76565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613fe557613fe5600080fd5b60006124b6848461392e565b600060001982141561400557614005613ba2565b5060010190565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015291505b5060400190565b602080825281016121848161400c565b600c81526000602082017f746b206e6f206e6174697665000000000000000000000000000000000000000081529150613607565b6020808252810161218481614079565b602081016121848284613877565b60006121848261359b565b600981526000602082017f73656e64206661696c000000000000000000000000000000000000000000000081529150613607565b60208082528101612184816140d6565b600061218482516001600160e01b03191690565b6000614138825190565b602083016141458161411a565b9250600482101561416c576141676001600160e01b0319836004036008021b90565b831692505b5050919050565b600f81526000602082017f756e737570706f7274656420646578000000000000000000000000000000000081529150613607565b6020808252810161218481614173565b60006141c1825190565b8084526020840193506141d8818560208601613944565b601f01601f19169290920192915050565b805160009060408401906141fd85826130a3565b5060208301518482036020860152610add82826141b7565b6020808252810161227981846141e9565b60008060006060848603121561423e5761423e600080fd5b600061424a868661392e565b935050602061425b86828701613939565b92505060406132fd86828701613939565b600d81526000602082017f746b696e206d69736d617463680000000000000000000000000000000000000081529150613607565b602080825281016121848161426c565b600c81526000602082017f746b6f206d69736d61746368000000000000000000000000000000000000000081529150613607565b60208082528101612184816142b0565b6000821982111561430757614307613ba2565b500190565b6060808252810161431d81866141b7565b905061432c6020830185613877565b6124b660408301846130a3565b60006020828403121561434e5761434e600080fd5b815167ffffffffffffffff81111561436857614368600080fd5b6124b6848285016139a4565b600061437e825190565b61438c818560208601613944565b9290920192915050565b60006122798284614374565b600b81526000602082017f73776170206661696c656400000000000000000000000000000000000000000081529150613607565b60208082528101612184816143a2565b601081526000602082017f616c6c207377617073206661696c65640000000000000000000000000000000081529150613607565b60208082528101612184816143e6565b6060810161443882866130a3565b61444560208301856130a3565b6124b66040830184613877565b600981526000602082017f73776170206661696c000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481614452565b60a081016144a48288613877565b6144b16020830187613877565b6144be60408301866130a3565b6144cb6060830185613877565b6144d860808301846130a3565b9695505050505050565b67ffffffffffffffff811661308f565b60e08101614500828a613877565b61450d6020830189613877565b61451a60408301886144e2565b6145276060830187613877565b61453460808301866130a3565b61454160a08301856130a3565b61454e60c08301846130a3565b98975050505050505050565b6040810161456882856130a3565b6122796020830184613877565b600c81526000602082017f636463206e6f20666f756e64000000000000000000000000000000000000000081529150613607565b6020808252810161218481614575565b60008160001904831182151516156145d3576145d3613ba2565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145fd576145fd6145d8565b500490565b60006020828403121561461757614617600080fd5b60006124b68484613ab3565b602a81526000602082017f5361666545524332303a204552433230206f7065726174696f6e20646964206e81527f6f7420737563636565640000000000000000000000000000000000000000000060208201529150614062565b6020808252810161218481614623565b60006121848260601b90565b60006121848261468d565b61308f6146b082612f36565b614699565b60006121848260c01b90565b61308f67ffffffffffffffff82166146b5565b60006146e082876146a4565b6014820191506146f082866146a4565b60148201915061470082856146c1565b60088201915061471082846146c1565b50600801949350505050565b7f6578656375746f722066656500000000000000000000000000000000000000008152600c01600061474e82896146c1565b60088201915061475e82886146c1565b60088201915061476e8287613877565b60208201915061477e82866146a4565b60148201915061478e8285613877565b60208201915061479e8284613877565b506020019695505050505050565b601181526000602082017f646561646c696e6520657863656564656400000000000000000000000000000081529150613607565b60208082528101612184816147ac565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0160006148228284613877565b50602001919050565b600e81526000602082017f696e76616c6964207369676e657200000000000000000000000000000000000081529150613607565b602080825281016121848161482b565b600061227983836141e9565b6000614885825190565b8084526020840193508360208202850161489f8560200190565b8060005b858110156148d457848403895281516148bc858261486f565b94506020830160209a909a01999250506001016148a3565b5091979650505050505050565b805160009060c08401906148f58582613877565b506020830151848203602086015261490d828261487b565b915050604083015161492260408601826130a3565b5060608301516149356060860182613365565b5060808301516149486080860182613877565b5060a08301516124da60a0860182613365565b6020808252810161227981846148e1565b600061218461359b67ffffffffffffffff841681565b61308f8161496c565b60a0810161499982886130a3565b6149a66020830187614982565b6149b360408301866130a3565b6149c06060830185613877565b81810360808301526138e181846141b7565b602681526000602082017f416464726573733a20696e73756666696369656e742062616c616e636520666f81527f722063616c6c000000000000000000000000000000000000000000000000000060208201529150614062565b60208082528101612184816149d2565b601d81526000602082017f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081529150613607565b6020808252810161218481614a3c565b600060208284031215614a9557614a95600080fd5b60006124b68484613939565b63ffffffff811661308f565b60c08101614abb82896130a3565b614ac860208301886130a3565b614ad56040830187613877565b614ae260608301866144e2565b614aef60808301856144e2565b6138e160a0830184614aa1565b60a08101614b0a82886130a3565b614b176020830187613877565b614b2460408301866144e2565b614b3160608301856130a3565b6144d860808301846144e2565b60808101614b4c82876130a3565b614b596020830186613877565b614b6660408301856130a3565b610add60608301846144e2565b601981526000602082017f6272696467652074797065206e6f7420737570706f727465640000000000000081529150613607565b6020808252810161218481614b73565b6020808252810161227981846141b7565b601881526000602082017f45434453413a20696e76616c6964207369676e6174757265000000000000000081529150613607565b6020808252810161218481614bc8565b601f81526000602082017f45434453413a20696e76616c6964207369676e6174757265206c656e6774680081529150613607565b6020808252810161218481614c0c565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c50565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c9f565b6000614cfa828a6146a4565b601482019150614d0a82896146a4565b601482019150614d1a82886146a4565b601482019150614d2a8287613877565b602082019150614d3a82866146c1565b600882019150614d4a82856146c1565b600882019150614d5a82846146c1565b50600801979650505050505050565b6000614d75828a6146a4565b601482019150614d8582896146a4565b601482019150614d958288613877565b602082019150614da582876146c1565b600882019150614db582866146a4565b601482019150614d4a82856146c1565b603681526000602082017f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060208201529150614062565b6020808252810161218481614dc5565b6000614e3b82896146a4565b601482019150614e4b82886146a4565b601482019150614e5b8287613877565b602082019150614e6b82866146a4565b601482019150614e7b82856146c1565b600882019150614e8b82846146c1565b506008019695505050505050565b60ff811661308f565b60808101614eb08287613877565b614ebd6020830186614e99565b614eca6040830185613877565b610add606083018461387756fea2646970667358221220eae1c3b25d0ff199671cc0ccdeb5ab9d13b1454bc5f6ee971c30f3211cf9448d64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000d71d18126e03646eb09fec929e2ae87b7cae69d000000000000000000000000420000000000000000000000000000000000000600000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d8000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e743235362929000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000db7e4d4dd546a6df6f9a312761e1b63c2036a7820000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000
-----Decoded View---------------
Arg [0] : _messageBus (address): 0x0D71D18126E03646eb09FEc929e2ae87b7CAE69d
Arg [1] : _nativeWrap (address): 0x4200000000000000000000000000000000000006
Arg [2] : _signer (address): 0x26e6eAf3D3C5d4B8290AA7dd896140f383dFf043
Arg [3] : _feeCollector (address): 0xf0761BB438CeFca39A8fd1F27d75ccC7F6Df92d8
Arg [4] : _funcSigs (string[]): exactInput((bytes,address,uint256,uint256,uint256))
Arg [5] : _codecs (address[]): 0xdB7E4d4dd546a6Df6F9a312761e1B63C2036a782
Arg [6] : _supportedDexList (address[]): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [7] : _supportedDexFuncs (string[]): exactInput((bytes,address,uint256,uint256,uint256))
-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 0000000000000000000000000d71d18126e03646eb09fec929e2ae87b7cae69d
Arg [1] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [2] : 00000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043
Arg [3] : 000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d8
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [5] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [6] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000033
Arg [11] : 6578616374496e707574282862797465732c616464726573732c75696e743235
Arg [12] : 362c75696e743235362c75696e74323536292900000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 000000000000000000000000db7e4d4dd546a6df6f9a312761e1b63c2036a782
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [16] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000033
Arg [20] : 6578616374496e707574282862797465732c616464726573732c75696e743235
Arg [21] : 362c75696e743235362c75696e74323536292900000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.