Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0.00111 ETH
Eth Value
$4.40 (@ $3,966.98/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 194 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer With Sw... | 14914623 | 923 days ago | IN | 2.5407814 ETH | 0.00732764 | ||||
Transfer With Sw... | 14914597 | 923 days ago | IN | 0.2750534 ETH | 0.00529362 | ||||
Transfer With Sw... | 14914588 | 923 days ago | IN | 0.2700534 ETH | 0.00502544 | ||||
Transfer With Sw... | 14914527 | 923 days ago | IN | 0.1001206 ETH | 0.01555307 | ||||
Transfer With Sw... | 14914255 | 923 days ago | IN | 0.10388564 ETH | 0.00402917 | ||||
Transfer With Sw... | 14914065 | 923 days ago | IN | 0.0201158 ETH | 0.01453723 | ||||
Transfer With Sw... | 14913999 | 923 days ago | IN | 0.0324564 ETH | 0.00637159 | ||||
Transfer With Sw... | 14913860 | 923 days ago | IN | 0.0768354 ETH | 0.00671023 | ||||
Transfer With Sw... | 14913825 | 923 days ago | IN | 0.0001206 ETH | 0.00716417 | ||||
Transfer With Sw... | 14913776 | 923 days ago | IN | 0.0581158 ETH | 0.00798577 | ||||
Transfer With Sw... | 14913705 | 923 days ago | IN | 0.0000534 ETH | 0.01093171 | ||||
Transfer With Sw... | 14913662 | 923 days ago | IN | 0.1500534 ETH | 0.00626377 | ||||
Transfer With Sw... | 14913662 | 923 days ago | IN | 0.0300534 ETH | 0.00626377 | ||||
Transfer With Sw... | 14913592 | 923 days ago | IN | 0.0894324 ETH | 0.00796597 | ||||
Transfer With Sw... | 14913558 | 923 days ago | IN | 0.0100534 ETH | 0.00821508 | ||||
Transfer With Sw... | 14913535 | 923 days ago | IN | 0.1074024 ETH | 0.01030991 | ||||
Transfer With Sw... | 14913478 | 923 days ago | IN | 0.0130839 ETH | 0.00486524 | ||||
Transfer With Sw... | 14913275 | 923 days ago | IN | 1.3920534 ETH | 0.00439411 | ||||
Transfer With Sw... | 14913272 | 923 days ago | IN | 1.4000534 ETH | 0.00501521 | ||||
Transfer With Sw... | 14913258 | 923 days ago | IN | 0.0200534 ETH | 0.0059881 | ||||
Transfer With Sw... | 14913251 | 923 days ago | IN | 0.0300534 ETH | 0.00282159 | ||||
Transfer With Sw... | 14913104 | 923 days ago | IN | 0.5000534 ETH | 0.01043221 | ||||
Transfer With Sw... | 14913057 | 923 days ago | IN | 0.5000966 ETH | 0.00782422 | ||||
Transfer With Sw... | 14913013 | 923 days ago | IN | 0.2300534 ETH | 0.00490855 | ||||
Transfer With Sw... | 14912943 | 923 days ago | IN | 2.9000534 ETH | 0.00515849 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
14914673 | 923 days ago | 0.24819315 ETH | ||||
14914673 | 923 days ago | 0.24819315 ETH | ||||
14914623 | 923 days ago | 0.0000534 ETH | ||||
14914623 | 923 days ago | 2.540728 ETH | ||||
14914597 | 923 days ago | 0.0000534 ETH | ||||
14914597 | 923 days ago | 0.275 ETH | ||||
14914588 | 923 days ago | 0.0000534 ETH | ||||
14914588 | 923 days ago | 0.27 ETH | ||||
14914527 | 923 days ago | 0.0001206 ETH | ||||
14914527 | 923 days ago | 0.1 ETH | ||||
14914255 | 923 days ago | 0.0000534 ETH | ||||
14914255 | 923 days ago | 0.10383224 ETH | ||||
14914065 | 923 days ago | 0.0001158 ETH | ||||
14914065 | 923 days ago | 0.02 ETH | ||||
14913999 | 923 days ago | 0.0000534 ETH | ||||
14913999 | 923 days ago | 0.032403 ETH | ||||
14913860 | 923 days ago | 0.0001254 ETH | ||||
14913860 | 923 days ago | 0.07671 ETH | ||||
14913825 | 923 days ago | 0.0001206 ETH | ||||
14913776 | 923 days ago | 0.058 ETH | ||||
14913705 | 923 days ago | 0.0000534 ETH | ||||
14913662 | 923 days ago | 0.0000534 ETH | ||||
14913662 | 923 days ago | 0.15 ETH | ||||
14913662 | 923 days ago | 0.0000534 ETH | ||||
14913662 | 923 days ago | 0.03 ETH |
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
[{"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
60806040523480156200001157600080fd5b50604051620056f5380380620056f58339810160408190526200003491620005fa565b848685858585818185856200004933620001d5565b8051825114620000765760405162461bcd60e51b81526004016200006d906200074f565b60405180910390fd5b60005b8251811015620000ef5760008382815181106200009a576200009a62000761565b6020026020010151805190602001209050620000d981848481518110620000c557620000c562000761565b60200260200101516200022560201b60201c565b5080620000e6816200078d565b91505062000079565b50505060005b82518110156200016d57600082828151811062000116576200011662000761565b60200260200101518051906020012090506200015784838151811062000140576200014062000761565b60200260200101518260016200029760201b60201c565b508062000164816200078d565b915050620000f5565b5050600580546001600160a01b03199081166001600160a01b039889161790915560068054821698881698909817909755505060016007819055805486169d85169d909d17909c5550506008805490921698169790971790965550620007d895505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff168015158215151415620002ef5760405162461bcd60e51b81526004016200006d90620007c6565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b60006001600160a01b0382165b92915050565b6200034f8162000331565b81146200035b57600080fd5b50565b80516200033e8162000344565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715620003a957620003a96200036b565b6040525050565b6000620003bc60405190565b9050620003ca828262000381565b919050565b60006001600160401b03821115620003eb57620003eb6200036b565b5060209081020190565b60006001600160401b038211156200041157620004116200036b565b601f19601f83011660200192915050565b60005b838110156200043f57818101518382015260200162000425565b838111156200044f576000848401525b50505050565b60006200046c6200046684620003f5565b620003b0565b905082815260208101848484011115620004895762000489600080fd5b6200049684828562000422565b509392505050565b600082601f830112620004b457620004b4600080fd5b8151620004c684826020860162000455565b949350505050565b6000620004df6200046684620003cf565b83815290506020808201908402830185811115620005005762000500600080fd5b835b81811015620005465780516001600160401b03811115620005265762000526600080fd5b8086016200053589826200049e565b855250506020928301920162000502565b5050509392505050565b600082601f830112620005665762000566600080fd5b8151620004c6848260208601620004ce565b6000620005896200046684620003cf565b83815290506020808201908402830185811115620005aa57620005aa600080fd5b835b81811015620005465780620005c288826200035e565b84525060209283019201620005ac565b600082601f830112620005e857620005e8600080fd5b8151620004c684826020860162000578565b600080600080600080600080610100898b0312156200061c576200061c600080fd5b60006200062a8b8b6200035e565b98505060206200063d8b828c016200035e565b9750506040620006508b828c016200035e565b9650506060620006638b828c016200035e565b95505060808901516001600160401b03811115620006845762000684600080fd5b620006928b828c0162000550565b94505060a08901516001600160401b03811115620006b357620006b3600080fd5b620006c18b828c01620005d2565b93505060c08901516001600160401b03811115620006e257620006e2600080fd5b620006f08b828c01620005d2565b92505060e08901516001600160401b03811115620007115762000711600080fd5b6200071f8b828c0162000550565b9150509295985092959890939650565b60068152600060208201656c656e206d6d60d01b815291505b5060200190565b602080825281016200033e816200072f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620007a457620007a462000777565b5060010190565b600381526000602082016206e6f760ec1b8152915062000748565b602080825281016200033e81620007ab565b614f0d80620007e86000396000f3fe6080604052600436106101845760003560e01c80638da5cb5b116100d6578063c415b95c1161007f578063efcfd8f511610059578063efcfd8f514610425578063f2fde38b14610445578063fbf5d7631461046557600080fd5b8063c415b95c146103d2578063c5bccca3146103f2578063d8318ae51461041257600080fd5b8063a1a227fa116100b0578063a1a227fa1461035c578063a1c9d41e1461037c578063a42dce80146103b257600080fd5b80638da5cb5b146102e357806391ec04b5146103015780639c649fdf1461034957600080fd5b80635b5a66a711610138578063715018a611610112578063715018a61461029b5780637cd2bffc146102b057806382665a8f146102c357600080fd5b80635b5a66a71461023b578063675df7591461025b5780636c19e7831461027b57600080fd5b8063457bfa2f11610169578063457bfa2f146101e6578063547cad12146102065780635ab7afc61461022857600080fd5b80630bcb498214610190578063238ac933146101b957600080fd5b3661018b57005b600080fd5b6101a361019e366004612fc2565b6104a8565b6040516101b09190613095565b60405180910390f35b3480156101c557600080fd5b506005546101d9906001600160a01b031681565b6040516101b091906130ac565b3480156101f257600080fd5b506008546101d9906001600160a01b031681565b34801561021257600080fd5b506102266102213660046130ba565b610585565b005b6101a36102363660046131e4565b610606565b34801561024757600080fd5b506102266102563660046130ba565b6106fb565b34801561026757600080fd5b506102266102763660046132b7565b610770565b34801561028757600080fd5b506102266102963660046130ba565b6107e5565b3480156102a757600080fd5b5061022661086e565b6101a36102be3660046131e4565b6108a4565b3480156102cf57600080fd5b506101d96102de366004613307565b610a86565b3480156102ef57600080fd5b506000546001600160a01b03166101d9565b34801561030d57600080fd5b5061033c61031c366004613328565b600460209081526000928352604080842090915290825290205460ff1681565b6040516101b0919061336d565b6101a361035736600461337b565b610ab0565b34801561036857600080fd5b506001546101d9906001600160a01b031681565b34801561038857600080fd5b506101d9610397366004613307565b6009602052600090815260409020546001600160a01b031681565b3480156103be57600080fd5b506102266103cd3660046130ba565b610ae6565b3480156103de57600080fd5b506006546101d9906001600160a01b031681565b3480156103fe57600080fd5b5061022661040d3660046133b3565b610b63565b61022661042036600461346b565b610c5f565b34801561043157600080fd5b50610226610440366004613528565b610ee1565b34801561045157600080fd5b506102266104603660046130ba565b611002565b34801561047157600080fd5b5061049b610480366004613566565b6002602052600090815260409020546001600160a01b031681565b6040516101b091906135c9565b6001546000906001600160a01b031633146104de5760405162461bcd60e51b81526004016104d59061360e565b60405180910390fd5b600260075414156105015760405162461bcd60e51b81526004016104d590613652565b600260075560006105148486018661383c565b905061052787878360400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24581600001516000888a8560800151600260405161056a96959493929190613892565b60405180910390a16001915050600160075595945050505050565b6000546001600160a01b031633146105af5760405162461bcd60e51b81526004016104d59061391e565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f3f8223bcd8b3b875473e9f9e14e1ad075451a2b5ffd31591655da9a01516bf5e916105fb916130ac565b60405180910390a150565b6001546000906001600160a01b031633146106335760405162461bcd60e51b81526004016104d59061360e565b600260075414156106565760405162461bcd60e51b81526004016104d590613652565b600260075582516000906106739085016020908101908601613b67565b905060008160800151876106879190613bb8565b905061069a88828460400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24582600001516000838b866080015160026040516106dd96959493929190613892565b60405180910390a16001925050505b60016007559695505050505050565b6000546001600160a01b031633146107255760405162461bcd60e51b81526004016104d59061391e565b600880546001600160a01b0319166001600160a01b0383161790556040517fb878cd71628ac64b2df1872301925e01164824535b02e8601077749eeeb88c3d906105fb9083906130ac565b6000546001600160a01b0316331461079a5760405162461bcd60e51b81526004016104d59061391e565b6107a583838361118e565b7f5e20184b00709d9f103306958e9fb9d509f78bec1829ca7080f2c43eb2ff21a88383836040516107d893929190613bdf565b60405180910390a1505050565b6000546001600160a01b0316331461080f5760405162461bcd60e51b81526004016104d59061391e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb906108629083908590613c07565b60405180910390a15050565b6000546001600160a01b031633146108985760405162461bcd60e51b81526004016104d59061391e565b6108a26000611225565b565b6001546000906001600160a01b031633146108d15760405162461bcd60e51b81526004016104d59061360e565b600260075414156108f45760405162461bcd60e51b81526004016104d590613652565b600260075582516000906109119085016020908101908601613b67565b90508060800151861015610974576080810186905280516040517f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245916109629160009081908c908c90600190613c22565b60405180910390a160019150506106ec565b60808101516109839087613bb8565b955060608101516020820151518891908890600090156109fd57606060006109ae8760200151611275565b90985093509150506001600160a01b03808216908e16146109e15760405162461bcd60e51b81526004016104d590613c7e565b6109f58760200151838e8a60a001516114a3565b909450925050505b8015610a1457610a148b828760400151600061105e565b610a24848387604001518661105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245856000015183838e89608001516001604051610a6696959493929190613c8e565b60405180910390a160019550505050505060016007559695505050505050565b60038181548110610a9657600080fd5b6000918252602090912001546001600160a01b0316905081565b6001546000906001600160a01b03163314610add5760405162461bcd60e51b81526004016104d59061360e565b95945050505050565b6000546001600160a01b03163314610b105760405162461bcd60e51b81526004016104d59061391e565b600680546001600160a01b038381166001600160a01b03198316179092556040519116907f5d16ad41baeb009cd23eb8f6c7cde5c2e0cd5acf4a33926ab488875c37c37f38906108629083908590613c07565b6000546001600160a01b03163314610b8d5760405162461bcd60e51b81526004016104d59061391e565b60008383604051610b9f929190613cbc565b60405180910390209050610c2081836001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b7f58ddcdb40971f55ad1b6a8a28067274a4ffc7e9d77c3ea14a17652faa705e1978183604051610c51929190613cc9565b60405180910390a150505050565b60026007541415610c825760405162461bcd60e51b81526004016104d590613652565b600260075582151580610cb8575067ffffffffffffffff4616610cab6040870160208801613cd7565b67ffffffffffffffff1614155b610cd45760405162461bcd60e51b81526004016104d590613d12565b82151580610d0c575061014085013515801590610d0c57506000610d00610180870161016088016130ba565b6001600160a01b031614155b610d285760405162461bcd60e51b81526004016104d590613d12565b6101408501356000610d42610180880161016089016130ba565b90506000610d5861018089016101608a016130ba565b905060608615610dc057610d74610d6f888a613d22565b611275565b92965090945092509050610d906101808a016101608b016130ba565b6001600160a01b0316836001600160a01b031614610dc05760405162461bcd60e51b81526004016104d590613c7e565b610dd060c08a0160a08b01613d2f565b15610e90576008546001600160a01b03848116911614610e025760405162461bcd60e51b81526004016104d590613d84565b83341015610e225760405162461bcd60e51b81526004016104d590613dc8565b600860009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b5050505050610ea5565b610ea56001600160a01b0384163330876117e6565b610ed08a858585610eb68c8e613d22565b610ec08b8d613d22565b8f610eca90613f6a565b88611853565b505060016007555050505050505050565b6006546001600160a01b03163314610f0b5760405162461bcd60e51b81526004016104d590613faa565b60005b82811015610ffc576000848483818110610f2a57610f2a613fba565b9050602002016020810190610f3f91906130ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f6a91906130ac565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190613fd0565b9050610fe98382878786818110610fc457610fc4613fba565b9050602002016020810190610fd991906130ba565b6001600160a01b031691906119c3565b5080610ff481613ff1565b915050610f0e565b50505050565b6000546001600160a01b0316331461102c5760405162461bcd60e51b81526004016104d59061391e565b6001600160a01b0381166110525760405162461bcd60e51b81526004016104d590614069565b61105b81611225565b50565b801561117a576008546001600160a01b038581169116146110915760405162461bcd60e51b81526004016104d5906140ad565b600854604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906110c19086906004016140bd565b600060405180830381600087803b1580156110db57600080fd5b505af11580156110ef573d6000803e3d6000fd5b505050506000826001600160a01b03168461c35090604051611110906140cb565b600060405180830381858888f193505050503d806000811461114e576040519150601f19603f3d011682016040523d82523d6000602084013e611153565b606091505b50509050806111745760405162461bcd60e51b81526004016104d59061410a565b50610ffc565b610ffc6001600160a01b03851683856119c3565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff1680151582151514156111e35760405162461bcd60e51b81526004016104d590613d12565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060006060600080611288876119e7565b925060005b875181101561149957600460008983815181106112ac576112ac613fba565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008983815181106112ec576112ec613fba565b6020026020010151602001516113019061412e565b6001600160e01b031916815260208101919091526040016000205460ff1661133b5760405162461bcd60e51b81526004016104d5906141a7565b600080600086848151811061135257611352613fba565b60200260200101516001600160a01b031663358f0e1c8c868151811061137a5761137a613fba565b60200260200101516040518263ffffffff1660e01b815260040161139e9190614215565b606060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190614226565b919450925090506001600160a01b038616158061140d5750816001600160a01b0316866001600160a01b0316145b6114295760405162461bcd60e51b81526004016104d5906142a0565b90945084906001600160a01b03851615806114555750806001600160a01b0316856001600160a01b0316145b6114715760405162461bcd60e51b81526004016104d5906142e4565b93508361147e838b6142f4565b9950909750955081905061149181613ff1565b91505061128d565b5050509193509193565b60008060008060006114b689888a611b27565b9250925092506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114ea91906130ac565b602060405180830381865afa158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190613fd0565b905060005b8a518110156117395760008a828151811061154d5761154d613fba565b60200260200101516001600160a01b0316634c6da2698d848151811061157557611575613fba565b60200260200101516020015188858151811061159357611593613fba565b6020026020010151306040518463ffffffff1660e01b81526004016115ba9392919061430c565b600060405180830381865afa1580156115d7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115ff9190810190614339565b90506116558c838151811061161657611616613fba565b60200260200101516000015187848151811061163457611634613fba565b6020026020010151876001600160a01b0316611cdc9092919063ffffffff16565b60008c838151811061166957611669613fba565b6020026020010151600001516001600160a01b03168260405161168c9190614396565b6000604051808303816000865af19150503d80600081146116c9576040519150601f19603f3d011682016040523d82523d6000602084013e6116ce565b606091505b5050905080806116db5750895b6116f75760405162461bcd60e51b81526004016104d5906143d6565b806117245786838151811061170e5761170e613fba565b60200260200101518861172191906142f4565b97505b5050808061173190613ff1565b915050611530565b506040516370a0823160e01b81526000906001600160a01b038416906370a08231906117699030906004016130ac565b602060405180830381865afa158015611786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117aa9190613fd0565b90506117b68282613bb8565b9650600087116117d85760405162461bcd60e51b81526004016104d59061441a565b505050505094509492505050565b610ffc846323b872dd60e01b8585856040516024016118079392919061442a565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152611d79565b835187901561188b5760006118688684611e08565b92509050806118895760405162461bcd60e51b81526004016104d590614486565b505b600061189f84600001518560800151612152565b90504667ffffffffffffffff16846020015167ffffffffffffffff16141561191b577f0e248ac8be20725176a5f0ab093c5fbb964634d4675012f3d3ad66e69e56d5b7818a8a858b6040516118f8959493929190614496565b60405180910390a1611914878386600001518760c0015161105e565b50506119b9565b611926848a8a61218a565b60a084015134901561193f5761193c8a34613bb8565b90505b600080875111611950578551611952565b8b5b905060006119658483898b898f89612213565b90507fbac7d3515b47f762d5edcc83b041c8ad43133089d06f60e3b8f307a66fcb6221848289602001518f8f8c6101800151886040516119ab97969594939291906144f2565b60405180910390a150505050505b5050505050505050565b6119e28363a9059cbb60e01b848460405160240161180792919061455a565b505050565b60606000825167ffffffffffffffff811115611a0557611a056130f6565b604051908082528060200260200182016040528015611a2e578160200160208202803683370190505b50905060005b8351811015611b20576000848281518110611a5157611a51613fba565b602002602001015160200151611a669061412e565b6001600160e01b0319811660009081526002602052604090205484519192506001600160a01b031690849084908110611aa157611aa1613fba565b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b0316838381518110611ade57611ade613fba565b60200260200101516001600160a01b03161415611b0d5760405162461bcd60e51b81526004016104d5906145a9565b5080611b1881613ff1565b915050611a34565b5092915050565b60606000806000865167ffffffffffffffff811115611b4857611b486130f6565b604051908082528060200260200182016040528015611b71578160200160208202803683370190505b50935060005b8751811015611c65576000868281518110611b9457611b94613fba565b60200260200101516001600160a01b031663358f0e1c8a8481518110611bbc57611bbc613fba565b60200260200101516040518263ffffffff1660e01b8152600401611be09190614215565b606060405180830381865afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c219190614226565b90965094509050611c3281846142f4565b925080868381518110611c4757611c47613fba565b60209081029190910101525080611c5d81613ff1565b915050611b77565b5060005b8451811015611cd15781858281518110611c8557611c85613fba565b602002602001015188611c9891906145b9565b611ca291906145ee565b858281518110611cb457611cb4613fba565b602090810291909101015280611cc981613ff1565b915050611c69565b505093509350939050565b600081846001600160a01b031663dd62ed3e30866040518363ffffffff1660e01b8152600401611d0d929190613c07565b602060405180830381865afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613fd0565b611d5891906142f4565b9050610ffc8463095ea7b360e01b858460405160240161180792919061455a565b6000611dce826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122679092919063ffffffff16565b8051909150156119e25780806020019051810190611dec9190614602565b6119e25760405162461bcd60e51b81526004016104d59061467d565b60008060005b8451811015612149576000806000868481518110611e2e57611e2e613fba565b60200260200101516001600160a01b031663358f0e1c898681518110611e5657611e56613fba565b60200260200101516040518263ffffffff1660e01b8152600401611e7a9190614215565b606060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190614226565b9250925092506000878581518110611ed557611ed5613fba565b60200260200101516001600160a01b0316634c6da2698a8781518110611efd57611efd613fba565b60200260200101516020015186306040518463ffffffff1660e01b8152600401611f299392919061430c565b600060405180830381865afa158015611f46573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f6e9190810190614339565b9050611fa2898681518110611f8557611f85613fba565b6020908102919091010151516001600160a01b0385169086611cdc565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611fd19030906004016130ac565b602060405180830381865afa158015611fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120129190613fd0565b905089868151811061202657612026613fba565b6020026020010151600001516001600160a01b0316826040516120499190614396565b6000604051808303816000865af19150503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b505080985050876120a8576000809750975050505050505061214b565b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906120d79030906004016130ac565b602060405180830381865afa1580156120f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121189190613fd0565b90506121248282613bb8565b61212e90896142f4565b9750505050505050808061214190613ff1565b915050611e0e565b505b9250929050565b60003383468460405160200161216b94939291906146d4565b6040516020818303038152906040528051906020012090505b92915050565b600046846020015184848761010001518860e001516040516020016121b49695949392919061471c565b60405160208183030381529060405280519060200120905060006121d782612280565b90506121e8818661012001516122b0565b428561010001511161220c5760405162461bcd60e51b81526004016104d5906147e0565b5050505050565b6000806122218988886122ec565b905061225a8885878a602001518b608001518c60400151878e60600151600160009054906101000a90046001600160a01b03168c612361565b9998505050505050505050565b606061227684846000856123fa565b90505b9392505050565b60008160405160200161229391906147f0565b604051602081830303815290604052805190602001209050919050565b60006122bc83836124be565b6005549091506001600160a01b038083169116146119e25760405162461bcd60e51b81526004016104d59061485f565b60606040518060c0016040528085815260200183815260200184600001516001600160a01b031681526020018460c00151151581526020018460e001518152602001846101a001511515815250604051602001612349919061495b565b60405160208183030381529060405290509392505050565b60008060006123768d8d8d8d8d8d8c8c6124e2565b88519193509150156123ea57846001600160a01b0316634289fbb3858f8d85878d6040518763ffffffff1660e01b81526004016123b795949392919061498b565b6000604051808303818588803b1580156123d057600080fd5b505af11580156123e4573d6000803e3d6000fd5b50505050505b509b9a5050505050505050505050565b60608247101561241c5760405162461bcd60e51b81526004016104d590614a2c565b6001600160a01b0385163b6124435760405162461bcd60e51b81526004016104d590614a70565b600080866001600160a01b0316858760405161245f9190614396565b60006040518083038185875af1925050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50915091506124b1828286612b29565b925050505b949350505050565b60008060006124cd8585612b62565b915091506124da81612bcf565b509392505050565b60008060018460068111156124f9576124f9613046565b14156125f357826001600160a01b03166382980dc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190614a80565b90506125776001600160a01b038a16828a611cdc565b60405163a5977fbb60e01b81526001600160a01b0382169063a5977fbb906125ad908d908d908d908d908d908d90600401614aad565b600060405180830381600087803b1580156125c757600080fd5b505af11580156125db573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cb4565b9150612b1c565b600284600681111561260757612607613046565b14156126f857826001600160a01b031663d8257d176040518163ffffffff1660e01b8152600401602060405180830381865afa15801561264b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266f9190614a80565b90506126856001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016126b9959493929190614afc565b600060405180830381600087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cf4565b600384600681111561270c5761270c613046565b141561281057826001600160a01b031663dfa2dbaf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127749190614a80565b905061278a6001600160a01b038a16828a611cdc565b604051636f3c863f60e11b81526001600160a01b0382169063de790c7e906127bc908c908c908f908c90600401614b3e565b600060405180830381600087803b1580156127d657600080fd5b505af11580156127ea573d6000803e3d6000fd5b50612804925050506001600160a01b038a16826000612d13565b6125ec8a8a8a89612dc7565b600484600681111561282457612824613046565b141561291957826001600160a01b031663c66a9c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288c9190614a80565b90506128a26001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016128d6959493929190614afc565b6020604051808303816000875af11580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190613fd0565b600584600681111561292d5761292d613046565b1415612a3e57826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129959190614a80565b90506129ab6001600160a01b038a16828a611cdc565b806001600160a01b031663a00293018a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b6020604051808303816000875af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190613fd0565b9150612a396001600160a01b038a16826000612d13565b612b1c565b6006846006811115612a5257612a52613046565b1415612b0457826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aba9190614a80565b9050612ad06001600160a01b038a16828a611cdc565b806001600160a01b0316639e422c338a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b60405162461bcd60e51b81526004016104d590614ba7565b9850989650505050505050565b60608315612b38575081612279565b825115612b485782518084602001fd5b8160405162461bcd60e51b81526004016104d59190614bb7565b600080825160411415612b995760208301516040840151606085015160001a612b8d87828585612e04565b9450945050505061214b565b825160401415612bc35760208301516040840151612bb8868383612ee4565b93509350505061214b565b5060009050600261214b565b6000816004811115612be357612be3613046565b1415612bec5750565b6001816004811115612c0057612c00613046565b1415612c1e5760405162461bcd60e51b81526004016104d590614bfc565b6002816004811115612c3257612c32613046565b1415612c505760405162461bcd60e51b81526004016104d590614c40565b6003816004811115612c6457612c64613046565b1415612c825760405162461bcd60e51b81526004016104d590614c8f565b6004816004811115612c9657612c96613046565b141561105b5760405162461bcd60e51b81526004016104d590614cde565b600030868686868646604051602001612cd39796959493929190614cee565b60405160208183030381529060405280519060200120905095945050505050565b600030858585898646604051602001612cd39796959493929190614d69565b801580612d8c5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612d499030908690600401613c07565b602060405180830381865afa158015612d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8a9190613fd0565b155b612da85760405162461bcd60e51b81526004016104d590614e1f565b6119e28363095ea7b360e01b848460405160240161180792919061455a565b6000308484878546604051602001612de496959493929190614e2f565b604051602081830303815290604052805190602001209050949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e3b5750600090506003612edb565b8460ff16601b14158015612e5357508460ff16601c14155b15612e645750600090506004612edb565b600060018787878760405160008152602001604052604051612e899493929190614ea2565b6020604051602081039080840390855afa158015612eab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ed457600060019250925050612edb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681612f1a60ff86901c601b6142f4565b9050612f2887828885612e04565b935093505050935093915050565b60006001600160a01b038216612184565b612f5081612f36565b811461105b57600080fd5b803561218481612f47565b80612f50565b803561218481612f66565b60008083601f840112612f8c57612f8c600080fd5b50813567ffffffffffffffff811115612fa757612fa7600080fd5b60208301915083600182028301111561214b5761214b600080fd5b600080600080600060808688031215612fdd57612fdd600080fd5b6000612fe98888612f5b565b9550506020612ffa88828901612f6c565b945050604086013567ffffffffffffffff81111561301a5761301a600080fd5b61302688828901612f77565b9350935050606061303988828901612f5b565b9150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6003811061105b5761105b613046565b806130768161305c565b919050565b60006121848261306c565b61308f8161307b565b82525050565b602081016121848284613086565b61308f81612f36565b6020810161218482846130a3565b6000602082840312156130cf576130cf600080fd5b60006124b68484612f5b565b67ffffffffffffffff8116612f50565b8035612184816130db565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613132576131326130f6565b6040525050565b600061314460405190565b9050613076828261310c565b600067ffffffffffffffff82111561316a5761316a6130f6565b601f19601f83011660200192915050565b82818337506000910152565b600061319a61319584613150565b613139565b9050828152602081018484840111156131b5576131b5600080fd5b6124da84828561317b565b600082601f8301126131d4576131d4600080fd5b81356124b6848260208601613187565b60008060008060008060c0878903121561320057613200600080fd5b600061320c8989612f5b565b965050602061321d89828a01612f5b565b955050604061322e89828a01612f6c565b945050606061323f89828a016130eb565b935050608087013567ffffffffffffffff81111561325f5761325f600080fd5b61326b89828a016131c0565b92505060a061327c89828a01612f5b565b9150509295509295509295565b6001600160e01b03198116612f50565b803561218481613289565b801515612f50565b8035612184816132a4565b6000806000606084860312156132cf576132cf600080fd5b60006132db8686612f5b565b93505060206132ec86828701613299565b92505060406132fd868287016132ac565b9150509250925092565b60006020828403121561331c5761331c600080fd5b60006124b68484612f6c565b6000806040838503121561333e5761333e600080fd5b600061334a8585612f5b565b925050602061335b85828601613299565b9150509250929050565b80151561308f565b602081016121848284613365565b60008060008060006080868803121561339657613396600080fd5b60006133a28888612f5b565b9550506020612ffa888289016130eb565b6000806000604084860312156133cb576133cb600080fd5b833567ffffffffffffffff8111156133e5576133e5600080fd5b6133f186828701612f77565b935093505060206132fd86828701612f5b565b60006101c0828403121561341a5761341a600080fd5b50919050565b60008083601f84011261343557613435600080fd5b50813567ffffffffffffffff81111561345057613450600080fd5b60208301915083602082028301111561214b5761214b600080fd5b6000806000806000806080878903121561348757613487600080fd5b60006134938989612f5b565b965050602087013567ffffffffffffffff8111156134b3576134b3600080fd5b6134bf89828a01613404565b955050604087013567ffffffffffffffff8111156134df576134df600080fd5b6134eb89828a01613420565b9450945050606087013567ffffffffffffffff81111561350d5761350d600080fd5b61351989828a01613420565b92509250509295509295509295565b60008060006040848603121561354057613540600080fd5b833567ffffffffffffffff81111561355a5761355a600080fd5b6133f186828701613420565b60006020828403121561357b5761357b600080fd5b60006124b68484613299565b60006121846001600160a01b03831661359e565b90565b6001600160a01b031690565b600061218482613587565b6000612184826135aa565b61308f816135b5565b6020810161218482846135c0565b601981526000602082017f63616c6c6572206973206e6f74206d6573736167652062757300000000000000815291505b5060200190565b60208082528101612184816135d7565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150613607565b602080825281016121848161361e565b600067ffffffffffffffff82111561367c5761367c6130f6565b5060209081020190565b60006040828403121561369b5761369b600080fd5b6136a56040613139565b905060006136b38484612f5b565b825250602082013567ffffffffffffffff8111156136d3576136d3600080fd5b6136df848285016131c0565b60208301525092915050565b60006136f961319584613662565b8381529050602080820190840283018581111561371857613718600080fd5b835b8181101561375957803567ffffffffffffffff81111561373c5761373c600080fd5b8086016137498982613686565b855250506020928301920161371a565b5050509392505050565b600082601f83011261377757613777600080fd5b81356124b68482602086016136eb565b600060c0828403121561379c5761379c600080fd5b6137a660c0613139565b905060006137b48484612f6c565b825250602082013567ffffffffffffffff8111156137d4576137d4600080fd5b6137e084828501613763565b60208301525060406137f484828501612f5b565b6040830152506060613808848285016132ac565b606083015250608061381c84828501612f6c565b60808301525060a0613830848285016132ac565b60a08301525092915050565b60006020828403121561385157613851600080fd5b813567ffffffffffffffff81111561386b5761386b600080fd5b6124b684828501613787565b8061308f565b600061218461359b8381565b61308f8161387d565b60c081016138a08289613877565b6138ad6020830188613889565b6138ba6040830187613877565b6138c760608301866130a3565b6138d46080830185613877565b6138e160a0830184613086565b979650505050505050565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613607565b60208082528101612184816138ec565b805161218481612f66565b805161218481612f47565b60005b8381101561395f578181015183820152602001613947565b83811115610ffc5750506000910152565b600061397e61319584613150565b90508281526020810184848401111561399957613999600080fd5b6124da848285613944565b600082601f8301126139b8576139b8600080fd5b81516124b6848260208601613970565b6000604082840312156139dd576139dd600080fd5b6139e76040613139565b905060006139f58484613939565b825250602082015167ffffffffffffffff811115613a1557613a15600080fd5b6136df848285016139a4565b6000613a2f61319584613662565b83815290506020808201908402830185811115613a4e57613a4e600080fd5b835b8181101561375957805167ffffffffffffffff811115613a7257613a72600080fd5b808601613a7f89826139c8565b8552505060209283019201613a50565b600082601f830112613aa357613aa3600080fd5b81516124b6848260208601613a21565b8051612184816132a4565b600060c08284031215613ad357613ad3600080fd5b613add60c0613139565b90506000613aeb848461392e565b825250602082015167ffffffffffffffff811115613b0b57613b0b600080fd5b613b1784828501613a8f565b6020830152506040613b2b84828501613939565b6040830152506060613b3f84828501613ab3565b6060830152506080613b538482850161392e565b60808301525060a061383084828501613ab3565b600060208284031215613b7c57613b7c600080fd5b815167ffffffffffffffff811115613b9657613b96600080fd5b6124b684828501613abe565b634e487b7160e01b600052601160045260246000fd5b600082821015613bca57613bca613ba2565b500390565b6001600160e01b0319811661308f565b60608101613bed82866130a3565b613bfa6020830185613bcf565b6124b66040830184613365565b60408101613c1582856130a3565b61227960208301846130a3565b60c08101613c308289613877565b613c3d6020830188613889565b6138ba6040830187613889565b600781526000602082017f746b696e206d6d0000000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481613c4a565b60c08101613c9c8289613877565b6138ad6020830188613877565b6000613cb683858461317b565b50500190565b60006124b6828486613ca9565b60408101613c158285613bcf565b600060208284031215613cec57613cec600080fd5b60006124b684846130eb565b600381526000602082016206e6f760ec1b81529150613607565b6020808252810161218481613cf8565b60006122793684846136eb565b600060208284031215613d4457613d44600080fd5b60006124b684846132ac565b601281526000602082017f746b696e206e6f206e617469766557726170000000000000000000000000000081529150613607565b6020808252810161218481613d50565b600b81526000602082017f696e7366636e7420616d7400000000000000000000000000000000000000000081529150613607565b6020808252810161218481613d94565b63ffffffff8116612f50565b803561218481613dd8565b6007811061105b57600080fd5b803561218481613def565b60006101c08284031215613e1d57613e1d600080fd5b613e286101c0613139565b90506000613e368484612f5b565b8252506020613e47848483016130eb565b6020830152506040613e5b84828501613de4565b6040830152506060613e6f84828501613dfc565b6060830152506080613e83848285016130eb565b60808301525060a0613e97848285016132ac565b60a08301525060c0613eab848285016132ac565b60c08301525060e0613ebf84828501612f6c565b60e083015250610100613ed484828501612f6c565b6101008301525061012082013567ffffffffffffffff811115613ef957613ef9600080fd5b613f05848285016131c0565b61012083015250610140613f1b84828501612f6c565b61014083015250610160613f3184828501612f5b565b61016083015250610180613f4784828501612f5b565b610180830152506101a0613f5d848285016132ac565b6101a08301525092915050565b60006121843683613e07565b601181526000602082017f6e6f742066656520636f6c6c6563746f7200000000000000000000000000000081529150613607565b6020808252810161218481613f76565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613fe557613fe5600080fd5b60006124b6848461392e565b600060001982141561400557614005613ba2565b5060010190565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015291505b5060400190565b602080825281016121848161400c565b600c81526000602082017f746b206e6f206e6174697665000000000000000000000000000000000000000081529150613607565b6020808252810161218481614079565b602081016121848284613877565b60006121848261359b565b600981526000602082017f73656e64206661696c000000000000000000000000000000000000000000000081529150613607565b60208082528101612184816140d6565b600061218482516001600160e01b03191690565b6000614138825190565b602083016141458161411a565b9250600482101561416c576141676001600160e01b0319836004036008021b90565b831692505b5050919050565b600f81526000602082017f756e737570706f7274656420646578000000000000000000000000000000000081529150613607565b6020808252810161218481614173565b60006141c1825190565b8084526020840193506141d8818560208601613944565b601f01601f19169290920192915050565b805160009060408401906141fd85826130a3565b5060208301518482036020860152610add82826141b7565b6020808252810161227981846141e9565b60008060006060848603121561423e5761423e600080fd5b600061424a868661392e565b935050602061425b86828701613939565b92505060406132fd86828701613939565b600d81526000602082017f746b696e206d69736d617463680000000000000000000000000000000000000081529150613607565b602080825281016121848161426c565b600c81526000602082017f746b6f206d69736d61746368000000000000000000000000000000000000000081529150613607565b60208082528101612184816142b0565b6000821982111561430757614307613ba2565b500190565b6060808252810161431d81866141b7565b905061432c6020830185613877565b6124b660408301846130a3565b60006020828403121561434e5761434e600080fd5b815167ffffffffffffffff81111561436857614368600080fd5b6124b6848285016139a4565b600061437e825190565b61438c818560208601613944565b9290920192915050565b60006122798284614374565b600b81526000602082017f73776170206661696c656400000000000000000000000000000000000000000081529150613607565b60208082528101612184816143a2565b601081526000602082017f616c6c207377617073206661696c65640000000000000000000000000000000081529150613607565b60208082528101612184816143e6565b6060810161443882866130a3565b61444560208301856130a3565b6124b66040830184613877565b600981526000602082017f73776170206661696c000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481614452565b60a081016144a48288613877565b6144b16020830187613877565b6144be60408301866130a3565b6144cb6060830185613877565b6144d860808301846130a3565b9695505050505050565b67ffffffffffffffff811661308f565b60e08101614500828a613877565b61450d6020830189613877565b61451a60408301886144e2565b6145276060830187613877565b61453460808301866130a3565b61454160a08301856130a3565b61454e60c08301846130a3565b98975050505050505050565b6040810161456882856130a3565b6122796020830184613877565b600c81526000602082017f636463206e6f20666f756e64000000000000000000000000000000000000000081529150613607565b6020808252810161218481614575565b60008160001904831182151516156145d3576145d3613ba2565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145fd576145fd6145d8565b500490565b60006020828403121561461757614617600080fd5b60006124b68484613ab3565b602a81526000602082017f5361666545524332303a204552433230206f7065726174696f6e20646964206e81527f6f7420737563636565640000000000000000000000000000000000000000000060208201529150614062565b6020808252810161218481614623565b60006121848260601b90565b60006121848261468d565b61308f6146b082612f36565b614699565b60006121848260c01b90565b61308f67ffffffffffffffff82166146b5565b60006146e082876146a4565b6014820191506146f082866146a4565b60148201915061470082856146c1565b60088201915061471082846146c1565b50600801949350505050565b7f6578656375746f722066656500000000000000000000000000000000000000008152600c01600061474e82896146c1565b60088201915061475e82886146c1565b60088201915061476e8287613877565b60208201915061477e82866146a4565b60148201915061478e8285613877565b60208201915061479e8284613877565b506020019695505050505050565b601181526000602082017f646561646c696e6520657863656564656400000000000000000000000000000081529150613607565b60208082528101612184816147ac565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0160006148228284613877565b50602001919050565b600e81526000602082017f696e76616c6964207369676e657200000000000000000000000000000000000081529150613607565b602080825281016121848161482b565b600061227983836141e9565b6000614885825190565b8084526020840193508360208202850161489f8560200190565b8060005b858110156148d457848403895281516148bc858261486f565b94506020830160209a909a01999250506001016148a3565b5091979650505050505050565b805160009060c08401906148f58582613877565b506020830151848203602086015261490d828261487b565b915050604083015161492260408601826130a3565b5060608301516149356060860182613365565b5060808301516149486080860182613877565b5060a08301516124da60a0860182613365565b6020808252810161227981846148e1565b600061218461359b67ffffffffffffffff841681565b61308f8161496c565b60a0810161499982886130a3565b6149a66020830187614982565b6149b360408301866130a3565b6149c06060830185613877565b81810360808301526138e181846141b7565b602681526000602082017f416464726573733a20696e73756666696369656e742062616c616e636520666f81527f722063616c6c000000000000000000000000000000000000000000000000000060208201529150614062565b60208082528101612184816149d2565b601d81526000602082017f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081529150613607565b6020808252810161218481614a3c565b600060208284031215614a9557614a95600080fd5b60006124b68484613939565b63ffffffff811661308f565b60c08101614abb82896130a3565b614ac860208301886130a3565b614ad56040830187613877565b614ae260608301866144e2565b614aef60808301856144e2565b6138e160a0830184614aa1565b60a08101614b0a82886130a3565b614b176020830187613877565b614b2460408301866144e2565b614b3160608301856130a3565b6144d860808301846144e2565b60808101614b4c82876130a3565b614b596020830186613877565b614b6660408301856130a3565b610add60608301846144e2565b601981526000602082017f6272696467652074797065206e6f7420737570706f727465640000000000000081529150613607565b6020808252810161218481614b73565b6020808252810161227981846141b7565b601881526000602082017f45434453413a20696e76616c6964207369676e6174757265000000000000000081529150613607565b6020808252810161218481614bc8565b601f81526000602082017f45434453413a20696e76616c6964207369676e6174757265206c656e6774680081529150613607565b6020808252810161218481614c0c565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c50565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c9f565b6000614cfa828a6146a4565b601482019150614d0a82896146a4565b601482019150614d1a82886146a4565b601482019150614d2a8287613877565b602082019150614d3a82866146c1565b600882019150614d4a82856146c1565b600882019150614d5a82846146c1565b50600801979650505050505050565b6000614d75828a6146a4565b601482019150614d8582896146a4565b601482019150614d958288613877565b602082019150614da582876146c1565b600882019150614db582866146a4565b601482019150614d4a82856146c1565b603681526000602082017f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060208201529150614062565b6020808252810161218481614dc5565b6000614e3b82896146a4565b601482019150614e4b82886146a4565b601482019150614e5b8287613877565b602082019150614e6b82866146a4565b601482019150614e7b82856146c1565b600882019150614e8b82846146c1565b506008019695505050505050565b60ff811661308f565b60808101614eb08287613877565b614ebd6020830186614e99565b614eca6040830185613877565b610add606083018461387756fea2646970667358221220eae1c3b25d0ff199671cc0ccdeb5ab9d13b1454bc5f6ee971c30f3211cf9448d64736f6c634300080c00330000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d80000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000000000000000000000000000000000000000000000000000000000000000002765786368616e676528696e743132382c696e743132382c75696e743235362c75696e743235362900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003265786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e74323536290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c616464726573732900000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000006ece0fbb1ed61ca4186fa5345766dafd5713818d000000000000000000000000b7c24c8c783259c8b870974f549570e58e2c4fdd0000000000000000000000002f3eedc9d0c3bf56d0b0618364257f2dff57c680000000000000000000000000dc6d59423b78cffbdfd7ec2294242e7a00e264480000000000000000000000000000000000000000000000000000000000000008000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7000000000000000000000000d632f22692fac7611d2aa1c0d552930d43caed3b0000000000000000000000005a6a4d54456819380173272a5e8e9b9904bdf41b000000000000000000000000ceaf7747579696a2f0bb206a14210e3c9e6fb269000000000000000000000000a5407eae9ba41422680e2e00537571bcc53efbfd000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca0000000000000000000000004807862aa8b2bf68830e4c8dc86d0e9a998e085a00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000000000000000000000000000000000000000000000000000000000000000002765786368616e676528696e743132382c696e743132382c75696e743235362c75696e743235362900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003265786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e74323536290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000
Deployed Bytecode
0x6080604052600436106101845760003560e01c80638da5cb5b116100d6578063c415b95c1161007f578063efcfd8f511610059578063efcfd8f514610425578063f2fde38b14610445578063fbf5d7631461046557600080fd5b8063c415b95c146103d2578063c5bccca3146103f2578063d8318ae51461041257600080fd5b8063a1a227fa116100b0578063a1a227fa1461035c578063a1c9d41e1461037c578063a42dce80146103b257600080fd5b80638da5cb5b146102e357806391ec04b5146103015780639c649fdf1461034957600080fd5b80635b5a66a711610138578063715018a611610112578063715018a61461029b5780637cd2bffc146102b057806382665a8f146102c357600080fd5b80635b5a66a71461023b578063675df7591461025b5780636c19e7831461027b57600080fd5b8063457bfa2f11610169578063457bfa2f146101e6578063547cad12146102065780635ab7afc61461022857600080fd5b80630bcb498214610190578063238ac933146101b957600080fd5b3661018b57005b600080fd5b6101a361019e366004612fc2565b6104a8565b6040516101b09190613095565b60405180910390f35b3480156101c557600080fd5b506005546101d9906001600160a01b031681565b6040516101b091906130ac565b3480156101f257600080fd5b506008546101d9906001600160a01b031681565b34801561021257600080fd5b506102266102213660046130ba565b610585565b005b6101a36102363660046131e4565b610606565b34801561024757600080fd5b506102266102563660046130ba565b6106fb565b34801561026757600080fd5b506102266102763660046132b7565b610770565b34801561028757600080fd5b506102266102963660046130ba565b6107e5565b3480156102a757600080fd5b5061022661086e565b6101a36102be3660046131e4565b6108a4565b3480156102cf57600080fd5b506101d96102de366004613307565b610a86565b3480156102ef57600080fd5b506000546001600160a01b03166101d9565b34801561030d57600080fd5b5061033c61031c366004613328565b600460209081526000928352604080842090915290825290205460ff1681565b6040516101b0919061336d565b6101a361035736600461337b565b610ab0565b34801561036857600080fd5b506001546101d9906001600160a01b031681565b34801561038857600080fd5b506101d9610397366004613307565b6009602052600090815260409020546001600160a01b031681565b3480156103be57600080fd5b506102266103cd3660046130ba565b610ae6565b3480156103de57600080fd5b506006546101d9906001600160a01b031681565b3480156103fe57600080fd5b5061022661040d3660046133b3565b610b63565b61022661042036600461346b565b610c5f565b34801561043157600080fd5b50610226610440366004613528565b610ee1565b34801561045157600080fd5b506102266104603660046130ba565b611002565b34801561047157600080fd5b5061049b610480366004613566565b6002602052600090815260409020546001600160a01b031681565b6040516101b091906135c9565b6001546000906001600160a01b031633146104de5760405162461bcd60e51b81526004016104d59061360e565b60405180910390fd5b600260075414156105015760405162461bcd60e51b81526004016104d590613652565b600260075560006105148486018661383c565b905061052787878360400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24581600001516000888a8560800151600260405161056a96959493929190613892565b60405180910390a16001915050600160075595945050505050565b6000546001600160a01b031633146105af5760405162461bcd60e51b81526004016104d59061391e565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f3f8223bcd8b3b875473e9f9e14e1ad075451a2b5ffd31591655da9a01516bf5e916105fb916130ac565b60405180910390a150565b6001546000906001600160a01b031633146106335760405162461bcd60e51b81526004016104d59061360e565b600260075414156106565760405162461bcd60e51b81526004016104d590613652565b600260075582516000906106739085016020908101908601613b67565b905060008160800151876106879190613bb8565b905061069a88828460400151600061105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c24582600001516000838b866080015160026040516106dd96959493929190613892565b60405180910390a16001925050505b60016007559695505050505050565b6000546001600160a01b031633146107255760405162461bcd60e51b81526004016104d59061391e565b600880546001600160a01b0319166001600160a01b0383161790556040517fb878cd71628ac64b2df1872301925e01164824535b02e8601077749eeeb88c3d906105fb9083906130ac565b6000546001600160a01b0316331461079a5760405162461bcd60e51b81526004016104d59061391e565b6107a583838361118e565b7f5e20184b00709d9f103306958e9fb9d509f78bec1829ca7080f2c43eb2ff21a88383836040516107d893929190613bdf565b60405180910390a1505050565b6000546001600160a01b0316331461080f5760405162461bcd60e51b81526004016104d59061391e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb906108629083908590613c07565b60405180910390a15050565b6000546001600160a01b031633146108985760405162461bcd60e51b81526004016104d59061391e565b6108a26000611225565b565b6001546000906001600160a01b031633146108d15760405162461bcd60e51b81526004016104d59061360e565b600260075414156108f45760405162461bcd60e51b81526004016104d590613652565b600260075582516000906109119085016020908101908601613b67565b90508060800151861015610974576080810186905280516040517f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245916109629160009081908c908c90600190613c22565b60405180910390a160019150506106ec565b60808101516109839087613bb8565b955060608101516020820151518891908890600090156109fd57606060006109ae8760200151611275565b90985093509150506001600160a01b03808216908e16146109e15760405162461bcd60e51b81526004016104d590613c7e565b6109f58760200151838e8a60a001516114a3565b909450925050505b8015610a1457610a148b828760400151600061105e565b610a24848387604001518661105e565b7f83fb878bc850fecc32634e2924a47daa8db823de1e2eb33084be9fd29f22c245856000015183838e89608001516001604051610a6696959493929190613c8e565b60405180910390a160019550505050505060016007559695505050505050565b60038181548110610a9657600080fd5b6000918252602090912001546001600160a01b0316905081565b6001546000906001600160a01b03163314610add5760405162461bcd60e51b81526004016104d59061360e565b95945050505050565b6000546001600160a01b03163314610b105760405162461bcd60e51b81526004016104d59061391e565b600680546001600160a01b038381166001600160a01b03198316179092556040519116907f5d16ad41baeb009cd23eb8f6c7cde5c2e0cd5acf4a33926ab488875c37c37f38906108629083908590613c07565b6000546001600160a01b03163314610b8d5760405162461bcd60e51b81526004016104d59061391e565b60008383604051610b9f929190613cbc565b60405180910390209050610c2081836001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b7f58ddcdb40971f55ad1b6a8a28067274a4ffc7e9d77c3ea14a17652faa705e1978183604051610c51929190613cc9565b60405180910390a150505050565b60026007541415610c825760405162461bcd60e51b81526004016104d590613652565b600260075582151580610cb8575067ffffffffffffffff4616610cab6040870160208801613cd7565b67ffffffffffffffff1614155b610cd45760405162461bcd60e51b81526004016104d590613d12565b82151580610d0c575061014085013515801590610d0c57506000610d00610180870161016088016130ba565b6001600160a01b031614155b610d285760405162461bcd60e51b81526004016104d590613d12565b6101408501356000610d42610180880161016089016130ba565b90506000610d5861018089016101608a016130ba565b905060608615610dc057610d74610d6f888a613d22565b611275565b92965090945092509050610d906101808a016101608b016130ba565b6001600160a01b0316836001600160a01b031614610dc05760405162461bcd60e51b81526004016104d590613c7e565b610dd060c08a0160a08b01613d2f565b15610e90576008546001600160a01b03848116911614610e025760405162461bcd60e51b81526004016104d590613d84565b83341015610e225760405162461bcd60e51b81526004016104d590613dc8565b600860009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b5050505050610ea5565b610ea56001600160a01b0384163330876117e6565b610ed08a858585610eb68c8e613d22565b610ec08b8d613d22565b8f610eca90613f6a565b88611853565b505060016007555050505050505050565b6006546001600160a01b03163314610f0b5760405162461bcd60e51b81526004016104d590613faa565b60005b82811015610ffc576000848483818110610f2a57610f2a613fba565b9050602002016020810190610f3f91906130ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f6a91906130ac565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190613fd0565b9050610fe98382878786818110610fc457610fc4613fba565b9050602002016020810190610fd991906130ba565b6001600160a01b031691906119c3565b5080610ff481613ff1565b915050610f0e565b50505050565b6000546001600160a01b0316331461102c5760405162461bcd60e51b81526004016104d59061391e565b6001600160a01b0381166110525760405162461bcd60e51b81526004016104d590614069565b61105b81611225565b50565b801561117a576008546001600160a01b038581169116146110915760405162461bcd60e51b81526004016104d5906140ad565b600854604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906110c19086906004016140bd565b600060405180830381600087803b1580156110db57600080fd5b505af11580156110ef573d6000803e3d6000fd5b505050506000826001600160a01b03168461c35090604051611110906140cb565b600060405180830381858888f193505050503d806000811461114e576040519150601f19603f3d011682016040523d82523d6000602084013e611153565b606091505b50509050806111745760405162461bcd60e51b81526004016104d59061410a565b50610ffc565b610ffc6001600160a01b03851683856119c3565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff1680151582151514156111e35760405162461bcd60e51b81526004016104d590613d12565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060006060600080611288876119e7565b925060005b875181101561149957600460008983815181106112ac576112ac613fba565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008983815181106112ec576112ec613fba565b6020026020010151602001516113019061412e565b6001600160e01b031916815260208101919091526040016000205460ff1661133b5760405162461bcd60e51b81526004016104d5906141a7565b600080600086848151811061135257611352613fba565b60200260200101516001600160a01b031663358f0e1c8c868151811061137a5761137a613fba565b60200260200101516040518263ffffffff1660e01b815260040161139e9190614215565b606060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190614226565b919450925090506001600160a01b038616158061140d5750816001600160a01b0316866001600160a01b0316145b6114295760405162461bcd60e51b81526004016104d5906142a0565b90945084906001600160a01b03851615806114555750806001600160a01b0316856001600160a01b0316145b6114715760405162461bcd60e51b81526004016104d5906142e4565b93508361147e838b6142f4565b9950909750955081905061149181613ff1565b91505061128d565b5050509193509193565b60008060008060006114b689888a611b27565b9250925092506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114ea91906130ac565b602060405180830381865afa158015611507573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152b9190613fd0565b905060005b8a518110156117395760008a828151811061154d5761154d613fba565b60200260200101516001600160a01b0316634c6da2698d848151811061157557611575613fba565b60200260200101516020015188858151811061159357611593613fba565b6020026020010151306040518463ffffffff1660e01b81526004016115ba9392919061430c565b600060405180830381865afa1580156115d7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115ff9190810190614339565b90506116558c838151811061161657611616613fba565b60200260200101516000015187848151811061163457611634613fba565b6020026020010151876001600160a01b0316611cdc9092919063ffffffff16565b60008c838151811061166957611669613fba565b6020026020010151600001516001600160a01b03168260405161168c9190614396565b6000604051808303816000865af19150503d80600081146116c9576040519150601f19603f3d011682016040523d82523d6000602084013e6116ce565b606091505b5050905080806116db5750895b6116f75760405162461bcd60e51b81526004016104d5906143d6565b806117245786838151811061170e5761170e613fba565b60200260200101518861172191906142f4565b97505b5050808061173190613ff1565b915050611530565b506040516370a0823160e01b81526000906001600160a01b038416906370a08231906117699030906004016130ac565b602060405180830381865afa158015611786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117aa9190613fd0565b90506117b68282613bb8565b9650600087116117d85760405162461bcd60e51b81526004016104d59061441a565b505050505094509492505050565b610ffc846323b872dd60e01b8585856040516024016118079392919061442a565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152611d79565b835187901561188b5760006118688684611e08565b92509050806118895760405162461bcd60e51b81526004016104d590614486565b505b600061189f84600001518560800151612152565b90504667ffffffffffffffff16846020015167ffffffffffffffff16141561191b577f0e248ac8be20725176a5f0ab093c5fbb964634d4675012f3d3ad66e69e56d5b7818a8a858b6040516118f8959493929190614496565b60405180910390a1611914878386600001518760c0015161105e565b50506119b9565b611926848a8a61218a565b60a084015134901561193f5761193c8a34613bb8565b90505b600080875111611950578551611952565b8b5b905060006119658483898b898f89612213565b90507fbac7d3515b47f762d5edcc83b041c8ad43133089d06f60e3b8f307a66fcb6221848289602001518f8f8c6101800151886040516119ab97969594939291906144f2565b60405180910390a150505050505b5050505050505050565b6119e28363a9059cbb60e01b848460405160240161180792919061455a565b505050565b60606000825167ffffffffffffffff811115611a0557611a056130f6565b604051908082528060200260200182016040528015611a2e578160200160208202803683370190505b50905060005b8351811015611b20576000848281518110611a5157611a51613fba565b602002602001015160200151611a669061412e565b6001600160e01b0319811660009081526002602052604090205484519192506001600160a01b031690849084908110611aa157611aa1613fba565b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b0316838381518110611ade57611ade613fba565b60200260200101516001600160a01b03161415611b0d5760405162461bcd60e51b81526004016104d5906145a9565b5080611b1881613ff1565b915050611a34565b5092915050565b60606000806000865167ffffffffffffffff811115611b4857611b486130f6565b604051908082528060200260200182016040528015611b71578160200160208202803683370190505b50935060005b8751811015611c65576000868281518110611b9457611b94613fba565b60200260200101516001600160a01b031663358f0e1c8a8481518110611bbc57611bbc613fba565b60200260200101516040518263ffffffff1660e01b8152600401611be09190614215565b606060405180830381865afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c219190614226565b90965094509050611c3281846142f4565b925080868381518110611c4757611c47613fba565b60209081029190910101525080611c5d81613ff1565b915050611b77565b5060005b8451811015611cd15781858281518110611c8557611c85613fba565b602002602001015188611c9891906145b9565b611ca291906145ee565b858281518110611cb457611cb4613fba565b602090810291909101015280611cc981613ff1565b915050611c69565b505093509350939050565b600081846001600160a01b031663dd62ed3e30866040518363ffffffff1660e01b8152600401611d0d929190613c07565b602060405180830381865afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613fd0565b611d5891906142f4565b9050610ffc8463095ea7b360e01b858460405160240161180792919061455a565b6000611dce826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122679092919063ffffffff16565b8051909150156119e25780806020019051810190611dec9190614602565b6119e25760405162461bcd60e51b81526004016104d59061467d565b60008060005b8451811015612149576000806000868481518110611e2e57611e2e613fba565b60200260200101516001600160a01b031663358f0e1c898681518110611e5657611e56613fba565b60200260200101516040518263ffffffff1660e01b8152600401611e7a9190614215565b606060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190614226565b9250925092506000878581518110611ed557611ed5613fba565b60200260200101516001600160a01b0316634c6da2698a8781518110611efd57611efd613fba565b60200260200101516020015186306040518463ffffffff1660e01b8152600401611f299392919061430c565b600060405180830381865afa158015611f46573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f6e9190810190614339565b9050611fa2898681518110611f8557611f85613fba565b6020908102919091010151516001600160a01b0385169086611cdc565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611fd19030906004016130ac565b602060405180830381865afa158015611fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120129190613fd0565b905089868151811061202657612026613fba565b6020026020010151600001516001600160a01b0316826040516120499190614396565b6000604051808303816000865af19150503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b505080985050876120a8576000809750975050505050505061214b565b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906120d79030906004016130ac565b602060405180830381865afa1580156120f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121189190613fd0565b90506121248282613bb8565b61212e90896142f4565b9750505050505050808061214190613ff1565b915050611e0e565b505b9250929050565b60003383468460405160200161216b94939291906146d4565b6040516020818303038152906040528051906020012090505b92915050565b600046846020015184848761010001518860e001516040516020016121b49695949392919061471c565b60405160208183030381529060405280519060200120905060006121d782612280565b90506121e8818661012001516122b0565b428561010001511161220c5760405162461bcd60e51b81526004016104d5906147e0565b5050505050565b6000806122218988886122ec565b905061225a8885878a602001518b608001518c60400151878e60600151600160009054906101000a90046001600160a01b03168c612361565b9998505050505050505050565b606061227684846000856123fa565b90505b9392505050565b60008160405160200161229391906147f0565b604051602081830303815290604052805190602001209050919050565b60006122bc83836124be565b6005549091506001600160a01b038083169116146119e25760405162461bcd60e51b81526004016104d59061485f565b60606040518060c0016040528085815260200183815260200184600001516001600160a01b031681526020018460c00151151581526020018460e001518152602001846101a001511515815250604051602001612349919061495b565b60405160208183030381529060405290509392505050565b60008060006123768d8d8d8d8d8d8c8c6124e2565b88519193509150156123ea57846001600160a01b0316634289fbb3858f8d85878d6040518763ffffffff1660e01b81526004016123b795949392919061498b565b6000604051808303818588803b1580156123d057600080fd5b505af11580156123e4573d6000803e3d6000fd5b50505050505b509b9a5050505050505050505050565b60608247101561241c5760405162461bcd60e51b81526004016104d590614a2c565b6001600160a01b0385163b6124435760405162461bcd60e51b81526004016104d590614a70565b600080866001600160a01b0316858760405161245f9190614396565b60006040518083038185875af1925050503d806000811461249c576040519150601f19603f3d011682016040523d82523d6000602084013e6124a1565b606091505b50915091506124b1828286612b29565b925050505b949350505050565b60008060006124cd8585612b62565b915091506124da81612bcf565b509392505050565b60008060018460068111156124f9576124f9613046565b14156125f357826001600160a01b03166382980dc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190614a80565b90506125776001600160a01b038a16828a611cdc565b60405163a5977fbb60e01b81526001600160a01b0382169063a5977fbb906125ad908d908d908d908d908d908d90600401614aad565b600060405180830381600087803b1580156125c757600080fd5b505af11580156125db573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cb4565b9150612b1c565b600284600681111561260757612607613046565b14156126f857826001600160a01b031663d8257d176040518163ffffffff1660e01b8152600401602060405180830381865afa15801561264b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266f9190614a80565b90506126856001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016126b9959493929190614afc565b600060405180830381600087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506125ec8a8a8a8a8a612cf4565b600384600681111561270c5761270c613046565b141561281057826001600160a01b031663dfa2dbaf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127749190614a80565b905061278a6001600160a01b038a16828a611cdc565b604051636f3c863f60e11b81526001600160a01b0382169063de790c7e906127bc908c908c908f908c90600401614b3e565b600060405180830381600087803b1580156127d657600080fd5b505af11580156127ea573d6000803e3d6000fd5b50612804925050506001600160a01b038a16826000612d13565b6125ec8a8a8a89612dc7565b600484600681111561282457612824613046565b141561291957826001600160a01b031663c66a9c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288c9190614a80565b90506128a26001600160a01b038a16828a611cdc565b806001600160a01b031663234636248a8a8a8e8b6040518663ffffffff1660e01b81526004016128d6959493929190614afc565b6020604051808303816000875af11580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190613fd0565b600584600681111561292d5761292d613046565b1415612a3e57826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129959190614a80565b90506129ab6001600160a01b038a16828a611cdc565b806001600160a01b031663a00293018a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b6020604051808303816000875af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190613fd0565b9150612a396001600160a01b038a16826000612d13565b612b1c565b6006846006811115612a5257612a52613046565b1415612b0457826001600160a01b03166395b12c276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aba9190614a80565b9050612ad06001600160a01b038a16828a611cdc565b806001600160a01b0316639e422c338a8a8a8e8b6040518663ffffffff1660e01b81526004016129df959493929190614afc565b60405162461bcd60e51b81526004016104d590614ba7565b9850989650505050505050565b60608315612b38575081612279565b825115612b485782518084602001fd5b8160405162461bcd60e51b81526004016104d59190614bb7565b600080825160411415612b995760208301516040840151606085015160001a612b8d87828585612e04565b9450945050505061214b565b825160401415612bc35760208301516040840151612bb8868383612ee4565b93509350505061214b565b5060009050600261214b565b6000816004811115612be357612be3613046565b1415612bec5750565b6001816004811115612c0057612c00613046565b1415612c1e5760405162461bcd60e51b81526004016104d590614bfc565b6002816004811115612c3257612c32613046565b1415612c505760405162461bcd60e51b81526004016104d590614c40565b6003816004811115612c6457612c64613046565b1415612c825760405162461bcd60e51b81526004016104d590614c8f565b6004816004811115612c9657612c96613046565b141561105b5760405162461bcd60e51b81526004016104d590614cde565b600030868686868646604051602001612cd39796959493929190614cee565b60405160208183030381529060405280519060200120905095945050505050565b600030858585898646604051602001612cd39796959493929190614d69565b801580612d8c5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612d499030908690600401613c07565b602060405180830381865afa158015612d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8a9190613fd0565b155b612da85760405162461bcd60e51b81526004016104d590614e1f565b6119e28363095ea7b360e01b848460405160240161180792919061455a565b6000308484878546604051602001612de496959493929190614e2f565b604051602081830303815290604052805190602001209050949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e3b5750600090506003612edb565b8460ff16601b14158015612e5357508460ff16601c14155b15612e645750600090506004612edb565b600060018787878760405160008152602001604052604051612e899493929190614ea2565b6020604051602081039080840390855afa158015612eab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ed457600060019250925050612edb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681612f1a60ff86901c601b6142f4565b9050612f2887828885612e04565b935093505050935093915050565b60006001600160a01b038216612184565b612f5081612f36565b811461105b57600080fd5b803561218481612f47565b80612f50565b803561218481612f66565b60008083601f840112612f8c57612f8c600080fd5b50813567ffffffffffffffff811115612fa757612fa7600080fd5b60208301915083600182028301111561214b5761214b600080fd5b600080600080600060808688031215612fdd57612fdd600080fd5b6000612fe98888612f5b565b9550506020612ffa88828901612f6c565b945050604086013567ffffffffffffffff81111561301a5761301a600080fd5b61302688828901612f77565b9350935050606061303988828901612f5b565b9150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b6003811061105b5761105b613046565b806130768161305c565b919050565b60006121848261306c565b61308f8161307b565b82525050565b602081016121848284613086565b61308f81612f36565b6020810161218482846130a3565b6000602082840312156130cf576130cf600080fd5b60006124b68484612f5b565b67ffffffffffffffff8116612f50565b8035612184816130db565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613132576131326130f6565b6040525050565b600061314460405190565b9050613076828261310c565b600067ffffffffffffffff82111561316a5761316a6130f6565b601f19601f83011660200192915050565b82818337506000910152565b600061319a61319584613150565b613139565b9050828152602081018484840111156131b5576131b5600080fd5b6124da84828561317b565b600082601f8301126131d4576131d4600080fd5b81356124b6848260208601613187565b60008060008060008060c0878903121561320057613200600080fd5b600061320c8989612f5b565b965050602061321d89828a01612f5b565b955050604061322e89828a01612f6c565b945050606061323f89828a016130eb565b935050608087013567ffffffffffffffff81111561325f5761325f600080fd5b61326b89828a016131c0565b92505060a061327c89828a01612f5b565b9150509295509295509295565b6001600160e01b03198116612f50565b803561218481613289565b801515612f50565b8035612184816132a4565b6000806000606084860312156132cf576132cf600080fd5b60006132db8686612f5b565b93505060206132ec86828701613299565b92505060406132fd868287016132ac565b9150509250925092565b60006020828403121561331c5761331c600080fd5b60006124b68484612f6c565b6000806040838503121561333e5761333e600080fd5b600061334a8585612f5b565b925050602061335b85828601613299565b9150509250929050565b80151561308f565b602081016121848284613365565b60008060008060006080868803121561339657613396600080fd5b60006133a28888612f5b565b9550506020612ffa888289016130eb565b6000806000604084860312156133cb576133cb600080fd5b833567ffffffffffffffff8111156133e5576133e5600080fd5b6133f186828701612f77565b935093505060206132fd86828701612f5b565b60006101c0828403121561341a5761341a600080fd5b50919050565b60008083601f84011261343557613435600080fd5b50813567ffffffffffffffff81111561345057613450600080fd5b60208301915083602082028301111561214b5761214b600080fd5b6000806000806000806080878903121561348757613487600080fd5b60006134938989612f5b565b965050602087013567ffffffffffffffff8111156134b3576134b3600080fd5b6134bf89828a01613404565b955050604087013567ffffffffffffffff8111156134df576134df600080fd5b6134eb89828a01613420565b9450945050606087013567ffffffffffffffff81111561350d5761350d600080fd5b61351989828a01613420565b92509250509295509295509295565b60008060006040848603121561354057613540600080fd5b833567ffffffffffffffff81111561355a5761355a600080fd5b6133f186828701613420565b60006020828403121561357b5761357b600080fd5b60006124b68484613299565b60006121846001600160a01b03831661359e565b90565b6001600160a01b031690565b600061218482613587565b6000612184826135aa565b61308f816135b5565b6020810161218482846135c0565b601981526000602082017f63616c6c6572206973206e6f74206d6573736167652062757300000000000000815291505b5060200190565b60208082528101612184816135d7565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150613607565b602080825281016121848161361e565b600067ffffffffffffffff82111561367c5761367c6130f6565b5060209081020190565b60006040828403121561369b5761369b600080fd5b6136a56040613139565b905060006136b38484612f5b565b825250602082013567ffffffffffffffff8111156136d3576136d3600080fd5b6136df848285016131c0565b60208301525092915050565b60006136f961319584613662565b8381529050602080820190840283018581111561371857613718600080fd5b835b8181101561375957803567ffffffffffffffff81111561373c5761373c600080fd5b8086016137498982613686565b855250506020928301920161371a565b5050509392505050565b600082601f83011261377757613777600080fd5b81356124b68482602086016136eb565b600060c0828403121561379c5761379c600080fd5b6137a660c0613139565b905060006137b48484612f6c565b825250602082013567ffffffffffffffff8111156137d4576137d4600080fd5b6137e084828501613763565b60208301525060406137f484828501612f5b565b6040830152506060613808848285016132ac565b606083015250608061381c84828501612f6c565b60808301525060a0613830848285016132ac565b60a08301525092915050565b60006020828403121561385157613851600080fd5b813567ffffffffffffffff81111561386b5761386b600080fd5b6124b684828501613787565b8061308f565b600061218461359b8381565b61308f8161387d565b60c081016138a08289613877565b6138ad6020830188613889565b6138ba6040830187613877565b6138c760608301866130a3565b6138d46080830185613877565b6138e160a0830184613086565b979650505050505050565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613607565b60208082528101612184816138ec565b805161218481612f66565b805161218481612f47565b60005b8381101561395f578181015183820152602001613947565b83811115610ffc5750506000910152565b600061397e61319584613150565b90508281526020810184848401111561399957613999600080fd5b6124da848285613944565b600082601f8301126139b8576139b8600080fd5b81516124b6848260208601613970565b6000604082840312156139dd576139dd600080fd5b6139e76040613139565b905060006139f58484613939565b825250602082015167ffffffffffffffff811115613a1557613a15600080fd5b6136df848285016139a4565b6000613a2f61319584613662565b83815290506020808201908402830185811115613a4e57613a4e600080fd5b835b8181101561375957805167ffffffffffffffff811115613a7257613a72600080fd5b808601613a7f89826139c8565b8552505060209283019201613a50565b600082601f830112613aa357613aa3600080fd5b81516124b6848260208601613a21565b8051612184816132a4565b600060c08284031215613ad357613ad3600080fd5b613add60c0613139565b90506000613aeb848461392e565b825250602082015167ffffffffffffffff811115613b0b57613b0b600080fd5b613b1784828501613a8f565b6020830152506040613b2b84828501613939565b6040830152506060613b3f84828501613ab3565b6060830152506080613b538482850161392e565b60808301525060a061383084828501613ab3565b600060208284031215613b7c57613b7c600080fd5b815167ffffffffffffffff811115613b9657613b96600080fd5b6124b684828501613abe565b634e487b7160e01b600052601160045260246000fd5b600082821015613bca57613bca613ba2565b500390565b6001600160e01b0319811661308f565b60608101613bed82866130a3565b613bfa6020830185613bcf565b6124b66040830184613365565b60408101613c1582856130a3565b61227960208301846130a3565b60c08101613c308289613877565b613c3d6020830188613889565b6138ba6040830187613889565b600781526000602082017f746b696e206d6d0000000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481613c4a565b60c08101613c9c8289613877565b6138ad6020830188613877565b6000613cb683858461317b565b50500190565b60006124b6828486613ca9565b60408101613c158285613bcf565b600060208284031215613cec57613cec600080fd5b60006124b684846130eb565b600381526000602082016206e6f760ec1b81529150613607565b6020808252810161218481613cf8565b60006122793684846136eb565b600060208284031215613d4457613d44600080fd5b60006124b684846132ac565b601281526000602082017f746b696e206e6f206e617469766557726170000000000000000000000000000081529150613607565b6020808252810161218481613d50565b600b81526000602082017f696e7366636e7420616d7400000000000000000000000000000000000000000081529150613607565b6020808252810161218481613d94565b63ffffffff8116612f50565b803561218481613dd8565b6007811061105b57600080fd5b803561218481613def565b60006101c08284031215613e1d57613e1d600080fd5b613e286101c0613139565b90506000613e368484612f5b565b8252506020613e47848483016130eb565b6020830152506040613e5b84828501613de4565b6040830152506060613e6f84828501613dfc565b6060830152506080613e83848285016130eb565b60808301525060a0613e97848285016132ac565b60a08301525060c0613eab848285016132ac565b60c08301525060e0613ebf84828501612f6c565b60e083015250610100613ed484828501612f6c565b6101008301525061012082013567ffffffffffffffff811115613ef957613ef9600080fd5b613f05848285016131c0565b61012083015250610140613f1b84828501612f6c565b61014083015250610160613f3184828501612f5b565b61016083015250610180613f4784828501612f5b565b610180830152506101a0613f5d848285016132ac565b6101a08301525092915050565b60006121843683613e07565b601181526000602082017f6e6f742066656520636f6c6c6563746f7200000000000000000000000000000081529150613607565b6020808252810161218481613f76565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613fe557613fe5600080fd5b60006124b6848461392e565b600060001982141561400557614005613ba2565b5060010190565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015291505b5060400190565b602080825281016121848161400c565b600c81526000602082017f746b206e6f206e6174697665000000000000000000000000000000000000000081529150613607565b6020808252810161218481614079565b602081016121848284613877565b60006121848261359b565b600981526000602082017f73656e64206661696c000000000000000000000000000000000000000000000081529150613607565b60208082528101612184816140d6565b600061218482516001600160e01b03191690565b6000614138825190565b602083016141458161411a565b9250600482101561416c576141676001600160e01b0319836004036008021b90565b831692505b5050919050565b600f81526000602082017f756e737570706f7274656420646578000000000000000000000000000000000081529150613607565b6020808252810161218481614173565b60006141c1825190565b8084526020840193506141d8818560208601613944565b601f01601f19169290920192915050565b805160009060408401906141fd85826130a3565b5060208301518482036020860152610add82826141b7565b6020808252810161227981846141e9565b60008060006060848603121561423e5761423e600080fd5b600061424a868661392e565b935050602061425b86828701613939565b92505060406132fd86828701613939565b600d81526000602082017f746b696e206d69736d617463680000000000000000000000000000000000000081529150613607565b602080825281016121848161426c565b600c81526000602082017f746b6f206d69736d61746368000000000000000000000000000000000000000081529150613607565b60208082528101612184816142b0565b6000821982111561430757614307613ba2565b500190565b6060808252810161431d81866141b7565b905061432c6020830185613877565b6124b660408301846130a3565b60006020828403121561434e5761434e600080fd5b815167ffffffffffffffff81111561436857614368600080fd5b6124b6848285016139a4565b600061437e825190565b61438c818560208601613944565b9290920192915050565b60006122798284614374565b600b81526000602082017f73776170206661696c656400000000000000000000000000000000000000000081529150613607565b60208082528101612184816143a2565b601081526000602082017f616c6c207377617073206661696c65640000000000000000000000000000000081529150613607565b60208082528101612184816143e6565b6060810161443882866130a3565b61444560208301856130a3565b6124b66040830184613877565b600981526000602082017f73776170206661696c000000000000000000000000000000000000000000000081529150613607565b6020808252810161218481614452565b60a081016144a48288613877565b6144b16020830187613877565b6144be60408301866130a3565b6144cb6060830185613877565b6144d860808301846130a3565b9695505050505050565b67ffffffffffffffff811661308f565b60e08101614500828a613877565b61450d6020830189613877565b61451a60408301886144e2565b6145276060830187613877565b61453460808301866130a3565b61454160a08301856130a3565b61454e60c08301846130a3565b98975050505050505050565b6040810161456882856130a3565b6122796020830184613877565b600c81526000602082017f636463206e6f20666f756e64000000000000000000000000000000000000000081529150613607565b6020808252810161218481614575565b60008160001904831182151516156145d3576145d3613ba2565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145fd576145fd6145d8565b500490565b60006020828403121561461757614617600080fd5b60006124b68484613ab3565b602a81526000602082017f5361666545524332303a204552433230206f7065726174696f6e20646964206e81527f6f7420737563636565640000000000000000000000000000000000000000000060208201529150614062565b6020808252810161218481614623565b60006121848260601b90565b60006121848261468d565b61308f6146b082612f36565b614699565b60006121848260c01b90565b61308f67ffffffffffffffff82166146b5565b60006146e082876146a4565b6014820191506146f082866146a4565b60148201915061470082856146c1565b60088201915061471082846146c1565b50600801949350505050565b7f6578656375746f722066656500000000000000000000000000000000000000008152600c01600061474e82896146c1565b60088201915061475e82886146c1565b60088201915061476e8287613877565b60208201915061477e82866146a4565b60148201915061478e8285613877565b60208201915061479e8284613877565b506020019695505050505050565b601181526000602082017f646561646c696e6520657863656564656400000000000000000000000000000081529150613607565b60208082528101612184816147ac565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0160006148228284613877565b50602001919050565b600e81526000602082017f696e76616c6964207369676e657200000000000000000000000000000000000081529150613607565b602080825281016121848161482b565b600061227983836141e9565b6000614885825190565b8084526020840193508360208202850161489f8560200190565b8060005b858110156148d457848403895281516148bc858261486f565b94506020830160209a909a01999250506001016148a3565b5091979650505050505050565b805160009060c08401906148f58582613877565b506020830151848203602086015261490d828261487b565b915050604083015161492260408601826130a3565b5060608301516149356060860182613365565b5060808301516149486080860182613877565b5060a08301516124da60a0860182613365565b6020808252810161227981846148e1565b600061218461359b67ffffffffffffffff841681565b61308f8161496c565b60a0810161499982886130a3565b6149a66020830187614982565b6149b360408301866130a3565b6149c06060830185613877565b81810360808301526138e181846141b7565b602681526000602082017f416464726573733a20696e73756666696369656e742062616c616e636520666f81527f722063616c6c000000000000000000000000000000000000000000000000000060208201529150614062565b60208082528101612184816149d2565b601d81526000602082017f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081529150613607565b6020808252810161218481614a3c565b600060208284031215614a9557614a95600080fd5b60006124b68484613939565b63ffffffff811661308f565b60c08101614abb82896130a3565b614ac860208301886130a3565b614ad56040830187613877565b614ae260608301866144e2565b614aef60808301856144e2565b6138e160a0830184614aa1565b60a08101614b0a82886130a3565b614b176020830187613877565b614b2460408301866144e2565b614b3160608301856130a3565b6144d860808301846144e2565b60808101614b4c82876130a3565b614b596020830186613877565b614b6660408301856130a3565b610add60608301846144e2565b601981526000602082017f6272696467652074797065206e6f7420737570706f727465640000000000000081529150613607565b6020808252810161218481614b73565b6020808252810161227981846141b7565b601881526000602082017f45434453413a20696e76616c6964207369676e6174757265000000000000000081529150613607565b6020808252810161218481614bc8565b601f81526000602082017f45434453413a20696e76616c6964207369676e6174757265206c656e6774680081529150613607565b6020808252810161218481614c0c565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c50565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b60208201529150614062565b6020808252810161218481614c9f565b6000614cfa828a6146a4565b601482019150614d0a82896146a4565b601482019150614d1a82886146a4565b601482019150614d2a8287613877565b602082019150614d3a82866146c1565b600882019150614d4a82856146c1565b600882019150614d5a82846146c1565b50600801979650505050505050565b6000614d75828a6146a4565b601482019150614d8582896146a4565b601482019150614d958288613877565b602082019150614da582876146c1565b600882019150614db582866146a4565b601482019150614d4a82856146c1565b603681526000602082017f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060208201529150614062565b6020808252810161218481614dc5565b6000614e3b82896146a4565b601482019150614e4b82886146a4565b601482019150614e5b8287613877565b602082019150614e6b82866146a4565b601482019150614e7b82856146c1565b600882019150614e8b82846146c1565b506008019695505050505050565b60ff811661308f565b60808101614eb08287613877565b614ebd6020830186614e99565b614eca6040830185613877565b610add606083018461387756fea2646970667358221220eae1c3b25d0ff199671cc0ccdeb5ab9d13b1454bc5f6ee971c30f3211cf9448d64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d80000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000000000000000000000000000000000000000000000000000000000000000002765786368616e676528696e743132382c696e743132382c75696e743235362c75696e743235362900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003265786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e74323536290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c616464726573732900000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000006ece0fbb1ed61ca4186fa5345766dafd5713818d000000000000000000000000b7c24c8c783259c8b870974f549570e58e2c4fdd0000000000000000000000002f3eedc9d0c3bf56d0b0618364257f2dff57c680000000000000000000000000dc6d59423b78cffbdfd7ec2294242e7a00e264480000000000000000000000000000000000000000000000000000000000000008000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7000000000000000000000000d632f22692fac7611d2aa1c0d552930d43caed3b0000000000000000000000005a6a4d54456819380173272a5e8e9b9904bdf41b000000000000000000000000ceaf7747579696a2f0bb206a14210e3c9e6fb269000000000000000000000000a5407eae9ba41422680e2e00537571bcc53efbfd000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca0000000000000000000000004807862aa8b2bf68830e4c8dc86d0e9a998e085a00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000336578616374496e707574282862797465732c616464726573732c75696e743235362c75696e743235362c75696e74323536292900000000000000000000000000000000000000000000000000000000000000000000000000000000000000002765786368616e676528696e743132382c696e743132382c75696e743235362c75696e743235362900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003265786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e74323536290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000000000000000000000000000000000000000000000000000000000000000003a65786368616e67655f756e6465726c79696e6728696e743132382c696e743132382c75696e743235362c75696e743235362c6164647265737329000000000000
-----Decoded View---------------
Arg [0] : _messageBus (address): 0x4066D196A423b2b3B8B054f4F40efB47a74E200C
Arg [1] : _nativeWrap (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _signer (address): 0x26e6eAf3D3C5d4B8290AA7dd896140f383dFf043
Arg [3] : _feeCollector (address): 0xf0761BB438CeFca39A8fd1F27d75ccC7F6Df92d8
Arg [4] : _funcSigs (string[]): exactInput((bytes,address,uint256,uint256,uint256)),exchange(int128,int128,uint256,uint256),exchange_underlying(int128,int128,uint256,uint256),exchange_underlying(int128,int128,uint256,uint256,address)
Arg [5] : _codecs (address[]): 0x6ECe0fbB1ed61CA4186FA5345766DAfD5713818D,0xB7c24C8c783259C8B870974F549570E58e2c4FDd,0x2F3EEDC9d0c3bF56D0b0618364257f2DFF57c680,0xDc6D59423b78cfFBdfD7Ec2294242e7A00e26448
Arg [6] : _supportedDexList (address[]): 0xE592427A0AEce92De3Edee1F18E0157C05861564,0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7,0xd632f22692FaC7611d2AA1C0D552930D43CAEd3B,0x5a6A4D54456819380173272A5E8E9B9904BdF41B,0xCEAF7747579696A2F0bb206a14210e3c9e6fB269,0xA5407eAE9Ba41422680e2e00537571bcC53efBfD,0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA,0x4807862AA8b2bF68830e4C8dc86D0e9A998e085a
Arg [7] : _supportedDexFuncs (string[]): exactInput((bytes,address,uint256,uint256,uint256)),exchange(int128,int128,uint256,uint256),exchange_underlying(int128,int128,uint256,uint256,address),exchange_underlying(int128,int128,uint256,uint256,address),exchange_underlying(int128,int128,uint256,uint256,address),exchange_underlying(int128,int128,uint256,uint256),exchange_underlying(int128,int128,uint256,uint256,address),exchange_underlying(int128,int128,uint256,uint256,address)
-----Encoded View---------------
72 Constructor Arguments found :
Arg [0] : 0000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 00000000000000000000000026e6eaf3d3c5d4b8290aa7dd896140f383dff043
Arg [3] : 000000000000000000000000f0761bb438cefca39a8fd1f27d75ccc7f6df92d8
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000320
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003c0
Arg [7] : 00000000000000000000000000000000000000000000000000000000000004e0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [10] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [12] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000033
Arg [14] : 6578616374496e707574282862797465732c616464726573732c75696e743235
Arg [15] : 362c75696e743235362c75696e74323536292900000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000027
Arg [17] : 65786368616e676528696e743132382c696e743132382c75696e743235362c75
Arg [18] : 696e743235362900000000000000000000000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [20] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [21] : 382c75696e743235362c75696e74323536290000000000000000000000000000
Arg [22] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [23] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [24] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [26] : 0000000000000000000000006ece0fbb1ed61ca4186fa5345766dafd5713818d
Arg [27] : 000000000000000000000000b7c24c8c783259c8b870974f549570e58e2c4fdd
Arg [28] : 0000000000000000000000002f3eedc9d0c3bf56d0b0618364257f2dff57c680
Arg [29] : 000000000000000000000000dc6d59423b78cffbdfd7ec2294242e7a00e26448
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [31] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [32] : 000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7
Arg [33] : 000000000000000000000000d632f22692fac7611d2aa1c0d552930d43caed3b
Arg [34] : 0000000000000000000000005a6a4d54456819380173272a5e8e9b9904bdf41b
Arg [35] : 000000000000000000000000ceaf7747579696a2f0bb206a14210e3c9e6fb269
Arg [36] : 000000000000000000000000a5407eae9ba41422680e2e00537571bcc53efbfd
Arg [37] : 000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca
Arg [38] : 0000000000000000000000004807862aa8b2bf68830e4c8dc86d0e9a998e085a
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [40] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [41] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [42] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [43] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [44] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [45] : 00000000000000000000000000000000000000000000000000000000000002e0
Arg [46] : 0000000000000000000000000000000000000000000000000000000000000340
Arg [47] : 00000000000000000000000000000000000000000000000000000000000003a0
Arg [48] : 0000000000000000000000000000000000000000000000000000000000000033
Arg [49] : 6578616374496e707574282862797465732c616464726573732c75696e743235
Arg [50] : 362c75696e743235362c75696e74323536292900000000000000000000000000
Arg [51] : 0000000000000000000000000000000000000000000000000000000000000027
Arg [52] : 65786368616e676528696e743132382c696e743132382c75696e743235362c75
Arg [53] : 696e743235362900000000000000000000000000000000000000000000000000
Arg [54] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [55] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [56] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Arg [57] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [58] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [59] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Arg [60] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [61] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [62] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Arg [63] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [64] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [65] : 382c75696e743235362c75696e74323536290000000000000000000000000000
Arg [66] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [67] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [68] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Arg [69] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [70] : 65786368616e67655f756e6465726c79696e6728696e743132382c696e743132
Arg [71] : 382c75696e743235362c75696e743235362c6164647265737329000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
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.