Overview
MNT Balance
MNT Value
$0.00Latest 25 from a total of 40 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap And Bridge | 66735806 | 575 days ago | IN | 5 MNT | 0.09393633 | ||||
| Swap And Bridge | 66385213 | 583 days ago | IN | 0 MNT | 0.01595337 | ||||
| Swap And Bridge | 66367497 | 584 days ago | IN | 0 MNT | 0.06104577 | ||||
| Swap And Bridge | 66359628 | 584 days ago | IN | 0 MNT | 0.04300831 | ||||
| Swap And Bridge | 65962664 | 593 days ago | IN | 0 MNT | 0.09194031 | ||||
| Swap And Bridge | 65958244 | 593 days ago | IN | 50 MNT | 0.09366067 | ||||
| Swap And Bridge | 65550965 | 602 days ago | IN | 0 MNT | 0.05079265 | ||||
| Swap And Bridge | 65550933 | 602 days ago | IN | 0 MNT | 0.16134498 | ||||
| Swap And Bridge | 65402406 | 606 days ago | IN | 1 MNT | 0.07512505 | ||||
| Swap And Bridge | 65397398 | 606 days ago | IN | 10 MNT | 0.03368954 | ||||
| Swap And Bridge | 65397139 | 606 days ago | IN | 10 MNT | 0.10506004 | ||||
| Swap And Bridge | 65382749 | 606 days ago | IN | 0 MNT | 0.03329391 | ||||
| Swap And Bridge | 65368736 | 607 days ago | IN | 1 MNT | 0.09318358 | ||||
| Swap And Bridge | 65329791 | 608 days ago | IN | 14 MNT | 0.24929128 | ||||
| Swap And Bridge | 65256627 | 609 days ago | IN | 15 MNT | 0.13335804 | ||||
| Swap And Bridge | 65242245 | 610 days ago | IN | 2 MNT | 0.08719859 | ||||
| Swap And Bridge | 65238438 | 610 days ago | IN | 32 MNT | 0.09654222 | ||||
| Swap And Bridge | 65232152 | 610 days ago | IN | 10 MNT | 0.14759742 | ||||
| Swap And Bridge | 65229738 | 610 days ago | IN | 0 MNT | 0.09506475 | ||||
| Swap And Bridge | 65215187 | 610 days ago | IN | 1 MNT | 0.05617796 | ||||
| Swap And Bridge | 65193961 | 611 days ago | IN | 2 MNT | 0.06144054 | ||||
| Swap And Bridge | 65186529 | 611 days ago | IN | 3 MNT | 0.05737279 | ||||
| Swap And Bridge | 65176452 | 611 days ago | IN | 3 MNT | 0.06666651 | ||||
| Swap And Bridge | 65167771 | 611 days ago | IN | 1 MNT | 0.06953584 | ||||
| Swap And Bridge | 65167359 | 611 days ago | IN | 5 MNT | 0.09240543 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 66850776 | 572 days ago | 18.08601009 MNT | ||||
| 66850776 | 572 days ago | 18.08601009 MNT | ||||
| 66735806 | 575 days ago | 5 MNT | ||||
| 66716327 | 575 days ago | 0.19933495 MNT | ||||
| 66716327 | 575 days ago | 0.19933495 MNT | ||||
| 66695231 | 576 days ago | 1.10011667 MNT | ||||
| 66695231 | 576 days ago | 1.10011667 MNT | ||||
| 66632351 | 577 days ago | 2.96541766 MNT | ||||
| 66632351 | 577 days ago | 2.96541766 MNT | ||||
| 66630526 | 577 days ago | 0.26802279 MNT | ||||
| 66630526 | 577 days ago | 0.26802279 MNT | ||||
| 66627140 | 578 days ago | 2.57819587 MNT | ||||
| 66627140 | 578 days ago | 2.57819587 MNT | ||||
| 66623908 | 578 days ago | 2.80666504 MNT | ||||
| 66623908 | 578 days ago | 2.80666504 MNT | ||||
| 66367497 | 584 days ago | 4.37998049 MNT | ||||
| 66367497 | 584 days ago | 4.37998049 MNT | ||||
| 66359628 | 584 days ago | 1.21768351 MNT | ||||
| 66359628 | 584 days ago | 1.21768351 MNT | ||||
| 65958244 | 593 days ago | 50 MNT | ||||
| 65720920 | 599 days ago | 10 MNT | ||||
| 65720920 | 599 days ago | 10 MNT | ||||
| 65717324 | 599 days ago | 2.81098777 MNT | ||||
| 65717324 | 599 days ago | 2.81098777 MNT | ||||
| 65402406 | 606 days ago | 1 MNT |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@butternetwork/bridge/contracts/interface/IButterMosV2.sol";
import "@butternetwork/bridge/contracts/interface/IButterReceiver.sol";
import "./lib/ErrorMessage.sol";
import "./abstract/Router.sol";
import "./lib/Helper.sol";
contract ButterRouterV2 is Router, ReentrancyGuard, IButterReceiver {
using SafeERC20 for IERC20;
using Address for address;
address public mosAddress;
uint256 public gasForReFund = 80000;
struct BridgeParam {
uint256 toChain;
bytes receiver;
bytes data;
}
event SetMos(address indexed mos);
event SetGasForReFund(uint256 indexed _gasForReFund);
event SwapAndBridge(
bytes32 indexed orderId,
address indexed from,
address indexed originToken,
address bridgeToken,
uint256 originAmount,
uint256 bridgeAmount,
uint256 fromChain,
uint256 toChain,
bytes to
);
event RemoteSwapAndCall(
bytes32 indexed orderId,
address indexed receiver,
address indexed target,
address originToken,
address swapToken,
uint256 originAmount,
uint256 swapAmount,
uint256 callAmount,
uint256 fromChain,
uint256 toChain,
bytes from
);
constructor(address _mosAddress, address _owner, address _wToken) payable Router(_owner, _wToken) {
_setMosAddress(_mosAddress);
}
function swapAndBridge(
address _srcToken,
uint256 _amount,
bytes calldata _swapData,
bytes calldata _bridgeData,
bytes calldata _permitData
) external payable nonReentrant transferIn(_srcToken, _amount, _permitData) {
require(_swapData.length + _bridgeData.length > 0, ErrorMessage.DATA_EMPTY);
SwapTemp memory swapTemp;
swapTemp.srcToken = _srcToken;
swapTemp.srcAmount = _amount;
swapTemp.swapToken = _srcToken;
swapTemp.swapAmount = _amount;
bytes memory receiver;
if (_swapData.length > 0) {
Helper.SwapParam memory swap = abi.decode(_swapData, (Helper.SwapParam));
bool result;
(result, swapTemp.swapToken, swapTemp.swapAmount) = _makeSwap(swapTemp.srcAmount, swapTemp.srcToken, swap);
require(result, ErrorMessage.SWAP_FAIL);
require(swapTemp.swapAmount >= swap.minReturnAmount, ErrorMessage.RECEIVE_LOW);
if (_bridgeData.length == 0 && swapTemp.swapAmount > 0) {
receiver = abi.encodePacked(swap.receiver);
Helper._transfer(selfChainId, swapTemp.swapToken, swap.receiver, swapTemp.swapAmount);
}
}
bytes32 orderId;
if (_bridgeData.length > 0) {
BridgeParam memory bridge = abi.decode(_bridgeData, (BridgeParam));
swapTemp.toChain = bridge.toChain;
receiver = bridge.receiver;
orderId = _doBridge(msg.sender, swapTemp.swapToken, swapTemp.swapAmount, bridge);
}
emit SwapAndBridge(
orderId,
msg.sender,
swapTemp.srcToken,
swapTemp.swapToken,
swapTemp.srcAmount,
swapTemp.swapAmount,
block.chainid,
swapTemp.toChain,
receiver
);
}
function swapAndCall(
bytes32 _transferId,
address _srcToken,
uint256 _amount,
FeeType _feeType,
bytes calldata _swapData,
bytes calldata _callbackData,
bytes calldata _permitData
) external payable nonReentrant transferIn(_srcToken, _amount, _permitData) {
SwapTemp memory swapTemp;
swapTemp.srcToken = _srcToken;
swapTemp.srcAmount = _amount;
swapTemp.transferId = _transferId;
swapTemp.feeType = _feeType;
require(_swapData.length + _callbackData.length > 0, ErrorMessage.DATA_EMPTY);
(, swapTemp.swapAmount) = _collectFee(
swapTemp.srcToken,
swapTemp.srcAmount,
swapTemp.transferId,
swapTemp.feeType
);
(
swapTemp.receiver,
swapTemp.target,
swapTemp.swapToken,
swapTemp.swapAmount,
swapTemp.callAmount
) = _doSwapAndCall(_swapData, _callbackData, swapTemp.srcToken, swapTemp.swapAmount);
if (swapTemp.swapAmount > swapTemp.callAmount) {
Helper._transfer(selfChainId, swapTemp.swapToken, swapTemp.receiver, (swapTemp.swapAmount - swapTemp.callAmount));
}
emit SwapAndCall(
msg.sender,
swapTemp.receiver,
swapTemp.target,
swapTemp.transferId,
swapTemp.srcToken,
swapTemp.swapToken,
swapTemp.srcAmount,
swapTemp.swapAmount,
swapTemp.callAmount
);
}
// _srcToken must erc20 Token or wToken
function onReceived(
bytes32 _orderId,
address _srcToken,
uint256 _amount,
uint256 _fromChain,
bytes calldata _from,
bytes calldata _swapAndCall
) external nonReentrant {
SwapTemp memory swapTemp;
swapTemp.srcToken = _srcToken;
swapTemp.srcAmount = _amount;
swapTemp.swapToken = _srcToken;
swapTemp.swapAmount = _amount;
swapTemp.fromChain = _fromChain;
swapTemp.toChain = block.chainid;
swapTemp.from = _from;
nativeBalanceBeforeExec = address(this).balance;
require(msg.sender == mosAddress, ErrorMessage.MOS_ONLY);
require(Helper._getBalance(swapTemp.srcToken, address(this)) >= _amount, ErrorMessage.RECEIVE_LOW);
(bytes memory _swapData, bytes memory _callbackData) = abi.decode(_swapAndCall, (bytes, bytes));
require(_swapData.length + _callbackData.length > 0, ErrorMessage.DATA_EMPTY);
bool result = true;
uint256 minExecGas = gasForReFund * 2;
if (_swapData.length > 0) {
Helper.SwapParam memory swap = abi.decode(_swapData, (Helper.SwapParam));
swapTemp.receiver = swap.receiver;
if (gasleft() > minExecGas) {
try
this.doRemoteSwap{gas: gasleft() - gasForReFund}(swap, swapTemp.srcToken, swapTemp.srcAmount)
returns (address target, address dstToken, uint256 dstAmount) {
swapTemp.swapToken = dstToken;
swapTemp.target = target;
swapTemp.swapAmount = dstAmount;
} catch {
result = false;
}
}
}
if (_callbackData.length > 0) {
Helper.CallbackParam memory callParam = abi.decode(_callbackData, (Helper.CallbackParam));
if (swapTemp.receiver == address(0)) {
swapTemp.receiver = callParam.receiver;
}
if (result && gasleft() > minExecGas) {
try
this.doRemoteCall{gas: gasleft() - gasForReFund}(callParam, swapTemp.swapToken, swapTemp.swapAmount)
returns (address target, uint256 callAmount) {
swapTemp.target = target;
swapTemp.callAmount = callAmount;
swapTemp.receiver = callParam.receiver;
} catch {}
}
}
if (swapTemp.swapAmount > swapTemp.callAmount) {
Helper._transfer(selfChainId, swapTemp.swapToken, swapTemp.receiver, (swapTemp.swapAmount - swapTemp.callAmount));
}
emit RemoteSwapAndCall(
_orderId,
swapTemp.receiver,
swapTemp.target,
swapTemp.srcToken,
swapTemp.swapToken,
swapTemp.srcAmount,
swapTemp.swapAmount,
swapTemp.callAmount,
swapTemp.fromChain,
swapTemp.toChain,
swapTemp.from
);
}
function doRemoteSwap(
Helper.SwapParam memory _swap,
address _srcToken,
uint256 _amount
) external returns (address target, address dstToken, uint256 dstAmount) {
require(msg.sender == address(this));
bool result;
(result, dstToken, dstAmount) = _makeSwap(_amount, _srcToken, _swap);
require(result, ErrorMessage.SWAP_FAIL);
require(dstAmount >= _swap.minReturnAmount, ErrorMessage.RECEIVE_LOW);
target = _swap.executor;
}
function doRemoteCall(
Helper.CallbackParam memory _callParam,
address _callToken,
uint256 _amount
) external returns (address target, uint256 callAmount) {
require(msg.sender == address(this));
bool result;
(result, callAmount) = _callBack(_amount, _callToken, _callParam);
require(result, ErrorMessage.CALL_FAIL);
target = _callParam.target;
}
function _doBridge(
address _sender,
address _token,
uint256 _value,
BridgeParam memory _bridge
) internal returns (bytes32 _orderId) {
if (Helper._isNative(_token)) {
_orderId = IButterMosV2(mosAddress).swapOutNative{value: _value}(
_sender,
_bridge.receiver,
_bridge.toChain,
_bridge.data
);
} else {
IERC20(_token).safeApprove(mosAddress, _value);
_orderId = IButterMosV2(mosAddress).swapOutToken(
_sender,
_token,
_bridge.receiver,
_value,
_bridge.toChain,
_bridge.data
);
}
}
function setGasForReFund(uint256 _gasForReFund) external onlyOwner {
gasForReFund = _gasForReFund;
emit SetGasForReFund(_gasForReFund);
}
function setMosAddress(address _mosAddress) public onlyOwner returns (bool) {
_setMosAddress(_mosAddress);
return true;
}
function _setMosAddress(address _mosAddress) internal returns (bool) {
require(_mosAddress.isContract(), ErrorMessage.NOT_CONTRACT);
mosAddress = _mosAddress;
emit SetMos(_mosAddress);
return true;
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IButterMosV2 {
function swapOutToken(
address _sender,
address _token, // src token
bytes memory _to,
uint256 _amount,
uint256 _toChain, // target chain id
bytes calldata _swapData
) external returns (bytes32 orderId);
function swapOutNative(
address _sender,
bytes memory _to,
uint256 _toChain, // target chain id
bytes calldata _swapData
) external payable returns (bytes32 orderId);
function depositToken(address _token, address to, uint256 _amount) external;
function depositNative(address _to) external payable;
event SetButterRouterAddress(address indexed _newRouter);
event mapTransferOut(
uint256 indexed fromChain,
uint256 indexed toChain,
bytes32 orderId,
bytes token,
bytes from,
bytes to,
uint256 amount,
bytes toChainToken
);
event mapDepositOut(
uint256 indexed fromChain,
uint256 indexed toChain,
bytes32 orderId,
address token,
bytes from,
address to,
uint256 amount
);
event mapSwapOut(
uint256 indexed fromChain, // from chain
uint256 indexed toChain, // to chain
bytes32 orderId, // order id
bytes token, // token to transfer
bytes from, // source chain from address
bytes to,
uint256 amount,
bytes swapData // swap data, used on target chain dex.
);
event mapSwapIn(
uint256 indexed fromChain,
uint256 indexed toChain,
bytes32 indexed orderId,
address token,
bytes from,
address toAddress,
uint256 amountOut
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IButterReceiver {
//_srcToken received token (wtoken or erc20 token)
function onReceived(
bytes32 _orderId,
address _srcToken,
uint256 _amount,
uint256 _fromChain,
bytes calldata _from,
bytes calldata _payload
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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 Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling 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 (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides 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} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./IERC20Permit.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.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;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
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));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// 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 cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-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/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: UNLICENSED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../lib/ErrorMessage.sol";
import "../lib/Helper.sol";
abstract contract Router is Ownable2Step {
using SafeERC20 for IERC20;
using Address for address;
uint256 public feeRate;
uint256 public fixedFee;
address public feeReceiver;
address internal immutable wToken;
uint256 internal nativeBalanceBeforeExec;
uint256 private constant FEE_DENOMINATOR = 1000000;
mapping(address => bool) public approved;
uint256 public immutable selfChainId = block.chainid;
event Approve(address indexed executor, bool indexed flag);
event SetFee(address indexed receiver, uint256 indexed rate, uint256 indexed fixedf);
event CollectFee(
address indexed token,
address indexed receiver,
uint256 indexed amount,
bytes32 transferId,
FeeType feeType
);
enum FeeType {
FIXED,
PROPORTION
}
// use to solve deep stack
struct SwapTemp {
address srcToken;
address swapToken;
uint256 srcAmount;
uint256 swapAmount;
bytes32 transferId;
address receiver;
address target;
uint256 callAmount;
uint256 fromChain;
uint256 toChain;
bytes from;
FeeType feeType;
}
event SwapAndCall(
address indexed from,
address indexed receiver,
address indexed target,
bytes32 transferId,
address originToken,
address swapToken,
uint256 originAmount,
uint256 swapAmount,
uint256 callAmount
);
modifier transferIn(
address token,
uint256 amount,
bytes memory permitData
) {
require(amount > 0, ErrorMessage.ZERO_IN);
if (permitData.length > 0) {
Helper._permit(permitData);
}
nativeBalanceBeforeExec = address(this).balance - msg.value;
if (Helper._isNative(token)) {
require(msg.value >= amount, ErrorMessage.FEE_MISMATCH);
} else {
SafeERC20.safeTransferFrom(IERC20(token), msg.sender, address(this), amount);
}
_;
nativeBalanceBeforeExec = 0;
}
constructor(address _owner, address _wToken) payable {
require(_owner != Helper.ZERO_ADDRESS, ErrorMessage.ZERO_ADDR);
require(_wToken.isContract(), ErrorMessage.NOT_CONTRACT);
wToken = _wToken;
_transferOwnership(_owner);
}
function _doSwapAndCall(
bytes memory _swapData,
bytes memory _callbackData,
address _srcToken,
uint256 _amount
) internal returns (address receiver, address target, address dstToken, uint256 swapOutAmount, uint256 callAmount) {
bool result;
swapOutAmount = _amount;
dstToken = _srcToken;
if (_swapData.length > 0) {
Helper.SwapParam memory swap = abi.decode(_swapData, (Helper.SwapParam));
(result, dstToken, swapOutAmount) = _makeSwap(_amount, _srcToken, swap);
require(result, ErrorMessage.SWAP_FAIL);
require(swapOutAmount >= swap.minReturnAmount, ErrorMessage.RECEIVE_LOW);
receiver = swap.receiver;
target = swap.executor;
}
if (_callbackData.length > 0) {
Helper.CallbackParam memory callParam = abi.decode(_callbackData, (Helper.CallbackParam));
(result, callAmount) = _callBack(swapOutAmount, dstToken, callParam);
require(result, ErrorMessage.CALL_FAIL);
receiver = callParam.receiver;
target = callParam.target;
}
}
function setFee(address _feeReceiver, uint256 _feeRate, uint256 _fixedFee) external onlyOwner {
require(_feeReceiver != Helper.ZERO_ADDRESS, ErrorMessage.ZERO_ADDR);
require(_feeRate < FEE_DENOMINATOR);
feeReceiver = _feeReceiver;
feeRate = _feeRate;
fixedFee = _fixedFee;
emit SetFee(_feeReceiver, _feeRate, fixedFee);
}
function getFee(
uint256 _amount,
address _token,
FeeType _feeType
) external view returns (address _feeReceiver, address _feeToken, uint256 _fee, uint256 _feeAfter) {
if (feeReceiver == Helper.ZERO_ADDRESS) {
return (Helper.ZERO_ADDRESS, Helper.ZERO_ADDRESS, 0, _amount);
}
if (_feeType == FeeType.FIXED) {
_feeToken = Helper.ZERO_ADDRESS;
_fee = fixedFee;
if (!Helper._isNative(_token)) {
_feeAfter = _amount;
} else {
_feeAfter = _amount - _fee;
}
} else {
_feeToken = _token;
_fee = (_amount * feeRate) / FEE_DENOMINATOR;
_feeAfter = _amount - _fee;
}
_feeReceiver = feeReceiver;
}
function getInputBeforeFee(
uint256 _amountAfterFee,
address _token,
FeeType _feeType
) external view returns (uint256 _input, address _feeReceiver, address _feeToken, uint256 _fee) {
if (feeReceiver == Helper.ZERO_ADDRESS) {
return (_amountAfterFee, Helper.ZERO_ADDRESS, Helper.ZERO_ADDRESS, 0);
}
if (_feeType == FeeType.FIXED) {
_feeToken = Helper.ZERO_ADDRESS;
_fee = fixedFee;
if (!Helper._isNative(_token)) {
_input = _amountAfterFee;
} else {
_input = _amountAfterFee + _fee;
}
} else {
_feeToken = _token;
_input = (_amountAfterFee * FEE_DENOMINATOR) / (FEE_DENOMINATOR - feeRate) + 1;
_fee = _input - _amountAfterFee;
}
_feeReceiver = feeReceiver;
}
function _collectFee(
address _token,
uint256 _amount,
bytes32 transferId,
FeeType _feeType
) internal returns (uint256 _fee, uint256 _remain) {
if (feeReceiver == Helper.ZERO_ADDRESS) {
_remain = _amount;
return (_fee, _remain);
}
if (_feeType == FeeType.FIXED) {
_fee = fixedFee;
if (Helper._isNative(_token)) {
require(msg.value > fixedFee, ErrorMessage.FEE_LOWER);
_remain = _amount - _fee;
} else {
require(msg.value >= fixedFee, ErrorMessage.FEE_MISMATCH);
_remain = _amount;
}
_token = Helper.NATIVE_ADDRESS;
} else {
_fee = (_amount * feeRate) / FEE_DENOMINATOR;
_remain = _amount - _fee;
}
if (_fee > 0) {
Helper._transfer(selfChainId, _token, feeReceiver, _fee);
emit CollectFee(_token, feeReceiver, _fee, transferId, _feeType);
}
}
function _callBack(
uint256 _amount,
address _token,
Helper.CallbackParam memory _callParam
) internal returns (bool _result, uint256 _callAmount) {
require(approved[_callParam.target], ErrorMessage.NO_APPROVE);
(_result, _callAmount) = Helper._callBack(_amount, _token, _callParam);
require(address(this).balance >= nativeBalanceBeforeExec, ErrorMessage.NATIVE_VALUE_OVERSPEND);
}
function _makeSwap(
uint256 _amount,
address _srcToken,
Helper.SwapParam memory _swap
) internal returns (bool _result, address _dstToken, uint256 _returnAmount) {
require(approved[_swap.executor] || _swap.executor == wToken, ErrorMessage.NO_APPROVE);
if (_swap.executor == wToken) {
bytes4 sig = Helper._getFirst4Bytes(_swap.data);
//0x2e1a7d4d -> withdraw(uint256 wad) 0xd0e30db0 -> deposit()
if (sig != bytes4(0x2e1a7d4d) && sig != bytes4(0xd0e30db0)) {
return (false, _srcToken, 0);
}
}
(_result, _dstToken, _returnAmount) = Helper._makeSwap(_amount, _srcToken, _swap);
}
function setAuthorization(address[] calldata _executors, bool _flag) external onlyOwner {
require(_executors.length > 0, ErrorMessage.DATA_EMPTY);
for (uint i = 0; i < _executors.length; i++) {
require(_executors[i].isContract(), ErrorMessage.NOT_CONTRACT);
approved[_executors[i]] = _flag;
emit Approve(_executors[i], _flag);
}
}
function rescueFunds(address _token, uint256 _amount) external onlyOwner {
Helper._transfer(selfChainId, _token, msg.sender, _amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
library ErrorMessage {
string internal constant ZERO_IN = "ButterRouterV2: zero in";
string internal constant FEE_MISMATCH = "ButterRouterV2: fee mismatch";
string internal constant FEE_LOWER = "ButterRouterV2: lower than fee";
string internal constant ZERO_ADDR = "ButterRouterV2: zero addr";
string internal constant NOT_CONTRACT = "ButterRouterV2: not contract";
string internal constant BRIDGE_REQUIRE = "ButterRouterV2: bridge data required";
string internal constant RECEIVE_LOW = "ButterRouterV2: receive too low";
string internal constant SWAP_FAIL = "ButterRouterV2: swap failed";
string internal constant SWAP_REQUIRE = "ButterRouterV2: swap data required";
string internal constant CALL_AMOUNT_INVALID = "ButterRouterV2: callback amount invalid";
string internal constant CALL_FAIL = "ButterRouterV2: callback failed";
string internal constant MOS_ONLY = "ButterRouterV2: mos only";
string internal constant DATA_EMPTY = "ButterRouterV2: data empty";
string internal constant NO_APPROVE = "ButterRouterV2: not approved";
string internal constant NATIVE_VALUE_OVERSPEND = "ButterRouterV2: native value overspend";
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
library Helper {
using SafeERC20 for IERC20;
address internal constant ZERO_ADDRESS = address(0);
address internal constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
struct CallbackParam {
address target;
address approveTo;
uint256 offset;
uint256 extraNativeAmount;
address receiver;
bytes data;
}
struct SwapParam {
uint8 dexType;
address executor;
address approveTo;
address receiver;
address dstToken;
uint256 minReturnAmount;
bytes data;
}
function _isNative(address token) internal pure returns (bool) {
return (token == ZERO_ADDRESS || token == NATIVE_ADDRESS);
}
function _getBalance(address _token, address _account) internal view returns (uint256) {
if (_isNative(_token)) {
return _account.balance;
} else {
return IERC20(_token).balanceOf(_account);
}
}
function _transfer(uint256 _chainId, address _token, address _to, uint256 _amount) internal {
if (_isNative(_token)) {
Address.sendValue(payable(_to), _amount);
} else {
if (_chainId == 728126428 && _token == 0xa614f803B6FD780986A42c78Ec9c7f77e6DeD13C) {
// Tron USDT
_token.call(abi.encodeWithSelector(0xa9059cbb, _to, _amount));
} else {
IERC20(_token).safeTransfer(_to, _amount);
}
}
}
function _safeWithdraw(address _wToken, uint _value) internal returns (bool) {
(bool success, bytes memory data) = _wToken.call(abi.encodeWithSelector(0x2e1a7d4d, _value));
return (success && (data.length == 0 || abi.decode(data, (bool))));
}
function _getFirst4Bytes(bytes memory data) internal pure returns (bytes4 outBytes4) {
if (data.length == 0) {
return 0x0;
}
assembly {
outBytes4 := mload(add(data, 32))
}
}
function _makeSwap(
uint256 _amount,
address _srcToken,
SwapParam memory _swap
) internal returns (bool _result, address _dstToken, uint256 _returnAmount) {
_dstToken = _swap.dstToken;
uint256 nativeValue = 0;
bool isNative = Helper._isNative(_srcToken);
if (isNative) {
nativeValue = _amount;
} else {
IERC20(_srcToken).safeApprove(_swap.approveTo, 0);
IERC20(_srcToken).safeApprove(_swap.approveTo, _amount);
}
_returnAmount = Helper._getBalance(_dstToken, address(this));
(_result, ) = _swap.executor.call{value: nativeValue}(_swap.data);
_returnAmount = Helper._getBalance(_dstToken, address(this)) - _returnAmount;
if (!isNative) {
IERC20(_srcToken).safeApprove(_swap.approveTo, 0);
}
}
function _callBack(
uint256 _amount,
address _token,
CallbackParam memory _callParam
) internal returns (bool _result, uint256 _callAmount) {
_callAmount = Helper._getBalance(_token, address(this));
uint256 offset = _callParam.offset;
bytes memory callDatas = _callParam.data;
if (offset != 0) {
assembly {
mstore(add(callDatas, offset), _amount)
}
}
if (Helper._isNative(_token)) {
(_result, ) = _callParam.target.call{value: _amount}(callDatas);
} else {
if (_amount != 0) IERC20(_token).safeIncreaseAllowance(_callParam.approveTo, _amount);
// this contract not save money make sure send value can cover this
(_result, ) = _callParam.target.call{value: _callParam.extraNativeAmount}(callDatas);
if (_amount != 0) IERC20(_token).safeApprove(_callParam.approveTo, 0);
}
_callAmount = _callAmount - Helper._getBalance(_token, address(this));
}
function _permit(bytes memory _data) internal {
(
address token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) = abi.decode(_data, (address, address, address, uint256, uint256, uint8, bytes32, bytes32));
SafeERC20.safePermit(IERC20Permit(token), owner, spender, value, deadline, v, r, s);
}
}{
"evmVersion": "london",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_mosAddress","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_wToken","type":"address"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"bool","name":"flag","type":"bool"}],"name":"Approve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"enum Router.FeeType","name":"feeType","type":"uint8"}],"name":"CollectFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"swapToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChain","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"from","type":"bytes"}],"name":"RemoteSwapAndCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"fixedf","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_gasForReFund","type":"uint256"}],"name":"SetGasForReFund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"mos","type":"address"}],"name":"SetMos","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"bridgeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChain","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"to","type":"bytes"}],"name":"SwapAndBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"swapToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callAmount","type":"uint256"}],"name":"SwapAndCall","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"extraNativeAmount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Helper.CallbackParam","name":"_callParam","type":"tuple"},{"internalType":"address","name":"_callToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"doRemoteCall","outputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"callAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"dexType","type":"uint8"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Helper.SwapParam","name":"_swap","type":"tuple"},{"internalType":"address","name":"_srcToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"doRemoteSwap","outputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"uint256","name":"dstAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fixedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasForReFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"enum Router.FeeType","name":"_feeType","type":"uint8"}],"name":"getFee","outputs":[{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"address","name":"_feeToken","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_feeAfter","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountAfterFee","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"enum Router.FeeType","name":"_feeType","type":"uint8"}],"name":"getInputBeforeFee","outputs":[{"internalType":"uint256","name":"_input","type":"uint256"},{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"address","name":"_feeToken","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mosAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"address","name":"_srcToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fromChain","type":"uint256"},{"internalType":"bytes","name":"_from","type":"bytes"},{"internalType":"bytes","name":"_swapAndCall","type":"bytes"}],"name":"onReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"selfChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_executors","type":"address[]"},{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"uint256","name":"_feeRate","type":"uint256"},{"internalType":"uint256","name":"_fixedFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasForReFund","type":"uint256"}],"name":"setGasForReFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mosAddress","type":"address"}],"name":"setMosAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_srcToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_swapData","type":"bytes"},{"internalType":"bytes","name":"_bridgeData","type":"bytes"},{"internalType":"bytes","name":"_permitData","type":"bytes"}],"name":"swapAndBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_transferId","type":"bytes32"},{"internalType":"address","name":"_srcToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"enum Router.FeeType","name":"_feeType","type":"uint8"},{"internalType":"bytes","name":"_swapData","type":"bytes"},{"internalType":"bytes","name":"_callbackData","type":"bytes"},{"internalType":"bytes","name":"_permitData","type":"bytes"}],"name":"swapAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c06040524660a09081525062013880600955604051620040803803806200408083398101604081905262000034916200027e565b818162000041336200013d565b60408051808201909152601981527f427574746572526f7574657256323a207a65726f20616464720000000000000060208201526001600160a01b038316620000a85760405162461bcd60e51b81526004016200009f9190620002c8565b60405180910390fd5b5060408051808201909152601c81527f427574746572526f7574657256323a206e6f7420636f6e74726163740000000060208201526001600160a01b0382163b620001085760405162461bcd60e51b81526004016200009f9190620002c8565b506001600160a01b03811660805262000121826200013d565b5050600160075562000133836200015b565b5050505062000318565b600180546001600160a01b0319169055620001588162000211565b50565b60006001600160a01b0382163b15156040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420636f6e74726163740000000081525090620001c15760405162461bcd60e51b81526004016200009f9190620002c8565b50600880546001600160a01b0319166001600160a01b0384169081179091556040517ff43456bb773c1af890fa668fc6aabe2ea4c3141afd9e1c679f2a7d62b5a33d1790600090a2506001919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200027957600080fd5b919050565b6000806000606084860312156200029457600080fd5b6200029f8462000261565b9250620002af6020850162000261565b9150620002bf6040850162000261565b90509250925092565b600060208083528351808285015260005b81811015620002f757858101830151858201604001528201620002d9565b506000604082860101526040601f19601f8301168501019250505092915050565b60805160a051613d1862000368600039600081816103b6015281816108d001528181610d7e01528181610f5201528181611526015261211b015260008181611c4a0152611cd90152613d186000f3fe60806040526004361061014f5760003560e01c806391792d5b116100b6578063d904371e1161006f578063d904371e14610408578063e30c397814610428578063ecc847d314610446578063f2fde38b14610459578063f78f24a714610479578063f848a574146104c457600080fd5b806391792d5b14610338578063978bbdb91461034e578063b3f0067414610364578063c1b1660e14610384578063cc9e3e89146103a4578063d8b964e6146103d857600080fd5b80635dc4ba08116101085780635dc4ba0814610259578063715018a61461029857806378e3214f146102ad57806379ba5097146102cd5780638cbafe0a146102e25780638da5cb5b1461031a57600080fd5b80632344e6551461015b5780632b8b7b4b1461017d578063451559a9146101b2578063480a3411146102025780634e36b11c14610215578063536f4cfe1461023957600080fd5b3661015657005b600080fd5b34801561016757600080fd5b5061017b610176366004612e11565b61050a565b005b34801561018957600080fd5b5061019d610198366004612eaf565b6109b0565b60405190151581526020015b60405180910390f35b3480156101be57600080fd5b506101d26101cd366004612ee2565b6109ce565b6040516101a994939291909384526001600160a01b03928316602085015291166040830152606082015260800190565b61017b610210366004612f20565b610a9b565b34801561022157600080fd5b5061022b60095481565b6040519081526020016101a9565b34801561024557600080fd5b5061017b610254366004612fb4565b610e77565b34801561026557600080fd5b506102796102743660046130da565b610eb2565b604080516001600160a01b0390931683526020830191909152016101a9565b3480156102a457600080fd5b5061017b610f31565b3480156102b957600080fd5b5061017b6102c83660046131b0565b610f45565b3480156102d957600080fd5b5061017b610f7d565b3480156102ee57600080fd5b50600854610302906001600160a01b031681565b6040516001600160a01b0390911681526020016101a9565b34801561032657600080fd5b506000546001600160a01b0316610302565b34801561034457600080fd5b5061022b60035481565b34801561035a57600080fd5b5061022b60025481565b34801561037057600080fd5b50600454610302906001600160a01b031681565b34801561039057600080fd5b5061017b61039f3660046131dc565b610ff7565b3480156103b057600080fd5b5061022b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e457600080fd5b5061019d6103f3366004612eaf565b60066020526000908152604090205460ff1681565b34801561041457600080fd5b5061017b61042336600461321f565b6110c4565b34801561043457600080fd5b506001546001600160a01b0316610302565b61017b6104543660046132a4565b611280565b34801561046557600080fd5b5061017b610474366004612eaf565b61162c565b34801561048557600080fd5b50610499610494366004612ee2565b61169d565b604080516001600160a01b0395861681529490931660208501529183015260608201526080016101a9565b3480156104d057600080fd5b506104e46104df366004613436565b611753565b604080516001600160a01b039485168152939092166020840152908201526060016101a9565b610512611827565b61051a612d48565b6001600160a01b0388168082526040808301899052602080840192909252606083018990526101008301889052466101208401528051601f87018390048302810183019091528581529086908690819084018382808284376000920191909152505050506101408201524760055560085460408051808201909152601881527f427574746572526f7574657256323a206d6f73206f6e6c7900000000000000006020820152906001600160a01b031633146105f15760405162461bcd60e51b81526004016105e891906134df565b60405180910390fd5b5086610601826000015130611880565b10156040518060400160405280601f8152602001600080516020613cc3833981519152815250906106455760405162461bcd60e51b81526004016105e891906134df565b50600080610655848601866134f2565b91509150600081518351610669919061356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b815250906106bb5760405162461bcd60e51b81526004016105e891906134df565b506009546001906000906106d090600261357e565b8451909150156107bb576000848060200190518101906106f091906135f0565b60608101516001600160a01b031660a08801529050815a11156107b957306001600160a01b031663f848a5746009545a61072a91906136bb565b8389600001518a604001516040518563ffffffff1660e01b8152600401610753939291906136ce565b60606040518083038160008887f19350505050801561078f575060408051601f3d908101601f1916820190925261078c91810190613779565b60015b61079c57600092506107b9565b6001600160a01b0391821660208a0152911660c088015260608701525b505b8251156108bb576000838060200190518101906107d891906137bc565b60a08701519091506001600160a01b03166108015760808101516001600160a01b031660a08701525b82801561080d5750815a115b156108b957306001600160a01b0316635dc4ba086009545a61082f91906136bb565b8389602001518a606001516040518563ffffffff1660e01b815260040161085893929190613877565b604080518083038160008887f193505050508015610893575060408051601f3d908101601f19168201909252610890918101906138e8565b60015b156108b9576001600160a01b0391821660c089015260e088015260808201511660a08701525b505b8460e0015185606001511115610912576109127f000000000000000000000000000000000000000000000000000000000000000086602001518760a001518860e00151896060015161090d91906136bb565b611914565b8460c001516001600160a01b03168560a001516001600160a01b03168e7f593e4dbcb8f7312fc3bdd77e2095da131a6e1993f37752d12576d04e1f7253b4886000015189602001518a604001518b606001518c60e001518d61010001518e61012001518f610140015160405161098f989796959493929190613916565b60405180910390a450505050506109a66001600755565b5050505050505050565b60006109ba611a21565b6109c382611a7b565b50600190505b919050565b6004546000908190819081906001600160a01b03166109f857508592506000915081905080610a92565b6000856001811115610a0c57610a0c61396f565b03610a3f575050600354600090610a2286611b2e565b610a2e57869350610a83565b610a38818861356b565b9350610a83565b600254869250610a5290620f42406136bb565b610a5f620f42408961357e565b610a699190613985565b610a7490600161356b565b9350610a8087856136bb565b90505b6004546001600160a01b031692505b93509350935093565b610aa3611827565b878783838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526017815276213aba3a32b92937baba32b92b191d103d32b9379034b760491b602082015291505082610b285760405162461bcd60e51b81526004016105e891906134df565b50805115610b3957610b3981611b67565b610b4334476136bb565b600555610b4f83611b2e565b15610bb257813410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d617463680000000081525090610bac5760405162461bcd60e51b81526004016105e891906134df565b50610bbe565b610bbe83333085611bb2565b6000610bca878a61356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b81525090610c1c5760405162461bcd60e51b81526004016105e891906134df565b50610c25612d48565b6001600160a01b038c16808252604082018c9052602082015260608082018c90528915610db4576000610c5a8b8d018d6139a7565b90506000610c718460400151856000015184611c1d565b60608701526001600160a01b031660208087019190915260408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c656400000000009181019190915290915081610cdf5760405162461bcd60e51b81526004016105e891906134df565b508160a00151846060015110156040518060400160405280601f8152602001600080516020613cc383398151915281525090610d2e5760405162461bcd60e51b81526004016105e891906134df565b5089158015610d41575060008460600151115b15610db157606082810151604051911b6bffffffffffffffffffffffff191660208201526034016040516020818303038152906040529250610db17f0000000000000000000000000000000000000000000000000000000000000000856020015184606001518760600151611914565b50505b60008815610df7576000610dca8a8c018c6139db565b8051610120860152602080820151908601516060870151919550919250610df391339184611d8b565b9150505b82600001516001600160a01b0316336001600160a01b0316827f140fc1ae4910fc65859bbe978cf17402f862c5bd87a15aa3a0894d5aa50b0b06866020015187604001518860600151468a61012001518a604051610e5a96959493929190613a8b565b60405180910390a450506000600555506109a69250611a1a915050565b610e7f611a21565b600981905560405181907ff47543a7cab136b12cca0a2ecd728c9d1943f57b923b98db48725d2b76dd4da990600090a250565b600080333014610ec157600080fd5b6000610ece848688611ecd565b60408051808201909152601f81527f427574746572526f7574657256323a2063616c6c6261636b206661696c656400602082015290935090915081610f265760405162461bcd60e51b81526004016105e891906134df565b505093519492505050565b610f39611a21565b610f436000611f9a565b565b610f4d611a21565b610f797f0000000000000000000000000000000000000000000000000000000000000000833384611914565b5050565b60015433906001600160a01b03168114610feb5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105e8565b610ff481611f9a565b50565b610fff611a21565b60408051808201909152601981527f427574746572526f7574657256323a207a65726f20616464720000000000000060208201526001600160a01b03841661105a5760405162461bcd60e51b81526004016105e891906134df565b50620f4240821061106a57600080fd5b600480546001600160a01b0319166001600160a01b03851690811790915560028390556003829055604051829184917f17906aa05b055ced1cea92b104912638c3ec8c90eec152fca6f36fbd8becca1d90600090a4505050565b6110cc611a21565b60408051808201909152601a815279427574746572526f7574657256323a206461746120656d70747960301b60208201528261111b5760405162461bcd60e51b81526004016105e891906134df565b5060005b8281101561127a5761116084848381811061113c5761113c613ad0565b90506020020160208101906111519190612eaf565b6001600160a01b03163b151590565b6040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420636f6e747261637400000000815250906111b45760405162461bcd60e51b81526004016105e891906134df565b5081600660008686858181106111cc576111cc613ad0565b90506020020160208101906111e19190612eaf565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905581151584848381811061121e5761121e613ad0565b90506020020160208101906112339190612eaf565b6001600160a01b03167f1f478f1e5aee36a892d86e821aba410dc0934cb0ebd0241dd75370833884545360405160405180910390a38061127281613ae6565b91505061111f565b50505050565b611288611827565b888883838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526017815276213aba3a32b92937baba32b92b191d103d32b9379034b760491b60208201529150508261130d5760405162461bcd60e51b81526004016105e891906134df565b5080511561131e5761131e81611b67565b61132834476136bb565b60055561133483611b2e565b1561139757813410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d6174636800000000815250906113915760405162461bcd60e51b81526004016105e891906134df565b506113a3565b6113a383333085611bb2565b6113ab612d48565b6001600160a01b038d168152604081018c9052608081018e905261016081018b60018111156113dc576113dc61396f565b908160018111156113ef576113ef61396f565b90525060006113fe888b61356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b815250906114505760405162461bcd60e51b81526004016105e891906134df565b5061146e816000015182604001518360800151846101600151611fb3565b606083015250604080516020601f8c018190048102820181019092528a81526114ee918c908c908190840183828082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b9081908401838280828437600092019190915250508551606087015190925090506121a5565b60e08601819052606086018290526001600160a01b03928316602087015292821660c0860152921660a08401521015611563576115637f000000000000000000000000000000000000000000000000000000000000000082602001518360a001518460e00151856060015161090d91906136bb565b8060c001516001600160a01b03168160a001516001600160a01b0316336001600160a01b03167f54592234b1278d8a9675f22721443e0b9f8a1f4410b55bf6753330073b55e3ef846080015185600001518660200151876040015188606001518960e00151604051611609969594939291909586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450506000600555505060016007555b50505050505050505050565b611634611a21565b600180546001600160a01b0383166001600160a01b031990911681179091556116656000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6004546000908190819081906001600160a01b03166116c757506000925082915081905085610a92565b60008560018111156116db576116db61396f565b0361170e576000925060035491506116f286611b2e565b6116fd57508561173c565b61170782886136bb565b905061173c565b859250620f424060025488611723919061357e565b61172d9190613985565b915061173982886136bb565b90505b6004546001600160a01b0316935093509350935093565b6000808033301461176357600080fd5b6000611770858789611c1d565b60408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c6564000000000060208201529195509350909150816117ca5760405162461bcd60e51b81526004016105e891906134df565b508660a001518210156040518060400160405280601f8152602001600080516020613cc3833981519152815250906118155760405162461bcd60e51b81526004016105e891906134df565b50866020015193505093509350939050565b6002600754036118795760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105e8565b6002600755565b600061188b83611b2e565b156118a157506001600160a01b0381163161190e565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156118e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190b9190613aff565b90505b92915050565b61191d83611b2e565b156119315761192c828261232e565b61127a565b83632b6653dc148015611960575073a614f803b6fd780986a42c78ec9c7f77e6ded13c6001600160a01b038416145b15611a0657604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151918516916119bc9190613b18565b6000604051808303816000865af19150503d80600081146119f9576040519150601f19603f3d011682016040523d82523d6000602084013e6119fe565b606091505b50505061127a565b61127a6001600160a01b038416838361244c565b6001600755565b6000546001600160a01b03163314610f435760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105e8565b60006001600160a01b0382163b15156040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420636f6e74726163740000000081525090611ade5760405162461bcd60e51b81526004016105e891906134df565b50600880546001600160a01b0319166001600160a01b0384169081179091556040517ff43456bb773c1af890fa668fc6aabe2ea4c3141afd9e1c679f2a7d62b5a33d1790600090a2506001919050565b60006001600160a01b038216158061190e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b60008060008060008060008088806020019051810190611b879190613b34565b97509750975097509750975097509750611ba7888888888888888861247c565b505050505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261127a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612646565b6020808201516001600160a01b03166000908152600690915260408120548190819060ff1680611c8257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684602001516001600160a01b0316145b6040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420617070726f7665640000000081525090611cd65760405162461bcd60e51b81526004016105e891906134df565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684602001516001600160a01b031603611d6f576000611d238560c0015161271b565b90506001600160e01b03198116632e1a7d4d60e01b14801590611d5757506001600160e01b03198116630d0e30db60e41b14155b15611d6d57600086600093509350935050611d82565b505b611d7a868686612736565b919450925090505b93509350939050565b6000611d9684611b2e565b15611e2357600854602083015183516040808601519051636a9a8d5560e11b81526001600160a01b039094169363d5351aaa938893611dd9938c93600401613bba565b60206040518083038185885af1158015611df7573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e1c9190613aff565b9050611ec5565b600854611e3d906001600160a01b03868116911685612846565b600854602083015183516040808601519051632e267e4160e21b81526001600160a01b039094169363b899f90493611e7f938b938b938b929190600401613bf6565b6020604051808303816000875af1158015611e9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec29190613aff565b90505b949350505050565b80516001600160a01b03166000908152600660209081526040808320548151808301909252601c82527f427574746572526f7574657256323a206e6f7420617070726f7665640000000092820192909252829160ff16611f405760405162461bcd60e51b81526004016105e891906134df565b50611f4c85858561295b565b8092508193505050600554471015604051806060016040528060268152602001613c9d6026913990611f915760405162461bcd60e51b81526004016105e891906134df565b50935093915050565b600180546001600160a01b0319169055610ff481612ac3565b60045460009081906001600160a01b0316611fcf57508361219c565b6000836001811115611fe357611fe361396f565b036120e1576003549150611ff686611b2e565b156120665760035434116040518060400160405280601e81526020017f427574746572526f7574657256323a206c6f776572207468616e206665650000815250906120545760405162461bcd60e51b81526004016105e891906134df565b5061205f82866136bb565b90506120c5565b6003543410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d6174636800000000815250906120c05760405162461bcd60e51b81526004016105e891906134df565b508490505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee955061210c565b620f4240600254866120f3919061357e565b6120fd9190613985565b915061210982866136bb565b90505b811561219c5760045461214c907f00000000000000000000000000000000000000000000000000000000000000009088906001600160a01b031685611914565b60045460405183916001600160a01b0390811691908916907fcc4044b4bd9f077089a3cbea5f01bcacf584f45336b1b50a8fb5f5e552da5f14906121939089908990613c4d565b60405180910390a45b94509492505050565b835160009081908490849083908190156122925760008a8060200190518101906121cf91906135f0565b90506121dc888a83611c1d565b60408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c6564000000000060208201529197509550909250826122365760405162461bcd60e51b81526004016105e891906134df565b508060a001518410156040518060400160405280601f8152602001600080516020613cc3833981519152815250906122815760405162461bcd60e51b81526004016105e891906134df565b508060600151965080602001519550505b885115612322576000898060200190518101906122af91906137bc565b90506122bc848683611ecd565b60408051808201909152601f81527f427574746572526f7574657256323a2063616c6c6261636b206661696c6564006020820152909450909250826123145760405162461bcd60e51b81526004016105e891906134df565b506080810151905190965094505b50945094509450945094565b8047101561237e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016105e8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146123cb576040519150601f19603f3d011682016040523d82523d6000602084013e6123d0565b606091505b50509050806124475760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105e8565b505050565b6040516001600160a01b03831660248201526044810182905261244790849063a9059cbb60e01b90606401611be6565b604051623f675f60e91b81526001600160a01b038881166004830152600091908a1690637ecebe0090602401602060405180830381865afa1580156124c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e99190613aff565b60405163d505accf60e01b81526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c48201859052919250908a169063d505accf9060e401600060405180830381600087803b15801561255d57600080fd5b505af1158015612571573d6000803e3d6000fd5b5050604051623f675f60e91b81526001600160a01b038b81166004830152600093508c169150637ecebe0090602401602060405180830381865afa1580156125bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e19190613aff565b90506125ee82600161356b565b81146116205760405162461bcd60e51b815260206004820152602160248201527f5361666545524332303a207065726d697420646964206e6f74207375636365656044820152601960fa1b60648201526084016105e8565b600061269b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612b139092919063ffffffff16565b90508051600014806126bc5750808060200190518101906126bc9190613c7f565b6124475760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105e8565b6000815160000361272e57506000919050565b506020015190565b608081015160009081808061274a87611b2e565b9050801561275a5787915061278f565b6040860151612775906001600160a01b038916906000612846565b604086015161278f906001600160a01b038916908a612846565b6127998430611880565b925085602001516001600160a01b0316828760c001516040516127bc9190613b18565b60006040518083038185875af1925050503d80600081146127f9576040519150601f19603f3d011682016040523d82523d6000602084013e6127fe565b606091505b5050809550508261280f8530611880565b61281991906136bb565b92508061283b57604086015161283b906001600160a01b038916906000612846565b505093509350939050565b8015806128c05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561289a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128be9190613aff565b155b61292b5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016105e8565b6040516001600160a01b03831660248201526044810182905261244790849063095ea7b360e01b90606401611be6565b6000806129688430611880565b604084015160a08501519192509081156129825786828201525b61298b86611b2e565b156129fa5784600001516001600160a01b031687826040516129ad9190613b18565b60006040518083038185875af1925050503d80600081146129ea576040519150601f19603f3d011682016040523d82523d6000602084013e6129ef565b606091505b505080945050612aa3565b8615612a1a576020850151612a1a906001600160a01b0388169089612b22565b84600001516001600160a01b0316856060015182604051612a3b9190613b18565b60006040518083038185875af1925050503d8060008114612a78576040519150601f19603f3d011682016040523d82523d6000602084013e612a7d565b606091505b50909450508615612aa3576020850151612aa3906001600160a01b038816906000612846565b612aad8630611880565b612ab790846136bb565b92505050935093915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060611ec58484600085612bcf565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015612b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b969190613aff565b905061127a8463095ea7b360e01b85612baf868661356b565b6040516001600160a01b0390921660248301526044820152606401611be6565b606082471015612c305760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105e8565b600080866001600160a01b03168587604051612c4c9190613b18565b60006040518083038185875af1925050503d8060008114612c89576040519150601f19603f3d011682016040523d82523d6000602084013e612c8e565b606091505b5091509150612c9f87838387612caa565b979650505050505050565b60608315612d19578251600003612d12576001600160a01b0385163b612d125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105e8565b5081611ec5565b611ec58383815115612d2e5781518083602001fd5b8060405162461bcd60e51b81526004016105e891906134df565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201529061016082015290565b6001600160a01b0381168114610ff457600080fd5b80356109c981612da9565b60008083601f840112612ddb57600080fd5b5081356001600160401b03811115612df257600080fd5b602083019150836020828501011115612e0a57600080fd5b9250929050565b60008060008060008060008060c0898b031215612e2d57600080fd5b883597506020890135612e3f81612da9565b9650604089013595506060890135945060808901356001600160401b0380821115612e6957600080fd5b612e758c838d01612dc9565b909650945060a08b0135915080821115612e8e57600080fd5b50612e9b8b828c01612dc9565b999c989b5096995094979396929594505050565b600060208284031215612ec157600080fd5b8135612ecc81612da9565b9392505050565b8035600281106109c957600080fd5b600080600060608486031215612ef757600080fd5b833592506020840135612f0981612da9565b9150612f1760408501612ed3565b90509250925092565b60008060008060008060008060a0898b031215612f3c57600080fd5b8835612f4781612da9565b97506020890135965060408901356001600160401b0380821115612f6a57600080fd5b612f768c838d01612dc9565b909850965060608b0135915080821115612f8f57600080fd5b612f9b8c838d01612dc9565b909650945060808b0135915080821115612e8e57600080fd5b600060208284031215612fc657600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b038111828210171561300557613005612fcd565b60405290565b60405160e081016001600160401b038111828210171561300557613005612fcd565b604051601f8201601f191681016001600160401b038111828210171561305557613055612fcd565b604052919050565b60006001600160401b0382111561307657613076612fcd565b50601f01601f191660200190565b600082601f83011261309557600080fd5b81356130a86130a38261305d565b61302d565b8181528460208386010111156130bd57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156130ef57600080fd5b83356001600160401b038082111561310657600080fd5b9085019060c0828803121561311a57600080fd5b613122612fe3565b823561312d81612da9565b8152602083013561313d81612da9565b806020830152506040830135604082015260608301356060820152608083013561316681612da9565b608082015260a08301358281111561317d57600080fd5b61318989828601613084565b60a08301525094506131a091505060208501612dbe565b9150604084013590509250925092565b600080604083850312156131c357600080fd5b82356131ce81612da9565b946020939093013593505050565b6000806000606084860312156131f157600080fd5b83356131fc81612da9565b95602085013595506040909401359392505050565b8015158114610ff457600080fd5b60008060006040848603121561323457600080fd5b83356001600160401b038082111561324b57600080fd5b818601915086601f83011261325f57600080fd5b81358181111561326e57600080fd5b8760208260051b850101111561328357600080fd5b6020928301955093505084013561329981613211565b809150509250925092565b60008060008060008060008060008060e08b8d0312156132c357600080fd5b8a35995060208b01356132d581612da9565b985060408b013597506132ea60608c01612ed3565b965060808b01356001600160401b038082111561330657600080fd5b6133128e838f01612dc9565b909850965060a08d013591508082111561332b57600080fd5b6133378e838f01612dc9565b909650945060c08d013591508082111561335057600080fd5b5061335d8d828e01612dc9565b915080935050809150509295989b9194979a5092959850565b60ff81168114610ff457600080fd5b80356109c981613376565b600060e082840312156133a257600080fd5b6133aa61300b565b90506133b582613385565b81526133c360208301612dbe565b60208201526133d460408301612dbe565b60408201526133e560608301612dbe565b60608201526133f660808301612dbe565b608082015260a082013560a082015260c08201356001600160401b0381111561341e57600080fd5b61342a84828501613084565b60c08301525092915050565b60008060006060848603121561344b57600080fd5b83356001600160401b0381111561346157600080fd5b61346d86828701613390565b935050602084013561347e81612da9565b929592945050506040919091013590565b60005b838110156134aa578181015183820152602001613492565b50506000910152565b600081518084526134cb81602086016020860161348f565b601f01601f19169290920160200192915050565b602081526000612ecc60208301846134b3565b6000806040838503121561350557600080fd5b82356001600160401b038082111561351c57600080fd5b61352886838701613084565b9350602085013591508082111561353e57600080fd5b5061354b85828601613084565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561190e5761190e613555565b808202811582820484141761190e5761190e613555565b80516109c981613376565b80516109c981612da9565b600082601f8301126135bc57600080fd5b81516135ca6130a38261305d565b8181528460208386010111156135df57600080fd5b611ec582602083016020870161348f565b60006020828403121561360257600080fd5b81516001600160401b038082111561361957600080fd5b9083019060e0828603121561362d57600080fd5b61363561300b565b61363e83613595565b815261364c602084016135a0565b602082015261365d604084016135a0565b604082015261366e606084016135a0565b606082015261367f608084016135a0565b608082015260a083015160a082015260c0830151828111156136a057600080fd5b6136ac878286016135ab565b60c08301525095945050505050565b8181038181111561190e5761190e613555565b6060808252845160ff168282015260208501516001600160a01b03908116608084015260408601511660a083015284015160009061371760c08401826001600160a01b03169052565b5060808501516001600160a01b03811660e08401525060a085015161010083015260c085015160e06101208401526137536101408401826134b3565b91505061376b60208301856001600160a01b03169052565b826040830152949350505050565b60008060006060848603121561378e57600080fd5b835161379981612da9565b60208501519093506137aa81612da9565b80925050604084015190509250925092565b6000602082840312156137ce57600080fd5b81516001600160401b03808211156137e557600080fd5b9083019060c082860312156137f957600080fd5b613801612fe3565b825161380c81612da9565b8152602083015161381c81612da9565b806020830152506040830151604082015260608301516060820152608083015161384581612da9565b608082015260a08301518281111561385c57600080fd5b613868878286016135ab565b60a08301525095945050505050565b60608152600060018060a01b03808651166060840152806020870151166080840152604086015160a0840152606086015160c08401528060808701511660e084015260a086015160c06101008501526138d46101208501826134b3565b959091166020840152505060400152919050565b600080604083850312156138fb57600080fd5b825161390681612da9565b6020939093015192949293505050565b600061010060018060a01b03808c168452808b166020850152508860408401528760608401528660808401528560a08401528460c08401528060e0840152613960818401856134b3565b9b9a5050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000826139a257634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156139b957600080fd5b81356001600160401b038111156139cf57600080fd5b611ec584828501613390565b6000602082840312156139ed57600080fd5b81356001600160401b0380821115613a0457600080fd5b9083019060608286031215613a1857600080fd5b604051606081018181108382111715613a3357613a33612fcd565b60405282358152602083013582811115613a4c57600080fd5b613a5887828601613084565b602083015250604083013582811115613a7057600080fd5b613a7c87828601613084565b60408301525095945050505050565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000613ac460c08301846134b3565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613af857613af8613555565b5060010190565b600060208284031215613b1157600080fd5b5051919050565b60008251613b2a81846020870161348f565b9190910192915050565b600080600080600080600080610100898b031215613b5157600080fd5b8851613b5c81612da9565b60208a0151909850613b6d81612da9565b60408a0151909750613b7e81612da9565b80965050606089015194506080890151935060a0890151613b9e81613376565b60c08a015160e0909a0151989b979a5095989497939692505050565b6001600160a01b0385168152608060208201819052600090613bde908301866134b3565b8460408401528281036060840152612c9f81856134b3565b6001600160a01b0387811682528616602082015260c060408201819052600090613c22908301876134b3565b85606084015284608084015282810360a0840152613c4081856134b3565b9998505050505050505050565b8281526040810160028310613c7257634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b600060208284031215613c9157600080fd5b8151612ecc8161321156fe427574746572526f7574657256323a206e61746976652076616c7565206f7665727370656e64427574746572526f7574657256323a207265636569766520746f6f206c6f7700a2646970667358221220118380d524e5e59daca022a7498657c63eb1760f06d20576a5e35bfb1959c7e564736f6c63430008140033000000000000000000000000feb2b97e4efce787c08086dc16ab69e063911380000000000000000000000000df3f1ee5baf55055980887aad79f6fe6e3302d9300000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8
Deployed Bytecode
0x60806040526004361061014f5760003560e01c806391792d5b116100b6578063d904371e1161006f578063d904371e14610408578063e30c397814610428578063ecc847d314610446578063f2fde38b14610459578063f78f24a714610479578063f848a574146104c457600080fd5b806391792d5b14610338578063978bbdb91461034e578063b3f0067414610364578063c1b1660e14610384578063cc9e3e89146103a4578063d8b964e6146103d857600080fd5b80635dc4ba08116101085780635dc4ba0814610259578063715018a61461029857806378e3214f146102ad57806379ba5097146102cd5780638cbafe0a146102e25780638da5cb5b1461031a57600080fd5b80632344e6551461015b5780632b8b7b4b1461017d578063451559a9146101b2578063480a3411146102025780634e36b11c14610215578063536f4cfe1461023957600080fd5b3661015657005b600080fd5b34801561016757600080fd5b5061017b610176366004612e11565b61050a565b005b34801561018957600080fd5b5061019d610198366004612eaf565b6109b0565b60405190151581526020015b60405180910390f35b3480156101be57600080fd5b506101d26101cd366004612ee2565b6109ce565b6040516101a994939291909384526001600160a01b03928316602085015291166040830152606082015260800190565b61017b610210366004612f20565b610a9b565b34801561022157600080fd5b5061022b60095481565b6040519081526020016101a9565b34801561024557600080fd5b5061017b610254366004612fb4565b610e77565b34801561026557600080fd5b506102796102743660046130da565b610eb2565b604080516001600160a01b0390931683526020830191909152016101a9565b3480156102a457600080fd5b5061017b610f31565b3480156102b957600080fd5b5061017b6102c83660046131b0565b610f45565b3480156102d957600080fd5b5061017b610f7d565b3480156102ee57600080fd5b50600854610302906001600160a01b031681565b6040516001600160a01b0390911681526020016101a9565b34801561032657600080fd5b506000546001600160a01b0316610302565b34801561034457600080fd5b5061022b60035481565b34801561035a57600080fd5b5061022b60025481565b34801561037057600080fd5b50600454610302906001600160a01b031681565b34801561039057600080fd5b5061017b61039f3660046131dc565b610ff7565b3480156103b057600080fd5b5061022b7f000000000000000000000000000000000000000000000000000000000000138881565b3480156103e457600080fd5b5061019d6103f3366004612eaf565b60066020526000908152604090205460ff1681565b34801561041457600080fd5b5061017b61042336600461321f565b6110c4565b34801561043457600080fd5b506001546001600160a01b0316610302565b61017b6104543660046132a4565b611280565b34801561046557600080fd5b5061017b610474366004612eaf565b61162c565b34801561048557600080fd5b50610499610494366004612ee2565b61169d565b604080516001600160a01b0395861681529490931660208501529183015260608201526080016101a9565b3480156104d057600080fd5b506104e46104df366004613436565b611753565b604080516001600160a01b039485168152939092166020840152908201526060016101a9565b610512611827565b61051a612d48565b6001600160a01b0388168082526040808301899052602080840192909252606083018990526101008301889052466101208401528051601f87018390048302810183019091528581529086908690819084018382808284376000920191909152505050506101408201524760055560085460408051808201909152601881527f427574746572526f7574657256323a206d6f73206f6e6c7900000000000000006020820152906001600160a01b031633146105f15760405162461bcd60e51b81526004016105e891906134df565b60405180910390fd5b5086610601826000015130611880565b10156040518060400160405280601f8152602001600080516020613cc3833981519152815250906106455760405162461bcd60e51b81526004016105e891906134df565b50600080610655848601866134f2565b91509150600081518351610669919061356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b815250906106bb5760405162461bcd60e51b81526004016105e891906134df565b506009546001906000906106d090600261357e565b8451909150156107bb576000848060200190518101906106f091906135f0565b60608101516001600160a01b031660a08801529050815a11156107b957306001600160a01b031663f848a5746009545a61072a91906136bb565b8389600001518a604001516040518563ffffffff1660e01b8152600401610753939291906136ce565b60606040518083038160008887f19350505050801561078f575060408051601f3d908101601f1916820190925261078c91810190613779565b60015b61079c57600092506107b9565b6001600160a01b0391821660208a0152911660c088015260608701525b505b8251156108bb576000838060200190518101906107d891906137bc565b60a08701519091506001600160a01b03166108015760808101516001600160a01b031660a08701525b82801561080d5750815a115b156108b957306001600160a01b0316635dc4ba086009545a61082f91906136bb565b8389602001518a606001516040518563ffffffff1660e01b815260040161085893929190613877565b604080518083038160008887f193505050508015610893575060408051601f3d908101601f19168201909252610890918101906138e8565b60015b156108b9576001600160a01b0391821660c089015260e088015260808201511660a08701525b505b8460e0015185606001511115610912576109127f000000000000000000000000000000000000000000000000000000000000138886602001518760a001518860e00151896060015161090d91906136bb565b611914565b8460c001516001600160a01b03168560a001516001600160a01b03168e7f593e4dbcb8f7312fc3bdd77e2095da131a6e1993f37752d12576d04e1f7253b4886000015189602001518a604001518b606001518c60e001518d61010001518e61012001518f610140015160405161098f989796959493929190613916565b60405180910390a450505050506109a66001600755565b5050505050505050565b60006109ba611a21565b6109c382611a7b565b50600190505b919050565b6004546000908190819081906001600160a01b03166109f857508592506000915081905080610a92565b6000856001811115610a0c57610a0c61396f565b03610a3f575050600354600090610a2286611b2e565b610a2e57869350610a83565b610a38818861356b565b9350610a83565b600254869250610a5290620f42406136bb565b610a5f620f42408961357e565b610a699190613985565b610a7490600161356b565b9350610a8087856136bb565b90505b6004546001600160a01b031692505b93509350935093565b610aa3611827565b878783838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526017815276213aba3a32b92937baba32b92b191d103d32b9379034b760491b602082015291505082610b285760405162461bcd60e51b81526004016105e891906134df565b50805115610b3957610b3981611b67565b610b4334476136bb565b600555610b4f83611b2e565b15610bb257813410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d617463680000000081525090610bac5760405162461bcd60e51b81526004016105e891906134df565b50610bbe565b610bbe83333085611bb2565b6000610bca878a61356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b81525090610c1c5760405162461bcd60e51b81526004016105e891906134df565b50610c25612d48565b6001600160a01b038c16808252604082018c9052602082015260608082018c90528915610db4576000610c5a8b8d018d6139a7565b90506000610c718460400151856000015184611c1d565b60608701526001600160a01b031660208087019190915260408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c656400000000009181019190915290915081610cdf5760405162461bcd60e51b81526004016105e891906134df565b508160a00151846060015110156040518060400160405280601f8152602001600080516020613cc383398151915281525090610d2e5760405162461bcd60e51b81526004016105e891906134df565b5089158015610d41575060008460600151115b15610db157606082810151604051911b6bffffffffffffffffffffffff191660208201526034016040516020818303038152906040529250610db17f0000000000000000000000000000000000000000000000000000000000001388856020015184606001518760600151611914565b50505b60008815610df7576000610dca8a8c018c6139db565b8051610120860152602080820151908601516060870151919550919250610df391339184611d8b565b9150505b82600001516001600160a01b0316336001600160a01b0316827f140fc1ae4910fc65859bbe978cf17402f862c5bd87a15aa3a0894d5aa50b0b06866020015187604001518860600151468a61012001518a604051610e5a96959493929190613a8b565b60405180910390a450506000600555506109a69250611a1a915050565b610e7f611a21565b600981905560405181907ff47543a7cab136b12cca0a2ecd728c9d1943f57b923b98db48725d2b76dd4da990600090a250565b600080333014610ec157600080fd5b6000610ece848688611ecd565b60408051808201909152601f81527f427574746572526f7574657256323a2063616c6c6261636b206661696c656400602082015290935090915081610f265760405162461bcd60e51b81526004016105e891906134df565b505093519492505050565b610f39611a21565b610f436000611f9a565b565b610f4d611a21565b610f797f0000000000000000000000000000000000000000000000000000000000001388833384611914565b5050565b60015433906001600160a01b03168114610feb5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105e8565b610ff481611f9a565b50565b610fff611a21565b60408051808201909152601981527f427574746572526f7574657256323a207a65726f20616464720000000000000060208201526001600160a01b03841661105a5760405162461bcd60e51b81526004016105e891906134df565b50620f4240821061106a57600080fd5b600480546001600160a01b0319166001600160a01b03851690811790915560028390556003829055604051829184917f17906aa05b055ced1cea92b104912638c3ec8c90eec152fca6f36fbd8becca1d90600090a4505050565b6110cc611a21565b60408051808201909152601a815279427574746572526f7574657256323a206461746120656d70747960301b60208201528261111b5760405162461bcd60e51b81526004016105e891906134df565b5060005b8281101561127a5761116084848381811061113c5761113c613ad0565b90506020020160208101906111519190612eaf565b6001600160a01b03163b151590565b6040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420636f6e747261637400000000815250906111b45760405162461bcd60e51b81526004016105e891906134df565b5081600660008686858181106111cc576111cc613ad0565b90506020020160208101906111e19190612eaf565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905581151584848381811061121e5761121e613ad0565b90506020020160208101906112339190612eaf565b6001600160a01b03167f1f478f1e5aee36a892d86e821aba410dc0934cb0ebd0241dd75370833884545360405160405180910390a38061127281613ae6565b91505061111f565b50505050565b611288611827565b888883838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526017815276213aba3a32b92937baba32b92b191d103d32b9379034b760491b60208201529150508261130d5760405162461bcd60e51b81526004016105e891906134df565b5080511561131e5761131e81611b67565b61132834476136bb565b60055561133483611b2e565b1561139757813410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d6174636800000000815250906113915760405162461bcd60e51b81526004016105e891906134df565b506113a3565b6113a383333085611bb2565b6113ab612d48565b6001600160a01b038d168152604081018c9052608081018e905261016081018b60018111156113dc576113dc61396f565b908160018111156113ef576113ef61396f565b90525060006113fe888b61356b565b116040518060400160405280601a815260200179427574746572526f7574657256323a206461746120656d70747960301b815250906114505760405162461bcd60e51b81526004016105e891906134df565b5061146e816000015182604001518360800151846101600151611fb3565b606083015250604080516020601f8c018190048102820181019092528a81526114ee918c908c908190840183828082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b9081908401838280828437600092019190915250508551606087015190925090506121a5565b60e08601819052606086018290526001600160a01b03928316602087015292821660c0860152921660a08401521015611563576115637f000000000000000000000000000000000000000000000000000000000000138882602001518360a001518460e00151856060015161090d91906136bb565b8060c001516001600160a01b03168160a001516001600160a01b0316336001600160a01b03167f54592234b1278d8a9675f22721443e0b9f8a1f4410b55bf6753330073b55e3ef846080015185600001518660200151876040015188606001518960e00151604051611609969594939291909586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450506000600555505060016007555b50505050505050505050565b611634611a21565b600180546001600160a01b0383166001600160a01b031990911681179091556116656000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6004546000908190819081906001600160a01b03166116c757506000925082915081905085610a92565b60008560018111156116db576116db61396f565b0361170e576000925060035491506116f286611b2e565b6116fd57508561173c565b61170782886136bb565b905061173c565b859250620f424060025488611723919061357e565b61172d9190613985565b915061173982886136bb565b90505b6004546001600160a01b0316935093509350935093565b6000808033301461176357600080fd5b6000611770858789611c1d565b60408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c6564000000000060208201529195509350909150816117ca5760405162461bcd60e51b81526004016105e891906134df565b508660a001518210156040518060400160405280601f8152602001600080516020613cc3833981519152815250906118155760405162461bcd60e51b81526004016105e891906134df565b50866020015193505093509350939050565b6002600754036118795760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105e8565b6002600755565b600061188b83611b2e565b156118a157506001600160a01b0381163161190e565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156118e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190b9190613aff565b90505b92915050565b61191d83611b2e565b156119315761192c828261232e565b61127a565b83632b6653dc148015611960575073a614f803b6fd780986a42c78ec9c7f77e6ded13c6001600160a01b038416145b15611a0657604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151918516916119bc9190613b18565b6000604051808303816000865af19150503d80600081146119f9576040519150601f19603f3d011682016040523d82523d6000602084013e6119fe565b606091505b50505061127a565b61127a6001600160a01b038416838361244c565b6001600755565b6000546001600160a01b03163314610f435760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105e8565b60006001600160a01b0382163b15156040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420636f6e74726163740000000081525090611ade5760405162461bcd60e51b81526004016105e891906134df565b50600880546001600160a01b0319166001600160a01b0384169081179091556040517ff43456bb773c1af890fa668fc6aabe2ea4c3141afd9e1c679f2a7d62b5a33d1790600090a2506001919050565b60006001600160a01b038216158061190e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b60008060008060008060008088806020019051810190611b879190613b34565b97509750975097509750975097509750611ba7888888888888888861247c565b505050505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261127a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612646565b6020808201516001600160a01b03166000908152600690915260408120548190819060ff1680611c8257507f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031684602001516001600160a01b0316145b6040518060400160405280601c81526020017f427574746572526f7574657256323a206e6f7420617070726f7665640000000081525090611cd65760405162461bcd60e51b81526004016105e891906134df565b507f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031684602001516001600160a01b031603611d6f576000611d238560c0015161271b565b90506001600160e01b03198116632e1a7d4d60e01b14801590611d5757506001600160e01b03198116630d0e30db60e41b14155b15611d6d57600086600093509350935050611d82565b505b611d7a868686612736565b919450925090505b93509350939050565b6000611d9684611b2e565b15611e2357600854602083015183516040808601519051636a9a8d5560e11b81526001600160a01b039094169363d5351aaa938893611dd9938c93600401613bba565b60206040518083038185885af1158015611df7573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e1c9190613aff565b9050611ec5565b600854611e3d906001600160a01b03868116911685612846565b600854602083015183516040808601519051632e267e4160e21b81526001600160a01b039094169363b899f90493611e7f938b938b938b929190600401613bf6565b6020604051808303816000875af1158015611e9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec29190613aff565b90505b949350505050565b80516001600160a01b03166000908152600660209081526040808320548151808301909252601c82527f427574746572526f7574657256323a206e6f7420617070726f7665640000000092820192909252829160ff16611f405760405162461bcd60e51b81526004016105e891906134df565b50611f4c85858561295b565b8092508193505050600554471015604051806060016040528060268152602001613c9d6026913990611f915760405162461bcd60e51b81526004016105e891906134df565b50935093915050565b600180546001600160a01b0319169055610ff481612ac3565b60045460009081906001600160a01b0316611fcf57508361219c565b6000836001811115611fe357611fe361396f565b036120e1576003549150611ff686611b2e565b156120665760035434116040518060400160405280601e81526020017f427574746572526f7574657256323a206c6f776572207468616e206665650000815250906120545760405162461bcd60e51b81526004016105e891906134df565b5061205f82866136bb565b90506120c5565b6003543410156040518060400160405280601c81526020017f427574746572526f7574657256323a20666565206d69736d6174636800000000815250906120c05760405162461bcd60e51b81526004016105e891906134df565b508490505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee955061210c565b620f4240600254866120f3919061357e565b6120fd9190613985565b915061210982866136bb565b90505b811561219c5760045461214c907f00000000000000000000000000000000000000000000000000000000000013889088906001600160a01b031685611914565b60045460405183916001600160a01b0390811691908916907fcc4044b4bd9f077089a3cbea5f01bcacf584f45336b1b50a8fb5f5e552da5f14906121939089908990613c4d565b60405180910390a45b94509492505050565b835160009081908490849083908190156122925760008a8060200190518101906121cf91906135f0565b90506121dc888a83611c1d565b60408051808201909152601b81527f427574746572526f7574657256323a2073776170206661696c6564000000000060208201529197509550909250826122365760405162461bcd60e51b81526004016105e891906134df565b508060a001518410156040518060400160405280601f8152602001600080516020613cc3833981519152815250906122815760405162461bcd60e51b81526004016105e891906134df565b508060600151965080602001519550505b885115612322576000898060200190518101906122af91906137bc565b90506122bc848683611ecd565b60408051808201909152601f81527f427574746572526f7574657256323a2063616c6c6261636b206661696c6564006020820152909450909250826123145760405162461bcd60e51b81526004016105e891906134df565b506080810151905190965094505b50945094509450945094565b8047101561237e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016105e8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146123cb576040519150601f19603f3d011682016040523d82523d6000602084013e6123d0565b606091505b50509050806124475760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105e8565b505050565b6040516001600160a01b03831660248201526044810182905261244790849063a9059cbb60e01b90606401611be6565b604051623f675f60e91b81526001600160a01b038881166004830152600091908a1690637ecebe0090602401602060405180830381865afa1580156124c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e99190613aff565b60405163d505accf60e01b81526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c48201859052919250908a169063d505accf9060e401600060405180830381600087803b15801561255d57600080fd5b505af1158015612571573d6000803e3d6000fd5b5050604051623f675f60e91b81526001600160a01b038b81166004830152600093508c169150637ecebe0090602401602060405180830381865afa1580156125bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e19190613aff565b90506125ee82600161356b565b81146116205760405162461bcd60e51b815260206004820152602160248201527f5361666545524332303a207065726d697420646964206e6f74207375636365656044820152601960fa1b60648201526084016105e8565b600061269b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612b139092919063ffffffff16565b90508051600014806126bc5750808060200190518101906126bc9190613c7f565b6124475760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105e8565b6000815160000361272e57506000919050565b506020015190565b608081015160009081808061274a87611b2e565b9050801561275a5787915061278f565b6040860151612775906001600160a01b038916906000612846565b604086015161278f906001600160a01b038916908a612846565b6127998430611880565b925085602001516001600160a01b0316828760c001516040516127bc9190613b18565b60006040518083038185875af1925050503d80600081146127f9576040519150601f19603f3d011682016040523d82523d6000602084013e6127fe565b606091505b5050809550508261280f8530611880565b61281991906136bb565b92508061283b57604086015161283b906001600160a01b038916906000612846565b505093509350939050565b8015806128c05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561289a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128be9190613aff565b155b61292b5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016105e8565b6040516001600160a01b03831660248201526044810182905261244790849063095ea7b360e01b90606401611be6565b6000806129688430611880565b604084015160a08501519192509081156129825786828201525b61298b86611b2e565b156129fa5784600001516001600160a01b031687826040516129ad9190613b18565b60006040518083038185875af1925050503d80600081146129ea576040519150601f19603f3d011682016040523d82523d6000602084013e6129ef565b606091505b505080945050612aa3565b8615612a1a576020850151612a1a906001600160a01b0388169089612b22565b84600001516001600160a01b0316856060015182604051612a3b9190613b18565b60006040518083038185875af1925050503d8060008114612a78576040519150601f19603f3d011682016040523d82523d6000602084013e612a7d565b606091505b50909450508615612aa3576020850151612aa3906001600160a01b038816906000612846565b612aad8630611880565b612ab790846136bb565b92505050935093915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060611ec58484600085612bcf565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015612b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b969190613aff565b905061127a8463095ea7b360e01b85612baf868661356b565b6040516001600160a01b0390921660248301526044820152606401611be6565b606082471015612c305760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105e8565b600080866001600160a01b03168587604051612c4c9190613b18565b60006040518083038185875af1925050503d8060008114612c89576040519150601f19603f3d011682016040523d82523d6000602084013e612c8e565b606091505b5091509150612c9f87838387612caa565b979650505050505050565b60608315612d19578251600003612d12576001600160a01b0385163b612d125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105e8565b5081611ec5565b611ec58383815115612d2e5781518083602001fd5b8060405162461bcd60e51b81526004016105e891906134df565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201529061016082015290565b6001600160a01b0381168114610ff457600080fd5b80356109c981612da9565b60008083601f840112612ddb57600080fd5b5081356001600160401b03811115612df257600080fd5b602083019150836020828501011115612e0a57600080fd5b9250929050565b60008060008060008060008060c0898b031215612e2d57600080fd5b883597506020890135612e3f81612da9565b9650604089013595506060890135945060808901356001600160401b0380821115612e6957600080fd5b612e758c838d01612dc9565b909650945060a08b0135915080821115612e8e57600080fd5b50612e9b8b828c01612dc9565b999c989b5096995094979396929594505050565b600060208284031215612ec157600080fd5b8135612ecc81612da9565b9392505050565b8035600281106109c957600080fd5b600080600060608486031215612ef757600080fd5b833592506020840135612f0981612da9565b9150612f1760408501612ed3565b90509250925092565b60008060008060008060008060a0898b031215612f3c57600080fd5b8835612f4781612da9565b97506020890135965060408901356001600160401b0380821115612f6a57600080fd5b612f768c838d01612dc9565b909850965060608b0135915080821115612f8f57600080fd5b612f9b8c838d01612dc9565b909650945060808b0135915080821115612e8e57600080fd5b600060208284031215612fc657600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b038111828210171561300557613005612fcd565b60405290565b60405160e081016001600160401b038111828210171561300557613005612fcd565b604051601f8201601f191681016001600160401b038111828210171561305557613055612fcd565b604052919050565b60006001600160401b0382111561307657613076612fcd565b50601f01601f191660200190565b600082601f83011261309557600080fd5b81356130a86130a38261305d565b61302d565b8181528460208386010111156130bd57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156130ef57600080fd5b83356001600160401b038082111561310657600080fd5b9085019060c0828803121561311a57600080fd5b613122612fe3565b823561312d81612da9565b8152602083013561313d81612da9565b806020830152506040830135604082015260608301356060820152608083013561316681612da9565b608082015260a08301358281111561317d57600080fd5b61318989828601613084565b60a08301525094506131a091505060208501612dbe565b9150604084013590509250925092565b600080604083850312156131c357600080fd5b82356131ce81612da9565b946020939093013593505050565b6000806000606084860312156131f157600080fd5b83356131fc81612da9565b95602085013595506040909401359392505050565b8015158114610ff457600080fd5b60008060006040848603121561323457600080fd5b83356001600160401b038082111561324b57600080fd5b818601915086601f83011261325f57600080fd5b81358181111561326e57600080fd5b8760208260051b850101111561328357600080fd5b6020928301955093505084013561329981613211565b809150509250925092565b60008060008060008060008060008060e08b8d0312156132c357600080fd5b8a35995060208b01356132d581612da9565b985060408b013597506132ea60608c01612ed3565b965060808b01356001600160401b038082111561330657600080fd5b6133128e838f01612dc9565b909850965060a08d013591508082111561332b57600080fd5b6133378e838f01612dc9565b909650945060c08d013591508082111561335057600080fd5b5061335d8d828e01612dc9565b915080935050809150509295989b9194979a5092959850565b60ff81168114610ff457600080fd5b80356109c981613376565b600060e082840312156133a257600080fd5b6133aa61300b565b90506133b582613385565b81526133c360208301612dbe565b60208201526133d460408301612dbe565b60408201526133e560608301612dbe565b60608201526133f660808301612dbe565b608082015260a082013560a082015260c08201356001600160401b0381111561341e57600080fd5b61342a84828501613084565b60c08301525092915050565b60008060006060848603121561344b57600080fd5b83356001600160401b0381111561346157600080fd5b61346d86828701613390565b935050602084013561347e81612da9565b929592945050506040919091013590565b60005b838110156134aa578181015183820152602001613492565b50506000910152565b600081518084526134cb81602086016020860161348f565b601f01601f19169290920160200192915050565b602081526000612ecc60208301846134b3565b6000806040838503121561350557600080fd5b82356001600160401b038082111561351c57600080fd5b61352886838701613084565b9350602085013591508082111561353e57600080fd5b5061354b85828601613084565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561190e5761190e613555565b808202811582820484141761190e5761190e613555565b80516109c981613376565b80516109c981612da9565b600082601f8301126135bc57600080fd5b81516135ca6130a38261305d565b8181528460208386010111156135df57600080fd5b611ec582602083016020870161348f565b60006020828403121561360257600080fd5b81516001600160401b038082111561361957600080fd5b9083019060e0828603121561362d57600080fd5b61363561300b565b61363e83613595565b815261364c602084016135a0565b602082015261365d604084016135a0565b604082015261366e606084016135a0565b606082015261367f608084016135a0565b608082015260a083015160a082015260c0830151828111156136a057600080fd5b6136ac878286016135ab565b60c08301525095945050505050565b8181038181111561190e5761190e613555565b6060808252845160ff168282015260208501516001600160a01b03908116608084015260408601511660a083015284015160009061371760c08401826001600160a01b03169052565b5060808501516001600160a01b03811660e08401525060a085015161010083015260c085015160e06101208401526137536101408401826134b3565b91505061376b60208301856001600160a01b03169052565b826040830152949350505050565b60008060006060848603121561378e57600080fd5b835161379981612da9565b60208501519093506137aa81612da9565b80925050604084015190509250925092565b6000602082840312156137ce57600080fd5b81516001600160401b03808211156137e557600080fd5b9083019060c082860312156137f957600080fd5b613801612fe3565b825161380c81612da9565b8152602083015161381c81612da9565b806020830152506040830151604082015260608301516060820152608083015161384581612da9565b608082015260a08301518281111561385c57600080fd5b613868878286016135ab565b60a08301525095945050505050565b60608152600060018060a01b03808651166060840152806020870151166080840152604086015160a0840152606086015160c08401528060808701511660e084015260a086015160c06101008501526138d46101208501826134b3565b959091166020840152505060400152919050565b600080604083850312156138fb57600080fd5b825161390681612da9565b6020939093015192949293505050565b600061010060018060a01b03808c168452808b166020850152508860408401528760608401528660808401528560a08401528460c08401528060e0840152613960818401856134b3565b9b9a5050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000826139a257634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156139b957600080fd5b81356001600160401b038111156139cf57600080fd5b611ec584828501613390565b6000602082840312156139ed57600080fd5b81356001600160401b0380821115613a0457600080fd5b9083019060608286031215613a1857600080fd5b604051606081018181108382111715613a3357613a33612fcd565b60405282358152602083013582811115613a4c57600080fd5b613a5887828601613084565b602083015250604083013582811115613a7057600080fd5b613a7c87828601613084565b60408301525095945050505050565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000613ac460c08301846134b3565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613af857613af8613555565b5060010190565b600060208284031215613b1157600080fd5b5051919050565b60008251613b2a81846020870161348f565b9190910192915050565b600080600080600080600080610100898b031215613b5157600080fd5b8851613b5c81612da9565b60208a0151909850613b6d81612da9565b60408a0151909750613b7e81612da9565b80965050606089015194506080890151935060a0890151613b9e81613376565b60c08a015160e0909a0151989b979a5095989497939692505050565b6001600160a01b0385168152608060208201819052600090613bde908301866134b3565b8460408401528281036060840152612c9f81856134b3565b6001600160a01b0387811682528616602082015260c060408201819052600090613c22908301876134b3565b85606084015284608084015282810360a0840152613c4081856134b3565b9998505050505050505050565b8281526040810160028310613c7257634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b600060208284031215613c9157600080fd5b8151612ecc8161321156fe427574746572526f7574657256323a206e61746976652076616c7565206f7665727370656e64427574746572526f7574657256323a207265636569766520746f6f206c6f7700a2646970667358221220118380d524e5e59daca022a7498657c63eb1760f06d20576a5e35bfb1959c7e564736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000feb2b97e4efce787c08086dc16ab69e063911380000000000000000000000000df3f1ee5baf55055980887aad79f6fe6e3302d9300000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8
-----Decoded View---------------
Arg [0] : _mosAddress (address): 0xfeB2b97e4Efce787c08086dC16Ab69E063911380
Arg [1] : _owner (address): 0xdf3f1Ee5BAF55055980887AaD79F6fE6e3302D93
Arg [2] : _wToken (address): 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000feb2b97e4efce787c08086dc16ab69e063911380
Arg [1] : 000000000000000000000000df3f1ee5baf55055980887aad79f6fe6e3302d93
Arg [2] : 00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8
Net Worth in USD
Net Worth in MNT
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.