Smart Contract Repository
TransitSwapRouterV4

TransitSwapRouterV4

Deploy on Alchemy
Verified
Ethereum
Verified, Router
Solidity
Verified
Ethereum

Contract Information

The following smart contract is TransitSwapRouterV4, which is a router contract for swapping tokens across different chains. It allows users to swap tokens using different swap types and fees. The contract also supports cross-chain swaps and allows the owner to change the transit swap, transit cross, and transit fees addresses. The contract is implemented using SafeMath, ReentrancyGuard, Pausable, and various libraries.
More Info

TransitSwapRouterV4 Source Code

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./libraries/ReentrancyGuard.sol"; import "./libraries/RevertReasonParser.sol"; import "./libraries/TransferHelper.sol"; import "./libraries/TransitStructs.sol"; import "./libraries/Ownable.sol"; import "./libraries/Pausable.sol"; import "./libraries/SafeMath.sol"; import "./interfaces/IERC20.sol"; import "./interfaces/ITransitSwapFees.sol"; contract TransitSwapRouterV4 is Ownable, ReentrancyGuard, Pausable { using SafeMath for uint256; address private _transit_swap; address private _transit_cross; address private _transit_fees; //default: Pre-trade fee model mapping(uint8 => bool) private _swap_type_mode; //whitelist wrapped mapping(address => bool) private _wrapped_allowed; event Receipt(address from, uint256 amount); event Withdraw(address indexed token, address indexed executor, address indexed recipient, uint amount); event ChangeTransitSwap(address indexed previousTransit, address indexed newTransit); event ChangeTransitCross(address indexed previousTransit, address indexed newTransit); event ChangeTransitFees(address indexed previousTransitFees, address indexed newTransitFees); event ChangeSwapTypeMode(uint8[] types, bool[] newModes); event ChangeWrappedAllowed(address[] wrappeds, bool[] newAllowed); event TransitSwapped(address indexed srcToken, address indexed dstToken, address indexed dstReceiver, address trader, bool feeMode, uint256 amount, uint256 returnAmount, uint256 minReturnAmount, uint256 fee, uint256 toChainID, string channel, uint256 time); constructor(address transitSwap_, address transitCross_, address transitFees_, address executor) Ownable (executor) { _transit_swap = transitSwap_; _transit_cross = transitCross_; _transit_fees = transitFees_; } receive() external payable { emit Receipt(msg.sender, msg.value); } function transitSwap() external view returns (address) { return _transit_swap; } function transitCross() external view returns (address) { return _transit_cross; } function transitFees() external view returns (address) { return _transit_fees; } function swapTypeMode(uint8 swapType) external view returns (bool) { return _swap_type_mode[swapType]; } function wrappedAllowed(address wrapped) external view returns (bool) { return _wrapped_allowed[wrapped]; } function changeTransitSwap(address newTransit) external onlyExecutor { address oldTransit = _transit_swap; _transit_swap = newTransit; emit ChangeTransitSwap(oldTransit, newTransit); } function changeTransitCross(address newTransit) external onlyExecutor { address oldTransit = _transit_cross; _transit_cross = newTransit; emit ChangeTransitCross(oldTransit, newTransit); } function changeTransitFees(address newTransitFees) external onlyExecutor { address oldTransitFees = _transit_fees; _transit_fees = newTransitFees; emit ChangeTransitFees(oldTransitFees, newTransitFees); } function changeSwapTypeMode(uint8[] memory swapTypes) external onlyExecutor { bool[] memory newModes = new bool[](swapTypes.length); for (uint index; index < swapTypes.length; index++) { _swap_type_mode[swapTypes[index]] = !_swap_type_mode[swapTypes[index]]; newModes[index] = _swap_type_mode[swapTypes[index]]; } emit ChangeSwapTypeMode(swapTypes, newModes); } function changeWrappedAllowed(address[] calldata wrappeds) external onlyExecutor { bool[] memory newAllowed = new bool[](wrappeds.length); for (uint index; index < wrappeds.length; index++) { _wrapped_allowed[wrappeds[index]] = !_wrapped_allowed[wrappeds[index]]; newAllowed[index] = _wrapped_allowed[wrappeds[index]]; } emit ChangeWrappedAllowed(wrappeds, newAllowed); } function changePause(bool paused) external onlyExecutor { if (paused) { _pause(); } else { _unpause(); } } function _beforeSwap(bool preTradeModel, TransitStructs.TransitSwapDescription calldata desc) private returns (uint256 swapAmount, uint256 fee, uint256 beforeBalance) { if (preTradeModel) { fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, desc.amount, desc.swapType, desc.channel); } if (TransferHelper.isETH(desc.srcToken)) { require(msg.value == desc.amount, "TransitSwap: invalid msg.value"); swapAmount = desc.amount.sub(fee); } else { if (preTradeModel) { TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, address(this), desc.amount); TransferHelper.safeTransfer(desc.srcToken, desc.srcReceiver, desc.amount.sub(fee)); } else { TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, desc.srcReceiver, desc.amount); } } if (TransferHelper.isETH(desc.dstToken)) { if (preTradeModel) { beforeBalance = desc.dstReceiver.balance; } else { if (desc.swapType == uint8(TransitStructs.SwapTypes.swap)) { require(_wrapped_allowed[desc.wrappedNative], "TransitSwap: invalid wrapped address"); beforeBalance = IERC20(desc.wrappedNative).balanceOf(address(this)); } else { beforeBalance = address(this).balance; } } } else { if (preTradeModel) { beforeBalance = IERC20(desc.dstToken).balanceOf(desc.dstReceiver); } else { beforeBalance = IERC20(desc.dstToken).balanceOf(address(this)); } } } function _afterSwap(bool preTradeModel, TransitStructs.TransitSwapDescription calldata desc, uint256 beforeBalance) private returns (uint256 returnAmount, uint256 fee) { if (TransferHelper.isETH(desc.dstToken)) { if (preTradeModel) { returnAmount = desc.dstReceiver.balance.sub(beforeBalance); require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount"); } else { if (desc.swapType == uint8(TransitStructs.SwapTypes.swap)) { returnAmount = IERC20(desc.wrappedNative).balanceOf(address(this)).sub(beforeBalance); require(_wrapped_allowed[desc.wrappedNative], "TransitSwap: invalid wrapped address"); TransferHelper.safeWithdraw(desc.wrappedNative, returnAmount); } else { returnAmount = address(this).balance.sub(beforeBalance); } fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, returnAmount, desc.swapType, desc.channel); returnAmount = returnAmount.sub(fee); require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount"); TransferHelper.safeTransferETH(desc.dstReceiver, returnAmount); } } else { if (preTradeModel) { returnAmount = IERC20(desc.dstToken).balanceOf(desc.dstReceiver).sub(beforeBalance); require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount"); } else { returnAmount = IERC20(desc.dstToken).balanceOf(address(this)).sub(beforeBalance); fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, returnAmount, desc.swapType, desc.channel); returnAmount = returnAmount.sub(fee); uint256 receiverBeforeBalance = IERC20(desc.dstToken).balanceOf(desc.dstReceiver); TransferHelper.safeTransfer(desc.dstToken, desc.dstReceiver, returnAmount); returnAmount = IERC20(desc.dstToken).balanceOf(desc.dstReceiver).sub(receiverBeforeBalance); require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount"); } } } function swap(TransitStructs.TransitSwapDescription calldata desc, TransitStructs.CallbytesDescription calldata callbytesDesc) external payable nonReentrant whenNotPaused { require(callbytesDesc.calldatas.length > 0, "TransitSwap: data should be not zero"); require(desc.amount > 0, "TransitSwap: amount should be greater than 0"); require(desc.dstReceiver != address(0), "TransitSwap: receiver should be not address(0)"); require(desc.minReturnAmount > 0, "TransitSwap: minReturnAmount should be greater than 0"); if (callbytesDesc.flag == uint8(TransitStructs.Flag.aggregate)) { require(desc.srcToken == callbytesDesc.srcToken, "TransitSwap: invalid callbytesDesc"); } bool preTradeModel = !_swap_type_mode[desc.swapType]; (uint256 swapAmount, uint256 fee, uint256 beforeBalance) = _beforeSwap(preTradeModel, desc); { //bytes4(keccak256(bytes('callbytes(TransitStructs.CallbytesDescription)'))); (bool success, bytes memory result) = _transit_swap.call{value:swapAmount}(abi.encodeWithSelector(0xccbe4007, callbytesDesc)); if (!success) { revert(RevertReasonParser.parse(result,"TransitSwap:")); } } (uint256 returnAmount, uint256 postFee) = _afterSwap(preTradeModel, desc, beforeBalance); if (postFee > fee) { fee = postFee; } _emitTransit(desc, preTradeModel, fee, returnAmount); } function _beforeCross(TransitStructs.TransitSwapDescription calldata desc) private returns (uint256 swapAmount, uint256 fee, uint256 beforeBalance) { fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, desc.amount, desc.swapType, desc.channel); if (TransferHelper.isETH(desc.srcToken)) { require(msg.value == desc.amount, "TransitSwap: invalid msg.value"); swapAmount = desc.amount.sub(fee); } else { beforeBalance = IERC20(desc.srcToken).balanceOf(_transit_cross); if (fee == 0) { TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, _transit_cross, desc.amount); } else { TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, address(this), desc.amount); TransferHelper.safeTransfer(desc.srcToken, _transit_cross, desc.amount.sub(fee)); } } } function cross(TransitStructs.TransitSwapDescription calldata desc, TransitStructs.CallbytesDescription calldata callbytesDesc) external payable nonReentrant whenNotPaused { require(callbytesDesc.calldatas.length > 0, "TransitSwap: data should be not zero"); require(desc.amount > 0, "TransitSwap: amount should be greater than 0"); require(desc.srcToken == callbytesDesc.srcToken, "TransitSwap: invalid callbytesDesc"); (uint256 swapAmount, uint256 fee, uint256 beforeBalance) = _beforeCross(desc); { //bytes4(keccak256(bytes('callbytes(TransitStructs.CallbytesDescription)'))); (bool success, bytes memory result) = _transit_cross.call{value:swapAmount}(abi.encodeWithSelector(0xccbe4007, callbytesDesc)); if (!success) { revert(RevertReasonParser.parse(result,"TransitSwap:")); } } if (!TransferHelper.isETH(desc.srcToken)) { require(IERC20(desc.srcToken).balanceOf(_transit_cross) >= beforeBalance, "TransitSwap: invalid cross"); } _emitTransit(desc, true, fee, 0); } function _emitTransit(TransitStructs.TransitSwapDescription calldata desc, bool preTradeModel, uint256 fee, uint256 returnAmount) private { emit TransitSwapped( desc.srcToken, desc.dstToken, desc.dstReceiver, msg.sender, preTradeModel, desc.amount, returnAmount, desc.minReturnAmount, fee, desc.toChainID, desc.channel, block.timestamp ); } function withdrawTokens(address[] memory tokens, address recipient) external onlyExecutor { for(uint index; index < tokens.length; index++) { uint amount; if(TransferHelper.isETH(tokens[index])) { amount = address(this).balance; TransferHelper.safeTransferETH(recipient, amount); } else { amount = IERC20(tokens[index]).balanceOf(address(this)); TransferHelper.safeTransferWithoutRequire(tokens[index], recipient, amount); } emit Withdraw(tokens[index], msg.sender, recipient, amount); } } }// SPDX-License-Identifier: MIT pragma solidity >=0.6.9; interface ITransitSwapFees { function getFeeRate(address trader, uint256 tradeAmount, uint8 swapType, string memory channel) external view returns (uint payFees); }// SPDX-License-Identifier: MIT pragma solidity >=0.6.9; interface IERC20 { function totalSupply() external view returns (uint256); function decimals() external view returns (uint8); function name() external view returns (string memory); function symbol() external view returns (string memory); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } function div(uint x, uint y) internal pure returns (uint z) { require(y != 0 , 'ds-math-div-zero'); z = x / y; } }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(msg.sender); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(msg.sender); } }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) // Add executor extension pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable { address private _owner; address private _pendingOwner; address private _executor; address private _pendingExecutor; bool internal _initialized; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); event ExecutorshipTransferStarted(address indexed previousExecutor, address indexed newExecutor); event ExecutorshipTransferred(address indexed previousExecutor, address indexed newExecutor); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor(address newExecutor) { require(!_initialized, "Ownable: initialized"); _transferOwnership(msg.sender); _transferExecutorship(newExecutor); _initialized = true; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Throws if called by any account other than the executor. */ modifier onlyExecutor() { _checkExecutor(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Returns the address of the current executor. */ function executor() public view virtual returns (address) { return _executor; } /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Returns the address of the pending executor. */ function pendingExecutor() public view virtual returns (address) { return _pendingExecutor; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == msg.sender, "Ownable: caller is not the owner"); } /** * @dev Throws if the sender is not the executor. */ function _checkExecutor() internal view virtual { require(executor() == msg.sender, "Ownable: caller is not the executor"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers executorship of the contract to a new account (`newExecutor`). * Can only be called by the current executor. */ function transferExecutorship(address newExecutor) public virtual onlyExecutor { _pendingExecutor = newExecutor; emit ExecutorshipTransferStarted(executor(), newExecutor); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { delete _pendingOwner; address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } function _transferExecutorship(address newExecutor) internal virtual { delete _pendingExecutor; address oldExecutor = _executor; _executor = newExecutor; emit ExecutorshipTransferred(oldExecutor, newExecutor); } function acceptOwnership() external { address sender = msg.sender; require(pendingOwner() == sender, "Ownable: caller is not the new owner"); _transferOwnership(sender); } function acceptExecutorship() external { address sender = msg.sender; require(pendingExecutor() == sender, "Ownable: caller is not the new executor"); _transferExecutorship(sender); } }// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library TransitStructs { enum SwapTypes {aggregatePreMode, aggregatePostMode, swap, cross} enum Flag {aggregate, swap, cross} struct TransitSwapDescription { uint8 swapType; address srcToken; address dstToken; address srcReceiver; address dstReceiver; uint256 amount; uint256 minReturnAmount; string channel; uint256 toChainID; address wrappedNative; } struct CallbytesDescription { uint8 flag; address srcToken; bytes calldatas; } struct AggregateDescription { address dstToken; address receiver; uint[] amounts; uint[] needTransfer; address[] callers; address[] approveProxy; bytes[] calls; } struct SwapDescription { address[][] paths; address[][] pairs; uint[] fees; address receiver; uint deadline; } struct CrossDescription { address caller; uint256 amount; bool needWrapped; bytes calls; } function decodeAggregateDesc(bytes calldata calldatas) internal pure returns (AggregateDescription memory desc) { desc = abi.decode(calldatas, (AggregateDescription)); } function decodeSwapDesc(bytes calldata calldatas) internal pure returns (SwapDescription memory desc) { desc = abi.decode(calldatas, (SwapDescription)); } function decodeCrossDesc(bytes calldata calldatas) internal pure returns (CrossDescription memory desc) { desc = abi.decode(calldatas, (CrossDescription)); } }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; library TransferHelper { address private constant _ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); address private constant _ZERO_ADDRESS = address(0); function isETH(address token) internal pure returns (bool) { return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS); } function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_TOKEN_FAILED'); } function safeTransferWithoutRequire(address token, address to, uint256 value) internal returns (bool) { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); return (success && (data.length == 0 || abi.decode(data, (bool)))); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { // solium-disable-next-line (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: TRANSFER_FAILED'); } function safeDeposit(address wrapped, uint value) internal { // bytes4(keccak256(bytes('deposit()'))); (bool success, bytes memory data) = wrapped.call{value:value}(abi.encodeWithSelector(0xd0e30db0)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: DEPOSIT_FAILED'); } function safeWithdraw(address wrapped, uint value) internal { // bytes4(keccak256(bytes('withdraw(uint256 wad)'))); (bool success, bytes memory data) = wrapped.call{value:0}(abi.encodeWithSelector(0x2e1a7d4d, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: WITHDRAW_FAILED'); } }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; library RevertReasonParser { function parse(bytes memory data, string memory prefix) internal pure returns (string memory) { // https://solidity.readthedocs.io/en/latest/control-structures.html#revert // We assume that revert reason is abi-encoded as Error(string) // 68 = 4-byte selector 0x08c379a0 + 32 bytes offset + 32 bytes length if (data.length >= 68 && data[0] == "\x08" && data[1] == "\xc3" && data[2] == "\x79" && data[3] == "\xa0") { string memory reason; // solhint-disable no-inline-assembly assembly { // 68 = 32 bytes data length + 4-byte selector + 32 bytes offset reason := add(data, 68) } /* revert reason is padded up to 32 bytes with ABI encoder: Error(string) also sometimes there is extra 32 bytes of zeros padded in the end: https://github.com/ethereum/solidity/issues/10170 because of that we can't check for equality and instead check that string length + extra 68 bytes is less than overall data length */ require(data.length >= 68 + bytes(reason).length, "Invalid revert reason"); return string(abi.encodePacked(prefix, "Error(", reason, ")")); } // 36 = 4-byte selector 0x4e487b71 + 32 bytes integer else if (data.length == 36 && data[0] == "\x4e" && data[1] == "\x48" && data[2] == "\x7b" && data[3] == "\x71") { uint256 code; // solhint-disable no-inline-assembly assembly { // 36 = 32 bytes data length + 4-byte selector code := mload(add(data, 36)) } return string(abi.encodePacked(prefix, "Panic(", _toHex(code), ")")); } return string(abi.encodePacked(prefix, "Unknown(", _toHex(data), ")")); } function _toHex(uint256 value) private pure returns(string memory) { return _toHex(abi.encodePacked(value)); } function _toHex(bytes memory data) private pure returns(string memory) { bytes16 alphabet = 0x30313233343536373839616263646566; bytes memory str = new bytes(2 + data.length * 2); str[0] = "0"; str[1] = "x"; for (uint256 i = 0; i < data.length; i++) { str[2 * i + 2] = alphabet[uint8(data[i] >> 4)]; str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)]; } return string(str); } }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _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; } }
< // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./libraries/ReentrancyGuard.sol";
import "./libraries/RevertReasonParser.sol";
import "./libraries/TransferHelper.sol";
import "./libraries/TransitStructs.sol";
import "./libraries/Ownable.sol";
import "./libraries/Pausable.sol";
import "./libraries/SafeMath.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/ITransitSwapFees.sol";

contract TransitSwapRouterV4 is Ownable, ReentrancyGuard, Pausable {

    using SafeMath for uint256;

    address private _transit_swap;
    address private _transit_cross;
    address private _transit_fees;
    //default: Pre-trade fee model
    mapping(uint8 => bool) private _swap_type_mode;
    //whitelist wrapped
    mapping(address => bool) private _wrapped_allowed;

    event Receipt(address from, uint256 amount);
    event Withdraw(address indexed token, address indexed executor, address indexed recipient, uint amount);
    event ChangeTransitSwap(address indexed previousTransit, address indexed newTransit);
    event ChangeTransitCross(address indexed previousTransit, address indexed newTransit);
    event ChangeTransitFees(address indexed previousTransitFees, address indexed newTransitFees);
    event ChangeSwapTypeMode(uint8[] types, bool[] newModes);
    event ChangeWrappedAllowed(address[] wrappeds, bool[] newAllowed);
    event TransitSwapped(address indexed srcToken, address indexed dstToken, address indexed dstReceiver, address trader, bool feeMode, uint256 amount, uint256 returnAmount, uint256 minReturnAmount, uint256 fee, uint256 toChainID, string channel, uint256 time);


    constructor(address transitSwap_, address transitCross_, address transitFees_, address executor) Ownable (executor) {
        _transit_swap = transitSwap_;
        _transit_cross = transitCross_;
        _transit_fees = transitFees_;
    }

    receive() external payable {
        emit Receipt(msg.sender, msg.value);
    }

    function transitSwap() external view returns (address) {
        return _transit_swap;
    }

    function transitCross() external view returns (address) {
        return _transit_cross;
    }

    function transitFees() external view returns (address) {
        return _transit_fees;
    }

    function swapTypeMode(uint8 swapType) external view returns (bool) {
        return _swap_type_mode[swapType];
    }

    function wrappedAllowed(address wrapped) external view returns (bool) {
        return _wrapped_allowed[wrapped];
    }

    function changeTransitSwap(address newTransit) external onlyExecutor {
        address oldTransit = _transit_swap;
        _transit_swap = newTransit;
        emit ChangeTransitSwap(oldTransit, newTransit);
    }

    function changeTransitCross(address newTransit) external onlyExecutor {
        address oldTransit = _transit_cross;
        _transit_cross = newTransit;
        emit ChangeTransitCross(oldTransit, newTransit);
    }

    function changeTransitFees(address newTransitFees) external onlyExecutor {
        address oldTransitFees = _transit_fees;
        _transit_fees = newTransitFees;
        emit ChangeTransitFees(oldTransitFees, newTransitFees);
    }

    function changeSwapTypeMode(uint8[] memory swapTypes) external onlyExecutor {
        bool[] memory newModes = new bool[](swapTypes.length);
        for (uint index; index < swapTypes.length; index++) {
            _swap_type_mode[swapTypes[index]] = !_swap_type_mode[swapTypes[index]];
            newModes[index] = _swap_type_mode[swapTypes[index]];
        }
        emit ChangeSwapTypeMode(swapTypes, newModes);
    }

    function changeWrappedAllowed(address[] calldata wrappeds) external onlyExecutor {
        bool[] memory newAllowed = new bool[](wrappeds.length);
        for (uint index; index < wrappeds.length; index++) {
            _wrapped_allowed[wrappeds[index]] = !_wrapped_allowed[wrappeds[index]];
            newAllowed[index] = _wrapped_allowed[wrappeds[index]];
        }
        emit ChangeWrappedAllowed(wrappeds, newAllowed);
    }

    function changePause(bool paused) external onlyExecutor {
        if (paused) {
            _pause();
        } else {
            _unpause();
        }
    }

    function _beforeSwap(bool preTradeModel, TransitStructs.TransitSwapDescription calldata desc) private returns (uint256 swapAmount, uint256 fee, uint256 beforeBalance) {
        if (preTradeModel) {
            fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, desc.amount, desc.swapType, desc.channel);
        }
        if (TransferHelper.isETH(desc.srcToken)) {
            require(msg.value == desc.amount, "TransitSwap: invalid msg.value");
            swapAmount = desc.amount.sub(fee);
        } else {
            if (preTradeModel) {
                TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, address(this), desc.amount);
                TransferHelper.safeTransfer(desc.srcToken, desc.srcReceiver, desc.amount.sub(fee));
            } else {
                TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, desc.srcReceiver, desc.amount);
            }
        }
        if (TransferHelper.isETH(desc.dstToken)) {
            if (preTradeModel) {
                beforeBalance = desc.dstReceiver.balance;
            } else {
                if (desc.swapType == uint8(TransitStructs.SwapTypes.swap)) {
                    require(_wrapped_allowed[desc.wrappedNative], "TransitSwap: invalid wrapped address");
                    beforeBalance = IERC20(desc.wrappedNative).balanceOf(address(this));
                } else {
                    beforeBalance = address(this).balance;
                }
            }
        } else {
            if (preTradeModel) {
                beforeBalance = IERC20(desc.dstToken).balanceOf(desc.dstReceiver);
            } else {
                beforeBalance = IERC20(desc.dstToken).balanceOf(address(this));
            }
        }
    }

    function _afterSwap(bool preTradeModel, TransitStructs.TransitSwapDescription calldata desc, uint256 beforeBalance) private returns (uint256 returnAmount, uint256 fee) {
        if (TransferHelper.isETH(desc.dstToken)) {
            if (preTradeModel) {
                returnAmount = desc.dstReceiver.balance.sub(beforeBalance);
                require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount");
            } else {
                if (desc.swapType == uint8(TransitStructs.SwapTypes.swap)) {
                    returnAmount = IERC20(desc.wrappedNative).balanceOf(address(this)).sub(beforeBalance);
                    require(_wrapped_allowed[desc.wrappedNative], "TransitSwap: invalid wrapped address");
                    TransferHelper.safeWithdraw(desc.wrappedNative, returnAmount);
                } else {
                    returnAmount = address(this).balance.sub(beforeBalance);
                }
                fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, returnAmount, desc.swapType, desc.channel);
                returnAmount = returnAmount.sub(fee);
                require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount");
                TransferHelper.safeTransferETH(desc.dstReceiver, returnAmount);
            }
        } else {
            if (preTradeModel) {
                returnAmount = IERC20(desc.dstToken).balanceOf(desc.dstReceiver).sub(beforeBalance);
                require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount");
            } else {
                returnAmount = IERC20(desc.dstToken).balanceOf(address(this)).sub(beforeBalance);
                fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, returnAmount, desc.swapType, desc.channel);
                returnAmount = returnAmount.sub(fee);
                uint256 receiverBeforeBalance = IERC20(desc.dstToken).balanceOf(desc.dstReceiver);
                TransferHelper.safeTransfer(desc.dstToken, desc.dstReceiver, returnAmount);
                returnAmount = IERC20(desc.dstToken).balanceOf(desc.dstReceiver).sub(receiverBeforeBalance);
                require(returnAmount >= desc.minReturnAmount, "TransitSwap: insufficient return amount");
            }
        }        
    }

    function swap(TransitStructs.TransitSwapDescription calldata desc, TransitStructs.CallbytesDescription calldata callbytesDesc) external payable nonReentrant whenNotPaused {
        require(callbytesDesc.calldatas.length > 0, "TransitSwap: data should be not zero");
        require(desc.amount > 0, "TransitSwap: amount should be greater than 0");
        require(desc.dstReceiver != address(0), "TransitSwap: receiver should be not address(0)");
        require(desc.minReturnAmount > 0, "TransitSwap: minReturnAmount should be greater than 0");
        if (callbytesDesc.flag == uint8(TransitStructs.Flag.aggregate)) {
            require(desc.srcToken == callbytesDesc.srcToken, "TransitSwap: invalid callbytesDesc");
        }
        bool preTradeModel = !_swap_type_mode[desc.swapType];
        (uint256 swapAmount, uint256 fee, uint256 beforeBalance) = _beforeSwap(preTradeModel, desc);

        {
            //bytes4(keccak256(bytes('callbytes(TransitStructs.CallbytesDescription)')));
            (bool success, bytes memory result) = _transit_swap.call{value:swapAmount}(abi.encodeWithSelector(0xccbe4007, callbytesDesc));
            if (!success) {
                revert(RevertReasonParser.parse(result,"TransitSwap:"));
            }
        }

        (uint256 returnAmount, uint256 postFee) = _afterSwap(preTradeModel, desc, beforeBalance);
        if (postFee > fee) {
            fee = postFee;
        }
        _emitTransit(desc, preTradeModel, fee, returnAmount);
    }

    function _beforeCross(TransitStructs.TransitSwapDescription calldata desc) private returns (uint256 swapAmount, uint256 fee, uint256 beforeBalance) {
        fee = ITransitSwapFees(_transit_fees).getFeeRate(msg.sender, desc.amount, desc.swapType, desc.channel);
        if (TransferHelper.isETH(desc.srcToken)) {
            require(msg.value == desc.amount, "TransitSwap: invalid msg.value");
            swapAmount = desc.amount.sub(fee);
        } else {
            beforeBalance = IERC20(desc.srcToken).balanceOf(_transit_cross);
            if (fee == 0) {
                TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, _transit_cross, desc.amount);
            } else {
                TransferHelper.safeTransferFrom(desc.srcToken, msg.sender, address(this), desc.amount);
                TransferHelper.safeTransfer(desc.srcToken, _transit_cross, desc.amount.sub(fee));
            }
        }
    }

    function cross(TransitStructs.TransitSwapDescription calldata desc, TransitStructs.CallbytesDescription calldata callbytesDesc) external payable nonReentrant whenNotPaused {
        require(callbytesDesc.calldatas.length > 0, "TransitSwap: data should be not zero");
        require(desc.amount > 0, "TransitSwap: amount should be greater than 0");
        require(desc.srcToken == callbytesDesc.srcToken, "TransitSwap: invalid callbytesDesc");
        (uint256 swapAmount, uint256 fee, uint256 beforeBalance) = _beforeCross(desc);
        
        {
            //bytes4(keccak256(bytes('callbytes(TransitStructs.CallbytesDescription)')));
            (bool success, bytes memory result) = _transit_cross.call{value:swapAmount}(abi.encodeWithSelector(0xccbe4007, callbytesDesc));
            if (!success) {
                revert(RevertReasonParser.parse(result,"TransitSwap:"));
            }
        }
        
        if (!TransferHelper.isETH(desc.srcToken)) {
            require(IERC20(desc.srcToken).balanceOf(_transit_cross) >= beforeBalance, "TransitSwap: invalid cross");
        }

        _emitTransit(desc, true, fee, 0);
    }

    function _emitTransit(TransitStructs.TransitSwapDescription calldata desc, bool preTradeModel, uint256 fee, uint256 returnAmount) private {
        emit TransitSwapped(
            desc.srcToken, 
            desc.dstToken, 
            desc.dstReceiver, 
            msg.sender, 
            preTradeModel, 
            desc.amount, 
            returnAmount, 
            desc.minReturnAmount, 
            fee, 
            desc.toChainID, 
            desc.channel,
            block.timestamp
        );
    }

    function withdrawTokens(address[] memory tokens, address recipient) external onlyExecutor {
        for(uint index; index < tokens.length; index++) {
            uint amount;
            if(TransferHelper.isETH(tokens[index])) {
                amount = address(this).balance;
                TransferHelper.safeTransferETH(recipient, amount);
            } else {
                amount = IERC20(tokens[index]).balanceOf(address(this));
                TransferHelper.safeTransferWithoutRequire(tokens[index], recipient, amount);
            }
            emit Withdraw(tokens[index], msg.sender, recipient, amount);
        }
    }
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.9;

interface ITransitSwapFees {
    
    function getFeeRate(address trader, uint256 tradeAmount, uint8 swapType, string memory channel) external  view returns (uint payFees);

}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.9;

interface IERC20 {
    
    function totalSupply() external view returns (uint256);
    function decimals() external view returns (uint8);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
 
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

library SafeMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, 'ds-math-add-overflow');
    }

    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, 'ds-math-sub-underflow');
    }

    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
    }
    
    function div(uint x, uint y) internal pure returns (uint z) {
        require(y != 0 , 'ds-math-div-zero');
        z = x / y;
    }
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
// Add executor extension

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable {
    address private _owner;
    address private _pendingOwner;
    address private _executor;
    address private _pendingExecutor;
    bool internal _initialized;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event ExecutorshipTransferStarted(address indexed previousExecutor, address indexed newExecutor);
    event ExecutorshipTransferred(address indexed previousExecutor, address indexed newExecutor);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor(address newExecutor) {
        require(!_initialized, "Ownable: initialized");
        _transferOwnership(msg.sender);
        _transferExecutorship(newExecutor);
        _initialized = true;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Throws if called by any account other than the executor.
     */
    modifier onlyExecutor() {
        _checkExecutor();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Returns the address of the current executor.
     */
    function executor() public view virtual returns (address) {
        return _executor;
    }

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Returns the address of the pending executor.
     */
    function pendingExecutor() public view virtual returns (address) {
        return _pendingExecutor;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
    }

    /**
     * @dev Throws if the sender is not the executor.
     */
    function _checkExecutor() internal view virtual {
        require(executor() == msg.sender, "Ownable: caller is not the executor");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers executorship of the contract to a new account (`newExecutor`).
     * Can only be called by the current executor.
     */
    function transferExecutorship(address newExecutor) public virtual onlyExecutor {
        _pendingExecutor = newExecutor;
        emit ExecutorshipTransferStarted(executor(), newExecutor);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        delete _pendingOwner;
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    function _transferExecutorship(address newExecutor) internal virtual {
        delete _pendingExecutor;
        address oldExecutor = _executor;
        _executor = newExecutor;
        emit ExecutorshipTransferred(oldExecutor, newExecutor);
    }

    function acceptOwnership() external {
        address sender = msg.sender;
        require(pendingOwner() == sender, "Ownable: caller is not the new owner");
        _transferOwnership(sender);
    }

    function acceptExecutorship() external {
        address sender = msg.sender;
        require(pendingExecutor() == sender, "Ownable: caller is not the new executor");
        _transferExecutorship(sender);
    }
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library TransitStructs {

    enum SwapTypes {aggregatePreMode, aggregatePostMode, swap, cross}
    enum Flag {aggregate, swap, cross}

    struct TransitSwapDescription {
        uint8 swapType;
        address srcToken;
        address dstToken;
        address srcReceiver;
        address dstReceiver;
        uint256 amount;
        uint256 minReturnAmount;
        string channel;
        uint256 toChainID;
        address wrappedNative;
    }

    struct CallbytesDescription {
        uint8 flag;
        address srcToken;
        bytes calldatas;
    }

    struct AggregateDescription {
        address dstToken;
        address receiver;
        uint[] amounts;
        uint[] needTransfer;
        address[] callers;
        address[] approveProxy;
        bytes[] calls;
    }

    struct SwapDescription {
        address[][] paths;
        address[][] pairs;
        uint[] fees;
        address receiver;
        uint deadline;
    }

    struct CrossDescription {
        address caller;
        uint256 amount;
        bool needWrapped;
        bytes calls;
    }

    function decodeAggregateDesc(bytes calldata calldatas) internal pure returns (AggregateDescription memory desc) {
        desc = abi.decode(calldatas, (AggregateDescription));
    }

    function decodeSwapDesc(bytes calldata calldatas) internal pure returns (SwapDescription memory desc) {
        desc = abi.decode(calldatas, (SwapDescription));
    }

    function decodeCrossDesc(bytes calldata calldatas) internal pure returns (CrossDescription memory desc) {
        desc = abi.decode(calldatas, (CrossDescription));
    }
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

library TransferHelper {
    
    address private constant _ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    address private constant _ZERO_ADDRESS = address(0);
    
    function isETH(address token) internal pure returns (bool) {
        return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS);
    }
    
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_TOKEN_FAILED');
    }
    
    function safeTransferWithoutRequire(address token, address to, uint256 value) internal returns (bool) {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        return (success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        // solium-disable-next-line
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: TRANSFER_FAILED');
    }

    function safeDeposit(address wrapped, uint value) internal {
        // bytes4(keccak256(bytes('deposit()')));
        (bool success, bytes memory data) = wrapped.call{value:value}(abi.encodeWithSelector(0xd0e30db0));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: DEPOSIT_FAILED');
    }

    function safeWithdraw(address wrapped, uint value) internal {
        // bytes4(keccak256(bytes('withdraw(uint256 wad)')));
        (bool success, bytes memory data) = wrapped.call{value:0}(abi.encodeWithSelector(0x2e1a7d4d, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: WITHDRAW_FAILED');
    }
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

library RevertReasonParser {
        function parse(bytes memory data, string memory prefix) internal pure returns (string memory) {
        // https://solidity.readthedocs.io/en/latest/control-structures.html#revert
        // We assume that revert reason is abi-encoded as Error(string)

        // 68 = 4-byte selector 0x08c379a0 + 32 bytes offset + 32 bytes length
        if (data.length >= 68 && data[0] == "\x08" && data[1] == "\xc3" && data[2] == "\x79" && data[3] == "\xa0") {
            string memory reason;
            // solhint-disable no-inline-assembly
            assembly {
                // 68 = 32 bytes data length + 4-byte selector + 32 bytes offset
                reason := add(data, 68)
            }
            /*
                revert reason is padded up to 32 bytes with ABI encoder: Error(string)
                also sometimes there is extra 32 bytes of zeros padded in the end:
                https://github.com/ethereum/solidity/issues/10170
                because of that we can't check for equality and instead check
                that string length + extra 68 bytes is less than overall data length
            */
            require(data.length >= 68 + bytes(reason).length, "Invalid revert reason");
            return string(abi.encodePacked(prefix, "Error(", reason, ")"));
        }
        // 36 = 4-byte selector 0x4e487b71 + 32 bytes integer
        else if (data.length == 36 && data[0] == "\x4e" && data[1] == "\x48" && data[2] == "\x7b" && data[3] == "\x71") {
            uint256 code;
            // solhint-disable no-inline-assembly
            assembly {
                // 36 = 32 bytes data length + 4-byte selector
                code := mload(add(data, 36))
            }
            return string(abi.encodePacked(prefix, "Panic(", _toHex(code), ")"));
        }

        return string(abi.encodePacked(prefix, "Unknown(", _toHex(data), ")"));
    }
    
    function _toHex(uint256 value) private pure returns(string memory) {
        return _toHex(abi.encodePacked(value));
    }

    function _toHex(bytes memory data) private pure returns(string memory) {
        bytes16 alphabet = 0x30313233343536373839616263646566;
        bytes memory str = new bytes(2 + data.length * 2);
        str[0] = "0";
        str[1] = "x";
        for (uint256 i = 0; i < data.length; i++) {
            str[2 * i + 2] = alphabet[uint8(data[i] >> 4)];
            str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)];
        }
        return string(str);
    }
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _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;
    }
} < 

TransitSwapRouterV4 ABI

[{"inputs":[{"internalType":"address","name":"transitSwap_","type":"address"},{"internalType":"address","name":"transitCross_","type":"address"},{"internalType":"address","name":"transitFees_","type":"address"},{"internalType":"address","name":"executor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8[]","name":"types","type":"uint8[]"},{"indexed":false,"internalType":"bool[]","name":"newModes","type":"bool[]"}],"name":"ChangeSwapTypeMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransit","type":"address"},{"indexed":true,"internalType":"address","name":"newTransit","type":"address"}],"name":"ChangeTransitCross","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransitFees","type":"address"},{"indexed":true,"internalType":"address","name":"newTransitFees","type":"address"}],"name":"ChangeTransitFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransit","type":"address"},{"indexed":true,"internalType":"address","name":"newTransit","type":"address"}],"name":"ChangeTransitSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"wrappeds","type":"address[]"},{"indexed":false,"internalType":"bool[]","name":"newAllowed","type":"bool[]"}],"name":"ChangeWrappedAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousExecutor","type":"address"},{"indexed":true,"internalType":"address","name":"newExecutor","type":"address"}],"name":"ExecutorshipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousExecutor","type":"address"},{"indexed":true,"internalType":"address","name":"newExecutor","type":"address"}],"name":"ExecutorshipTransferred","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Receipt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"srcToken","type":"address"},{"indexed":true,"internalType":"address","name":"dstToken","type":"address"},{"indexed":true,"internalType":"address","name":"dstReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"bool","name":"feeMode","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChainID","type":"uint256"},{"indexed":false,"internalType":"string","name":"channel","type":"string"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"TransitSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"acceptExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"changePause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"swapTypes","type":"uint8[]"}],"name":"changeSwapTypeMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransit","type":"address"}],"name":"changeTransitCross","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransitFees","type":"address"}],"name":"changeTransitFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransit","type":"address"}],"name":"changeTransitSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"wrappeds","type":"address[]"}],"name":"changeWrappedAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"swapType","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"srcReceiver","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"address","name":"wrappedNative","type":"address"}],"internalType":"struct TransitStructs.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"uint8","name":"flag","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct TransitStructs.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"cross","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingExecutor","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":[{"components":[{"internalType":"uint8","name":"swapType","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"srcReceiver","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"address","name":"wrappedNative","type":"address"}],"internalType":"struct TransitStructs.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"uint8","name":"flag","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct TransitStructs.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"swapType","type":"uint8"}],"name":"swapTypeMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newExecutor","type":"address"}],"name":"transferExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transitCross","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitFees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitSwap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wrapped","type":"address"}],"name":"wrappedAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
[{"inputs":[{"internalType":"address","name":"transitSwap_","type":"address"},{"internalType":"address","name":"transitCross_","type":"address"},{"internalType":"address","name":"transitFees_","type":"address"},{"internalType":"address","name":"executor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8[]","name":"types","type":"uint8[]"},{"indexed":false,"internalType":"bool[]","name":"newModes","type":"bool[]"}],"name":"ChangeSwapTypeMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransit","type":"address"},{"indexed":true,"internalType":"address","name":"newTransit","type":"address"}],"name":"ChangeTransitCross","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransitFees","type":"address"},{"indexed":true,"internalType":"address","name":"newTransitFees","type":"address"}],"name":"ChangeTransitFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTransit","type":"address"},{"indexed":true,"internalType":"address","name":"newTransit","type":"address"}],"name":"ChangeTransitSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"wrappeds","type":"address[]"},{"indexed":false,"internalType":"bool[]","name":"newAllowed","type":"bool[]"}],"name":"ChangeWrappedAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousExecutor","type":"address"},{"indexed":true,"internalType":"address","name":"newExecutor","type":"address"}],"name":"ExecutorshipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousExecutor","type":"address"},{"indexed":true,"internalType":"address","name":"newExecutor","type":"address"}],"name":"ExecutorshipTransferred","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Receipt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"srcToken","type":"address"},{"indexed":true,"internalType":"address","name":"dstToken","type":"address"},{"indexed":true,"internalType":"address","name":"dstReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"bool","name":"feeMode","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChainID","type":"uint256"},{"indexed":false,"internalType":"string","name":"channel","type":"string"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"TransitSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"acceptExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"changePause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"swapTypes","type":"uint8[]"}],"name":"changeSwapTypeMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransit","type":"address"}],"name":"changeTransitCross","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransitFees","type":"address"}],"name":"changeTransitFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTransit","type":"address"}],"name":"changeTransitSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"wrappeds","type":"address[]"}],"name":"changeWrappedAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"swapType","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"srcReceiver","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"address","name":"wrappedNative","type":"address"}],"internalType":"struct TransitStructs.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"uint8","name":"flag","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct TransitStructs.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"cross","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingExecutor","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":[{"components":[{"internalType":"uint8","name":"swapType","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"srcReceiver","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"address","name":"wrappedNative","type":"address"}],"internalType":"struct TransitStructs.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"uint8","name":"flag","type":"uint8"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct TransitStructs.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"swapType","type":"uint8"}],"name":"swapTypeMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newExecutor","type":"address"}],"name":"transferExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transitCross","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitFees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitSwap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wrapped","type":"address"}],"name":"wrappedAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

TransitSwapRouterV4 Bytecode

60806040523480156200001157600080fd5b5060405162003697380380620036978339810160408190526200003491620001e4565b6003548190600160a01b900460ff1615620000955760405162461bcd60e51b815260206004820152601460248201527f4f776e61626c653a20696e697469616c697a6564000000000000000000000000604482015260640160405180910390fd5b620000a03362000110565b620000ab816200016a565b50506003805460ff60a01b1916600160a01b1790556001600455600580546001600160a01b03948516610100026001600160a81b0319909116179055600680549284166001600160a01b03199384161790556007805491909316911617905562000241565b600180546001600160a01b0319908116909155600080546001600160a01b03848116938216841783556040519116929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600380546001600160a01b0319908116909155600280546001600160a01b0384811693821684179092556040519116919082907f88436636ea40d5bb1bcc55ff9cd54788af71da886f4147a87f199adcca733d4d90600090a35050565b80516001600160a01b0381168114620001df57600080fd5b919050565b60008060008060808587031215620001fb57600080fd5b6200020685620001c7565b93506200021660208601620001c7565b92506200022660408601620001c7565b91506200023660608601620001c7565b905092959194509250565b61344680620002516000396000f3fe60806040526004361061014f5760003560e01c8063afed2d0e116100b6578063d63234e01161006f578063d63234e0146103e2578063dc69bbad14610400578063e30c397814610420578063e8e1bc5d1461043e578063f2fde38b1461045e578063f8c79f731461047e57600080fd5b8063afed2d0e1461031e578063c10bea5c1461033e578063c34c08e514610351578063c3dc51fe1461036f578063c58dff5c1461038f578063c6c46552146103c257600080fd5b8063715018a611610108578063715018a61461028057806379ba509714610295578063845b1f77146102aa5780638da5cb5b146102cd57806394752e82146102eb57806394d3d7931461030957600080fd5b8063017efb28146101935780630e8cc705146101a85780633932a93c146101c857806351205349146102165780635c975abb146102485780635d4fead31461026057600080fd5b3661018e57604080513381523460208201527f7784f8d436dc514f0690e472c7e2d7f660a73e504c69b2350f6be5a5f02432ef910160405180910390a1005b600080fd5b6101a66101a1366004612b08565b61049e565b005b3480156101b457600080fd5b506101a66101c3366004612c03565b61076f565b3480156101d457600080fd5b506102016101e3366004612cb2565b6001600160a01b031660009081526009602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561022257600080fd5b506007546001600160a01b03165b6040516001600160a01b03909116815260200161020d565b34801561025457600080fd5b5060055460ff16610201565b34801561026c57600080fd5b506101a661027b366004612ce2565b6108f3565b34801561028c57600080fd5b506101a6610914565b3480156102a157600080fd5b506101a6610928565b3480156102b657600080fd5b5060055461010090046001600160a01b0316610230565b3480156102d957600080fd5b506000546001600160a01b0316610230565b3480156102f757600080fd5b506006546001600160a01b0316610230565b34801561031557600080fd5b506101a66109a7565b34801561032a57600080fd5b506101a6610339366004612cb2565b610a2a565b6101a661034c366004612b08565b610a9b565b34801561035d57600080fd5b506002546001600160a01b0316610230565b34801561037b57600080fd5b506101a661038a366004612d10565b610dbe565b34801561039b57600080fd5b506102016103aa366004612da8565b60ff9081166000908152600860205260409020541690565b3480156103ce57600080fd5b506101a66103dd366004612cb2565b610f56565b3480156103ee57600080fd5b506003546001600160a01b0316610230565b34801561040c57600080fd5b506101a661041b366004612cb2565b610fb0565b34801561042c57600080fd5b506001546001600160a01b0316610230565b34801561044a57600080fd5b506101a6610459366004612cb2565b611012565b34801561046a57600080fd5b506101a6610479366004612cb2565b61106c565b34801561048a57600080fd5b506101a6610499366004612dc3565b6110dd565b6104a6611299565b6104ae6112f2565b60006104bd6040830183612e38565b9050116104e55760405162461bcd60e51b81526004016104dc90612e86565b60405180910390fd5b60008260a00135116105095760405162461bcd60e51b81526004016104dc90612eca565b6105196040820160208301612cb2565b6001600160a01b03166105326040840160208501612cb2565b6001600160a01b0316146105585760405162461bcd60e51b81526004016104dc90612f16565b600080600061056685611338565b600654604051939650919450925060009182916001600160a01b031690869063ccbe400790610599908a90602401612f81565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516105d29190613035565b60006040518083038185875af1925050503d806000811461060f576040519150601f19603f3d011682016040523d82523d6000602084013e610614565b606091505b5091509150816106655761064c816040518060400160405280600c81526020016b2a3930b739b4ba29bbb0b81d60a11b815250611562565b60405162461bcd60e51b81526004016104dc9190613051565b50610680905061067b6040870160208801612cb2565b6117d9565b61075057806106956040870160208801612cb2565b6006546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156106de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107029190613084565b10156107505760405162461bcd60e51b815260206004820152601a60248201527f5472616e736974537761703a20696e76616c69642063726f737300000000000060448201526064016104dc565b61075e856001846000611812565b50505061076b6001600455565b5050565b6107776118c7565b60005b82518110156108ee5760006107a784838151811061079a5761079a61309d565b60200260200101516117d9565b156107bd5750476107b8838261193c565b61086b565b8382815181106107cf576107cf61309d565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561081f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108439190613084565b905061086984838151811061085a5761085a61309d565b602002602001015184836119f9565b505b826001600160a01b0316336001600160a01b03168584815181106108915761089161309d565b60200260200101516001600160a01b03167f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7846040516108d391815260200190565b60405180910390a450806108e6816130c9565b91505061077a565b505050565b6108fb6118c7565b801561090c57610909611ae3565b50565b610909611b2e565b61091c611b70565b6109266000611bd9565b565b338061093c6001546001600160a01b031690565b6001600160a01b03161461099e5760405162461bcd60e51b8152602060048201526024808201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206e6577206f6044820152633bb732b960e11b60648201526084016104dc565b61090981611bd9565b33806109bb6003546001600160a01b031690565b6001600160a01b031614610a215760405162461bcd60e51b815260206004820152602760248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206e657720656044820152663c32b1baba37b960c91b60648201526084016104dc565b61090981611c33565b610a326118c7565b600380546001600160a01b0383166001600160a01b03199091168117909155610a636002546001600160a01b031690565b6001600160a01b03167fdd01547fc40682edc3cd8d164d53f5a1ae6b46138a83f045658ed760823ddba860405160405180910390a350565b610aa3611299565b610aab6112f2565b6000610aba6040830183612e38565b905011610ad95760405162461bcd60e51b81526004016104dc90612e86565b60008260a0013511610afd5760405162461bcd60e51b81526004016104dc90612eca565b6000610b0f60a0840160808501612cb2565b6001600160a01b031603610b7c5760405162461bcd60e51b815260206004820152602e60248201527f5472616e736974537761703a2072656365697665722073686f756c642062652060448201526d6e6f74206164647265737328302960901b60648201526084016104dc565b60008260c0013511610bee5760405162461bcd60e51b815260206004820152603560248201527f5472616e736974537761703a206d696e52657475726e416d6f756e742073686f6044820152740756c642062652067726561746572207468616e203605c1b60648201526084016104dc565b6000610bfd6020830183612da8565b60ff1603610c5457610c156040820160208301612cb2565b6001600160a01b0316610c2e6040840160208501612cb2565b6001600160a01b031614610c545760405162461bcd60e51b81526004016104dc90612f16565b6000600881610c666020860186612da8565b60ff908116825260208201929092526040016000908120549091161591508080610c908487611c90565b925092509250600080600560019054906101000a90046001600160a01b03166001600160a01b03168563ccbe400789604051602401610ccf9190612f81565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051610d089190613035565b60006040518083038185875af1925050503d8060008114610d45576040519150601f19603f3d011682016040523d82523d6000602084013e610d4a565b606091505b509150915081610d825761064c816040518060400160405280600c81526020016b2a3930b739b4ba29bbb0b81d60a11b815250611562565b5050600080610d92868985612041565b9150915083811115610da2578093505b610dae88878685611812565b50505050505061076b6001600455565b610dc66118c7565b6000815167ffffffffffffffff811115610de257610de2612b7c565b604051908082528060200260200182016040528015610e0b578160200160208202803683370190505b50905060005b8251811015610f185760086000848381518110610e3057610e3061309d565b602002602001015160ff1660ff16815260200190815260200160002060009054906101000a900460ff161560086000858481518110610e7157610e7161309d565b602002602001015160ff1660ff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060086000848381518110610eba57610eba61309d565b602002602001015160ff1660ff16815260200190815260200160002060009054906101000a900460ff16828281518110610ef657610ef661309d565b9115156020928302919091019091015280610f10816130c9565b915050610e11565b507f5e69b8fb6404283a560ee2205dc0f225019578c56e3a6c52137e0aa995235b668282604051610f4a92919061311f565b60405180910390a15050565b610f5e6118c7565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907faf855a7e4074e8930caf657b3505942d4ba0e69b6b6e63553c653d7b1ffcc06190600090a35050565b610fb86118c7565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907fbc071769e275808816d09db519c1888c355f7557cb63095ce21e26a97a5f0e9c90600090a35050565b61101a6118c7565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff2ef974bc2aedf0c322b1a97e8627e85114a789cadf8d172b5efb5d6c1d94f8d90600090a35050565b611074611b70565b600180546001600160a01b0383166001600160a01b031990911681179091556110a56000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6110e56118c7565b60008167ffffffffffffffff81111561110057611100612b7c565b604051908082528060200260200182016040528015611129578160200160208202803683370190505b50905060005b82811015611258576009600085858481811061114d5761114d61309d565b90506020020160208101906111629190612cb2565b6001600160a01b03168152602081019190915260400160009081205460ff1615906009908686858181106111985761119861309d565b90506020020160208101906111ad9190612cb2565b6001600160a01b0316815260208101919091526040016000908120805460ff1916921515929092179091556009908585848181106111ed576111ed61309d565b90506020020160208101906112029190612cb2565b6001600160a01b03168152602081019190915260400160002054825160ff909116908390839081106112365761123661309d565b9115156020928302919091019091015280611250816130c9565b91505061112f565b507f4a28b173d9bc739be3886d172e07fef80392184787fc6b92406ce0f0c05b7e6383838360405161128c9392919061316f565b60405180910390a1505050565b6002600454036112eb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104dc565b6002600455565b60055460ff16156109265760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016104dc565b600754600090819081906001600160a01b03166319fa763a3360a08701356113636020890189612da8565b61137060e08a018a612e38565b6040518663ffffffff1660e01b81526004016113909594939291906131c3565b602060405180830381865afa1580156113ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d19190613084565b91506113e661067b6040860160208701612cb2565b15611453578360a00135341461143e5760405162461bcd60e51b815260206004820152601e60248201527f5472616e736974537761703a20696e76616c6964206d73672e76616c7565000060448201526064016104dc565b61144c60a0850135836124e2565b925061155b565b6114636040850160208601612cb2565b6006546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156114ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d09190613084565b90508160000361150a576115056114ed6040860160208701612cb2565b60065433906001600160a01b031660a0880135612538565b61155b565b61152961151d6040860160208701612cb2565b33308760a00135612538565b61155b61153c6040860160208701612cb2565b6006546001600160a01b031661155660a0880135866124e2565b612668565b9193909250565b6060604483511015801561159b5750826000815181106115845761158461309d565b6020910101516001600160f81b031916600160fb1b145b80156115cc5750826001815181106115b5576115b561309d565b6020910101516001600160f81b03191660c360f81b145b80156115fd5750826002815181106115e6576115e661309d565b6020910101516001600160f81b031916607960f81b145b801561162e5750826003815181106116175761161761309d565b6020910101516001600160f81b031916600560fd1b145b156116b85760448381018051909161164691906131f4565b8451101561168e5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103932bb32b93a103932b0b9b7b760591b60448201526064016104dc565b82816040516020016116a1929190613207565b6040516020818303038152906040529150506117d3565b825160241480156116ee5750826000815181106116d7576116d761309d565b6020910101516001600160f81b031916602760f91b145b801561171f5750826001815181106117085761170861309d565b6020910101516001600160f81b031916600960fb1b145b80156117505750826002815181106117395761173961309d565b6020910101516001600160f81b031916607b60f81b145b801561178157508260038151811061176a5761176a61309d565b6020910101516001600160f81b031916607160f81b145b156117a65760248301518261179582612791565b6040516020016116a1929190613256565b816117b0846127b9565b6040516020016117c192919061328b565b60405160208183030381529060405290505b92915050565b60006001600160a01b03821615806117d357506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b61182260a0850160808601612cb2565b6001600160a01b031661183b6060860160408701612cb2565b6001600160a01b03166118546040870160208801612cb2565b6001600160a01b03167f7055e3d08e2c20429c6b162f3e3bee3f426d59896e66084c3580dc353e54129d33878960a00135878b60c001358a8d61010001358e8060e001906118a29190612e38565b426040516118b99a999897969594939291906132dc565b60405180910390a450505050565b336118da6002546001600160a01b031690565b6001600160a01b0316146109265760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652065786563756044820152623a37b960e91b60648201526084016104dc565b604080516000808252602082019092526001600160a01b0384169083906040516119669190613035565b60006040518083038185875af1925050503d80600081146119a3576040519150601f19603f3d011682016040523d82523d6000602084013e6119a8565b606091505b50509050806108ee5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016104dc565b6000806000856001600160a01b031663a9059cbb8686604051602401611a349291906001600160a01b03929092168252602082015260400190565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611a6d9190613035565b6000604051808303816000865af19150503d8060008114611aaa576040519150601f19603f3d011682016040523d82523d6000602084013e611aaf565b606091505b5091509150818015611ad9575080511580611ad9575080806020019051810190611ad9919061333e565b9695505050505050565b611aeb6112f2565b6005805460ff191660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020015b60405180910390a1565b611b366129a1565b6005805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602001611b24565b33611b836000546001600160a01b031690565b6001600160a01b0316146109265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104dc565b600180546001600160a01b0319908116909155600080546001600160a01b03848116938216841783556040519116929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600380546001600160a01b0319908116909155600280546001600160a01b0384811693821684179092556040519116919082907f88436636ea40d5bb1bcc55ff9cd54788af71da886f4147a87f199adcca733d4d90600090a35050565b60008060008415611d30576007546001600160a01b03166319fa763a3360a0870135611cbf6020890189612da8565b611ccc60e08a018a612e38565b6040518663ffffffff1660e01b8152600401611cec9594939291906131c3565b602060405180830381865afa158015611d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2d9190613084565b91505b611d4361067b6040860160208701612cb2565b15611db0578360a001353414611d9b5760405162461bcd60e51b815260206004820152601e60248201527f5472616e736974537761703a20696e76616c6964206d73672e76616c7565000060448201526064016104dc565b611da960a0850135836124e2565b9250611e2d565b8415611dff57611dc961151d6040860160208701612cb2565b611dfa611ddc6040860160208701612cb2565b611dec6080870160608801612cb2565b61155660a0880135866124e2565b611e2d565b611e2d611e126040860160208701612cb2565b33611e236080880160608901612cb2565b8760a00135612538565b611e4061067b6060860160408701612cb2565b15611f5d578415611e6c57611e5b60a0850160808601612cb2565b6001600160a01b031631905061203a565b6002611e7b6020860186612da8565b60ff1603611f565760096000611e9961014087016101208801612cb2565b6001600160a01b0316815260208101919091526040016000205460ff16611ed25760405162461bcd60e51b81526004016104dc9061335b565b611ee461014085016101208601612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a08231906024015b602060405180830381865afa158015611f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4f9190613084565b905061203a565b504761203a565b8415611fbd57611f736060850160408601612cb2565b6001600160a01b03166370a08231611f9160a0870160808801612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401611f0e565b611fcd6060850160408601612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120379190613084565b90505b9250925092565b60008061205761067b6060860160408701612cb2565b156122a65784156120b1576120868361207660a0870160808801612cb2565b6001600160a01b031631906124e2565b91508360c001358210156120ac5760405162461bcd60e51b81526004016104dc9061339f565b6124da565b60026120c06020860186612da8565b60ff16036121c05761214f836120de61014087016101208801612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a08231906024015b602060405180830381865afa158015612125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121499190613084565b906124e2565b91506009600061216761014087016101208801612cb2565b6001600160a01b0316815260208101919091526040016000205460ff166121a05760405162461bcd60e51b81526004016104dc9061335b565b6121bb6121b561014086016101208701612cb2565b836129ea565b6121cd565b6121ca47846124e2565b91505b6007546001600160a01b03166319fa763a33846121ed6020890189612da8565b6121fa60e08a018a612e38565b6040518663ffffffff1660e01b815260040161221a9594939291906131c3565b602060405180830381865afa158015612237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225b9190613084565b905061226782826124e2565b91508360c0013582101561228d5760405162461bcd60e51b81526004016104dc9061339f565b6120ac6122a060a0860160808701612cb2565b8361193c565b841561230a57612086836122c06060870160408801612cb2565b6001600160a01b03166370a082316122de60a0890160808a01612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401612108565b61231e836120de6060870160408801612cb2565b6007549092506001600160a01b03166319fa763a33846123416020890189612da8565b61234e60e08a018a612e38565b6040518663ffffffff1660e01b815260040161236e9594939291906131c3565b602060405180830381865afa15801561238b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123af9190613084565b90506123bb82826124e2565b915060006123cf6060860160408701612cb2565b6001600160a01b03166370a082316123ed60a0880160808901612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124559190613084565b905061248061246a6060870160408801612cb2565b61247a60a0880160808901612cb2565b85612668565b6124b2816124946060880160408901612cb2565b6001600160a01b03166370a082316122de60a08a0160808b01612cb2565b92508460c001358310156124d85760405162461bcd60e51b81526004016104dc9061339f565b505b935093915050565b6000826124ef83826133e6565b91508111156117d35760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b60448201526064016104dc565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161259c9190613035565b6000604051808303816000865af19150503d80600081146125d9576040519150601f19603f3d011682016040523d82523d6000602084013e6125de565b606091505b5091509150818015612608575080511580612608575080806020019051810190612608919061333e565b6126605760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b60648201526084016104dc565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916126c49190613035565b6000604051808303816000865af19150503d8060008114612701576040519150601f19603f3d011682016040523d82523d6000602084013e612706565b606091505b5091509150818015612730575080511580612730575080806020019051810190612730919061333e565b61278a5760405162461bcd60e51b815260206004820152602560248201527f5472616e7366657248656c7065723a205452414e534645525f544f4b454e5f46604482015264105253115160da1b60648201526084016104dc565b5050505050565b60606117d3826040516020016127a991815260200190565b6040516020818303038152906040525b80516060906f181899199a1a9b1b9c1cb0b131b232b360811b906000906127e19060026133f9565b6127ec9060026131f4565b67ffffffffffffffff81111561280457612804612b7c565b6040519080825280601f01601f19166020018201604052801561282e576020820181803683370190505b509050600360fc1b816000815181106128495761284961309d565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106128785761287861309d565b60200101906001600160f81b031916908160001a90535060005b8451811015612999578260048683815181106128b0576128b061309d565b01602001516001600160f81b031916901c60f81c601081106128d4576128d461309d565b1a60f81b826128e48360026133f9565b6128ef9060026131f4565b815181106128ff576128ff61309d565b60200101906001600160f81b031916908160001a905350828582815181106129295761292961309d565b60209101015160f81c600f16601081106129455761294561309d565b1a60f81b826129558360026133f9565b6129609060036131f4565b815181106129705761297061309d565b60200101906001600160f81b031916908160001a90535080612991816130c9565b915050612892565b509392505050565b60055460ff166109265760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016104dc565b600080836001600160a01b03166000632e1a7d4d85604051602401612a1191815260200190565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612a4a9190613035565b60006040518083038185875af1925050503d8060008114612a87576040519150601f19603f3d011682016040523d82523d6000602084013e612a8c565b606091505b5091509150818015612ab6575080511580612ab6575080806020019051810190612ab6919061333e565b612b025760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a2057495448445241575f4641494c45440060448201526064016104dc565b50505050565b60008060408385031215612b1b57600080fd5b823567ffffffffffffffff80821115612b3357600080fd5b908401906101408287031215612b4857600080fd5b90925060208401359080821115612b5e57600080fd5b50830160608186031215612b7157600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612bbb57612bbb612b7c565b604052919050565b600067ffffffffffffffff821115612bdd57612bdd612b7c565b5060051b60200190565b80356001600160a01b0381168114612bfe57600080fd5b919050565b60008060408385031215612c1657600080fd5b823567ffffffffffffffff811115612c2d57600080fd5b8301601f81018513612c3e57600080fd5b80356020612c53612c4e83612bc3565b612b92565b82815260059290921b83018101918181019088841115612c7257600080fd5b938201935b83851015612c9757612c8885612be7565b82529382019390820190612c77565b9550612ca69050868201612be7565b93505050509250929050565b600060208284031215612cc457600080fd5b612ccd82612be7565b9392505050565b801515811461090957600080fd5b600060208284031215612cf457600080fd5b8135612ccd81612cd4565b803560ff81168114612bfe57600080fd5b60006020808385031215612d2357600080fd5b823567ffffffffffffffff811115612d3a57600080fd5b8301601f81018513612d4b57600080fd5b8035612d59612c4e82612bc3565b81815260059190911b82018301908381019087831115612d7857600080fd5b928401925b82841015612d9d57612d8e84612cff565b82529284019290840190612d7d565b979650505050505050565b600060208284031215612dba57600080fd5b612ccd82612cff565b60008060208385031215612dd657600080fd5b823567ffffffffffffffff80821115612dee57600080fd5b818501915085601f830112612e0257600080fd5b813581811115612e1157600080fd5b8660208260051b8501011115612e2657600080fd5b60209290920196919550909350505050565b6000808335601e19843603018112612e4f57600080fd5b83018035915067ffffffffffffffff821115612e6a57600080fd5b602001915036819003821315612e7f57600080fd5b9250929050565b60208082526024908201527f5472616e736974537761703a20646174612073686f756c64206265206e6f74206040820152637a65726f60e01b606082015260800190565b6020808252602c908201527f5472616e736974537761703a20616d6f756e742073686f756c6420626520677260408201526b06561746572207468616e20360a41b606082015260800190565b60208082526022908201527f5472616e736974537761703a20696e76616c69642063616c6c62797465734465604082015261736360f01b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260ff612f9083612cff565b16602082015260018060a01b03612fa960208401612be7565b16604082015260006040830135601e19843603018112612fc857600080fd5b830160208101903567ffffffffffffffff811115612fe557600080fd5b803603821315612ff457600080fd5b606080850152613008608085018284612f58565b95945050505050565b60005b8381101561302c578181015183820152602001613014565b50506000910152565b60008251613047818460208701613011565b9190910192915050565b6020815260008251806020840152613070816040850160208701613011565b601f01601f19169190910160400192915050565b60006020828403121561309657600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016130db576130db6130b3565b5060010190565b600081518084526020808501945080840160005b838110156131145781511515875295820195908201906001016130f6565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b8281101561315b57815160ff168452928401929084019060010161313c565b50505083810382850152611ad981866130e2565b6040808252810183905260008460608301825b868110156131b0576001600160a01b0361319b84612be7565b16825260209283019290910190600101613182565b508381036020850152612d9d81866130e2565b60018060a01b038616815284602082015260ff84166040820152608060608201526000612d9d608083018486612f58565b808201808211156117d3576117d36130b3565b60008351613219818460208801613011565b6508ae4e4dee4560d31b908301908152835161323c816006840160208801613011565b602960f81b60069290910191820152600701949350505050565b60008351613268818460208801613011565b650a0c2dcd2c6560d31b908301908152835161323c816006840160208801613011565b6000835161329d818460208801613011565b670aadcd6dcdeeedc560c31b90830190815283516132c2816008840160208801613011565b602960f81b60089290910191820152600901949350505050565b600061012060018060a01b038d1683528b151560208401528a60408401528960608401528860808401528760a08401528660c08401528060e08401526133258184018688612f58565b915050826101008301529b9a5050505050505050505050565b60006020828403121561335057600080fd5b8151612ccd81612cd4565b60208082526024908201527f5472616e736974537761703a20696e76616c69642077726170706564206164646040820152637265737360e01b606082015260800190565b60208082526027908201527f5472616e736974537761703a20696e73756666696369656e742072657475726e60408201526608185b5bdd5b9d60ca1b606082015260800190565b818103818111156117d3576117d36130b3565b80820281158282048414176117d3576117d36130b356fea2646970667358221220e17c9f74d89f6274faaf48b4224f03f82f32783ebfdadf5d8ffbf445abc1ded064736f6c63430008110033000000000000000000000000f7a2f863299c17dfa11cd8a14e7c7dca92f315b90000000000000000000000008755773dc777b9f9b2e2c86402a03f099f8236910000000000000000000000001f6e41c47349634fe261403a18f8515546f58826000000000000000000000000280333c41a9302448ebc070ed0300ad2ed4b8244
60806040523480156200001157600080fd5b5060405162003697380380620036978339810160408190526200003491620001e4565b6003548190600160a01b900460ff1615620000955760405162461bcd60e51b815260206004820152601460248201527f4f776e61626c653a20696e697469616c697a6564000000000000000000000000604482015260640160405180910390fd5b620000a03362000110565b620000ab816200016a565b50506003805460ff60a01b1916600160a01b1790556001600455600580546001600160a01b03948516610100026001600160a81b0319909116179055600680549284166001600160a01b03199384161790556007805491909316911617905562000241565b600180546001600160a01b0319908116909155600080546001600160a01b03848116938216841783556040519116929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600380546001600160a01b0319908116909155600280546001600160a01b0384811693821684179092556040519116919082907f88436636ea40d5bb1bcc55ff9cd54788af71da886f4147a87f199adcca733d4d90600090a35050565b80516001600160a01b0381168114620001df57600080fd5b919050565b60008060008060808587031215620001fb57600080fd5b6200020685620001c7565b93506200021660208601620001c7565b92506200022660408601620001c7565b91506200023660608601620001c7565b905092959194509250565b61344680620002516000396000f3fe60806040526004361061014f5760003560e01c8063afed2d0e116100b6578063d63234e01161006f578063d63234e0146103e2578063dc69bbad14610400578063e30c397814610420578063e8e1bc5d1461043e578063f2fde38b1461045e578063f8c79f731461047e57600080fd5b8063afed2d0e1461031e578063c10bea5c1461033e578063c34c08e514610351578063c3dc51fe1461036f578063c58dff5c1461038f578063c6c46552146103c257600080fd5b8063715018a611610108578063715018a61461028057806379ba509714610295578063845b1f77146102aa5780638da5cb5b146102cd57806394752e82146102eb57806394d3d7931461030957600080fd5b8063017efb28146101935780630e8cc705146101a85780633932a93c146101c857806351205349146102165780635c975abb146102485780635d4fead31461026057600080fd5b3661018e57604080513381523460208201527f7784f8d436dc514f0690e472c7e2d7f660a73e504c69b2350f6be5a5f02432ef910160405180910390a1005b600080fd5b6101a66101a1366004612b08565b61049e565b005b3480156101b457600080fd5b506101a66101c3366004612c03565b61076f565b3480156101d457600080fd5b506102016101e3366004612cb2565b6001600160a01b031660009081526009602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561022257600080fd5b506007546001600160a01b03165b6040516001600160a01b03909116815260200161020d565b34801561025457600080fd5b5060055460ff16610201565b34801561026c57600080fd5b506101a661027b366004612ce2565b6108f3565b34801561028c57600080fd5b506101a6610914565b3480156102a157600080fd5b506101a6610928565b3480156102b657600080fd5b5060055461010090046001600160a01b0316610230565b3480156102d957600080fd5b506000546001600160a01b0316610230565b3480156102f757600080fd5b506006546001600160a01b0316610230565b34801561031557600080fd5b506101a66109a7565b34801561032a57600080fd5b506101a6610339366004612cb2565b610a2a565b6101a661034c366004612b08565b610a9b565b34801561035d57600080fd5b506002546001600160a01b0316610230565b34801561037b57600080fd5b506101a661038a366004612d10565b610dbe565b34801561039b57600080fd5b506102016103aa366004612da8565b60ff9081166000908152600860205260409020541690565b3480156103ce57600080fd5b506101a66103dd366004612cb2565b610f56565b3480156103ee57600080fd5b506003546001600160a01b0316610230565b34801561040c57600080fd5b506101a661041b366004612cb2565b610fb0565b34801561042c57600080fd5b506001546001600160a01b0316610230565b34801561044a57600080fd5b506101a6610459366004612cb2565b611012565b34801561046a57600080fd5b506101a6610479366004612cb2565b61106c565b34801561048a57600080fd5b506101a6610499366004612dc3565b6110dd565b6104a6611299565b6104ae6112f2565b60006104bd6040830183612e38565b9050116104e55760405162461bcd60e51b81526004016104dc90612e86565b60405180910390fd5b60008260a00135116105095760405162461bcd60e51b81526004016104dc90612eca565b6105196040820160208301612cb2565b6001600160a01b03166105326040840160208501612cb2565b6001600160a01b0316146105585760405162461bcd60e51b81526004016104dc90612f16565b600080600061056685611338565b600654604051939650919450925060009182916001600160a01b031690869063ccbe400790610599908a90602401612f81565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516105d29190613035565b60006040518083038185875af1925050503d806000811461060f576040519150601f19603f3d011682016040523d82523d6000602084013e610614565b606091505b5091509150816106655761064c816040518060400160405280600c81526020016b2a3930b739b4ba29bbb0b81d60a11b815250611562565b60405162461bcd60e51b81526004016104dc9190613051565b50610680905061067b6040870160208801612cb2565b6117d9565b61075057806106956040870160208801612cb2565b6006546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156106de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107029190613084565b10156107505760405162461bcd60e51b815260206004820152601a60248201527f5472616e736974537761703a20696e76616c69642063726f737300000000000060448201526064016104dc565b61075e856001846000611812565b50505061076b6001600455565b5050565b6107776118c7565b60005b82518110156108ee5760006107a784838151811061079a5761079a61309d565b60200260200101516117d9565b156107bd5750476107b8838261193c565b61086b565b8382815181106107cf576107cf61309d565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561081f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108439190613084565b905061086984838151811061085a5761085a61309d565b602002602001015184836119f9565b505b826001600160a01b0316336001600160a01b03168584815181106108915761089161309d565b60200260200101516001600160a01b03167f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7846040516108d391815260200190565b60405180910390a450806108e6816130c9565b91505061077a565b505050565b6108fb6118c7565b801561090c57610909611ae3565b50565b610909611b2e565b61091c611b70565b6109266000611bd9565b565b338061093c6001546001600160a01b031690565b6001600160a01b03161461099e5760405162461bcd60e51b8152602060048201526024808201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206e6577206f6044820152633bb732b960e11b60648201526084016104dc565b61090981611bd9565b33806109bb6003546001600160a01b031690565b6001600160a01b031614610a215760405162461bcd60e51b815260206004820152602760248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206e657720656044820152663c32b1baba37b960c91b60648201526084016104dc565b61090981611c33565b610a326118c7565b600380546001600160a01b0383166001600160a01b03199091168117909155610a636002546001600160a01b031690565b6001600160a01b03167fdd01547fc40682edc3cd8d164d53f5a1ae6b46138a83f045658ed760823ddba860405160405180910390a350565b610aa3611299565b610aab6112f2565b6000610aba6040830183612e38565b905011610ad95760405162461bcd60e51b81526004016104dc90612e86565b60008260a0013511610afd5760405162461bcd60e51b81526004016104dc90612eca565b6000610b0f60a0840160808501612cb2565b6001600160a01b031603610b7c5760405162461bcd60e51b815260206004820152602e60248201527f5472616e736974537761703a2072656365697665722073686f756c642062652060448201526d6e6f74206164647265737328302960901b60648201526084016104dc565b60008260c0013511610bee5760405162461bcd60e51b815260206004820152603560248201527f5472616e736974537761703a206d696e52657475726e416d6f756e742073686f6044820152740756c642062652067726561746572207468616e203605c1b60648201526084016104dc565b6000610bfd6020830183612da8565b60ff1603610c5457610c156040820160208301612cb2565b6001600160a01b0316610c2e6040840160208501612cb2565b6001600160a01b031614610c545760405162461bcd60e51b81526004016104dc90612f16565b6000600881610c666020860186612da8565b60ff908116825260208201929092526040016000908120549091161591508080610c908487611c90565b925092509250600080600560019054906101000a90046001600160a01b03166001600160a01b03168563ccbe400789604051602401610ccf9190612f81565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051610d089190613035565b60006040518083038185875af1925050503d8060008114610d45576040519150601f19603f3d011682016040523d82523d6000602084013e610d4a565b606091505b509150915081610d825761064c816040518060400160405280600c81526020016b2a3930b739b4ba29bbb0b81d60a11b815250611562565b5050600080610d92868985612041565b9150915083811115610da2578093505b610dae88878685611812565b50505050505061076b6001600455565b610dc66118c7565b6000815167ffffffffffffffff811115610de257610de2612b7c565b604051908082528060200260200182016040528015610e0b578160200160208202803683370190505b50905060005b8251811015610f185760086000848381518110610e3057610e3061309d565b602002602001015160ff1660ff16815260200190815260200160002060009054906101000a900460ff161560086000858481518110610e7157610e7161309d565b602002602001015160ff1660ff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060086000848381518110610eba57610eba61309d565b602002602001015160ff1660ff16815260200190815260200160002060009054906101000a900460ff16828281518110610ef657610ef661309d565b9115156020928302919091019091015280610f10816130c9565b915050610e11565b507f5e69b8fb6404283a560ee2205dc0f225019578c56e3a6c52137e0aa995235b668282604051610f4a92919061311f565b60405180910390a15050565b610f5e6118c7565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907faf855a7e4074e8930caf657b3505942d4ba0e69b6b6e63553c653d7b1ffcc06190600090a35050565b610fb86118c7565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907fbc071769e275808816d09db519c1888c355f7557cb63095ce21e26a97a5f0e9c90600090a35050565b61101a6118c7565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff2ef974bc2aedf0c322b1a97e8627e85114a789cadf8d172b5efb5d6c1d94f8d90600090a35050565b611074611b70565b600180546001600160a01b0383166001600160a01b031990911681179091556110a56000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6110e56118c7565b60008167ffffffffffffffff81111561110057611100612b7c565b604051908082528060200260200182016040528015611129578160200160208202803683370190505b50905060005b82811015611258576009600085858481811061114d5761114d61309d565b90506020020160208101906111629190612cb2565b6001600160a01b03168152602081019190915260400160009081205460ff1615906009908686858181106111985761119861309d565b90506020020160208101906111ad9190612cb2565b6001600160a01b0316815260208101919091526040016000908120805460ff1916921515929092179091556009908585848181106111ed576111ed61309d565b90506020020160208101906112029190612cb2565b6001600160a01b03168152602081019190915260400160002054825160ff909116908390839081106112365761123661309d565b9115156020928302919091019091015280611250816130c9565b91505061112f565b507f4a28b173d9bc739be3886d172e07fef80392184787fc6b92406ce0f0c05b7e6383838360405161128c9392919061316f565b60405180910390a1505050565b6002600454036112eb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104dc565b6002600455565b60055460ff16156109265760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016104dc565b600754600090819081906001600160a01b03166319fa763a3360a08701356113636020890189612da8565b61137060e08a018a612e38565b6040518663ffffffff1660e01b81526004016113909594939291906131c3565b602060405180830381865afa1580156113ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d19190613084565b91506113e661067b6040860160208701612cb2565b15611453578360a00135341461143e5760405162461bcd60e51b815260206004820152601e60248201527f5472616e736974537761703a20696e76616c6964206d73672e76616c7565000060448201526064016104dc565b61144c60a0850135836124e2565b925061155b565b6114636040850160208601612cb2565b6006546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156114ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d09190613084565b90508160000361150a576115056114ed6040860160208701612cb2565b60065433906001600160a01b031660a0880135612538565b61155b565b61152961151d6040860160208701612cb2565b33308760a00135612538565b61155b61153c6040860160208701612cb2565b6006546001600160a01b031661155660a0880135866124e2565b612668565b9193909250565b6060604483511015801561159b5750826000815181106115845761158461309d565b6020910101516001600160f81b031916600160fb1b145b80156115cc5750826001815181106115b5576115b561309d565b6020910101516001600160f81b03191660c360f81b145b80156115fd5750826002815181106115e6576115e661309d565b6020910101516001600160f81b031916607960f81b145b801561162e5750826003815181106116175761161761309d565b6020910101516001600160f81b031916600560fd1b145b156116b85760448381018051909161164691906131f4565b8451101561168e5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103932bb32b93a103932b0b9b7b760591b60448201526064016104dc565b82816040516020016116a1929190613207565b6040516020818303038152906040529150506117d3565b825160241480156116ee5750826000815181106116d7576116d761309d565b6020910101516001600160f81b031916602760f91b145b801561171f5750826001815181106117085761170861309d565b6020910101516001600160f81b031916600960fb1b145b80156117505750826002815181106117395761173961309d565b6020910101516001600160f81b031916607b60f81b145b801561178157508260038151811061176a5761176a61309d565b6020910101516001600160f81b031916607160f81b145b156117a65760248301518261179582612791565b6040516020016116a1929190613256565b816117b0846127b9565b6040516020016117c192919061328b565b60405160208183030381529060405290505b92915050565b60006001600160a01b03821615806117d357506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b61182260a0850160808601612cb2565b6001600160a01b031661183b6060860160408701612cb2565b6001600160a01b03166118546040870160208801612cb2565b6001600160a01b03167f7055e3d08e2c20429c6b162f3e3bee3f426d59896e66084c3580dc353e54129d33878960a00135878b60c001358a8d61010001358e8060e001906118a29190612e38565b426040516118b99a999897969594939291906132dc565b60405180910390a450505050565b336118da6002546001600160a01b031690565b6001600160a01b0316146109265760405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652065786563756044820152623a37b960e91b60648201526084016104dc565b604080516000808252602082019092526001600160a01b0384169083906040516119669190613035565b60006040518083038185875af1925050503d80600081146119a3576040519150601f19603f3d011682016040523d82523d6000602084013e6119a8565b606091505b50509050806108ee5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016104dc565b6000806000856001600160a01b031663a9059cbb8686604051602401611a349291906001600160a01b03929092168252602082015260400190565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611a6d9190613035565b6000604051808303816000865af19150503d8060008114611aaa576040519150601f19603f3d011682016040523d82523d6000602084013e611aaf565b606091505b5091509150818015611ad9575080511580611ad9575080806020019051810190611ad9919061333e565b9695505050505050565b611aeb6112f2565b6005805460ff191660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020015b60405180910390a1565b611b366129a1565b6005805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602001611b24565b33611b836000546001600160a01b031690565b6001600160a01b0316146109265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104dc565b600180546001600160a01b0319908116909155600080546001600160a01b03848116938216841783556040519116929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600380546001600160a01b0319908116909155600280546001600160a01b0384811693821684179092556040519116919082907f88436636ea40d5bb1bcc55ff9cd54788af71da886f4147a87f199adcca733d4d90600090a35050565b60008060008415611d30576007546001600160a01b03166319fa763a3360a0870135611cbf6020890189612da8565b611ccc60e08a018a612e38565b6040518663ffffffff1660e01b8152600401611cec9594939291906131c3565b602060405180830381865afa158015611d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2d9190613084565b91505b611d4361067b6040860160208701612cb2565b15611db0578360a001353414611d9b5760405162461bcd60e51b815260206004820152601e60248201527f5472616e736974537761703a20696e76616c6964206d73672e76616c7565000060448201526064016104dc565b611da960a0850135836124e2565b9250611e2d565b8415611dff57611dc961151d6040860160208701612cb2565b611dfa611ddc6040860160208701612cb2565b611dec6080870160608801612cb2565b61155660a0880135866124e2565b611e2d565b611e2d611e126040860160208701612cb2565b33611e236080880160608901612cb2565b8760a00135612538565b611e4061067b6060860160408701612cb2565b15611f5d578415611e6c57611e5b60a0850160808601612cb2565b6001600160a01b031631905061203a565b6002611e7b6020860186612da8565b60ff1603611f565760096000611e9961014087016101208801612cb2565b6001600160a01b0316815260208101919091526040016000205460ff16611ed25760405162461bcd60e51b81526004016104dc9061335b565b611ee461014085016101208601612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a08231906024015b602060405180830381865afa158015611f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4f9190613084565b905061203a565b504761203a565b8415611fbd57611f736060850160408601612cb2565b6001600160a01b03166370a08231611f9160a0870160808801612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401611f0e565b611fcd6060850160408601612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120379190613084565b90505b9250925092565b60008061205761067b6060860160408701612cb2565b156122a65784156120b1576120868361207660a0870160808801612cb2565b6001600160a01b031631906124e2565b91508360c001358210156120ac5760405162461bcd60e51b81526004016104dc9061339f565b6124da565b60026120c06020860186612da8565b60ff16036121c05761214f836120de61014087016101208801612cb2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a08231906024015b602060405180830381865afa158015612125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121499190613084565b906124e2565b91506009600061216761014087016101208801612cb2565b6001600160a01b0316815260208101919091526040016000205460ff166121a05760405162461bcd60e51b81526004016104dc9061335b565b6121bb6121b561014086016101208701612cb2565b836129ea565b6121cd565b6121ca47846124e2565b91505b6007546001600160a01b03166319fa763a33846121ed6020890189612da8565b6121fa60e08a018a612e38565b6040518663ffffffff1660e01b815260040161221a9594939291906131c3565b602060405180830381865afa158015612237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225b9190613084565b905061226782826124e2565b91508360c0013582101561228d5760405162461bcd60e51b81526004016104dc9061339f565b6120ac6122a060a0860160808701612cb2565b8361193c565b841561230a57612086836122c06060870160408801612cb2565b6001600160a01b03166370a082316122de60a0890160808a01612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401612108565b61231e836120de6060870160408801612cb2565b6007549092506001600160a01b03166319fa763a33846123416020890189612da8565b61234e60e08a018a612e38565b6040518663ffffffff1660e01b815260040161236e9594939291906131c3565b602060405180830381865afa15801561238b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123af9190613084565b90506123bb82826124e2565b915060006123cf6060860160408701612cb2565b6001600160a01b03166370a082316123ed60a0880160808901612cb2565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124559190613084565b905061248061246a6060870160408801612cb2565b61247a60a0880160808901612cb2565b85612668565b6124b2816124946060880160408901612cb2565b6001600160a01b03166370a082316122de60a08a0160808b01612cb2565b92508460c001358310156124d85760405162461bcd60e51b81526004016104dc9061339f565b505b935093915050565b6000826124ef83826133e6565b91508111156117d35760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b60448201526064016104dc565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161259c9190613035565b6000604051808303816000865af19150503d80600081146125d9576040519150601f19603f3d011682016040523d82523d6000602084013e6125de565b606091505b5091509150818015612608575080511580612608575080806020019051810190612608919061333e565b6126605760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b60648201526084016104dc565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916126c49190613035565b6000604051808303816000865af19150503d8060008114612701576040519150601f19603f3d011682016040523d82523d6000602084013e612706565b606091505b5091509150818015612730575080511580612730575080806020019051810190612730919061333e565b61278a5760405162461bcd60e51b815260206004820152602560248201527f5472616e7366657248656c7065723a205452414e534645525f544f4b454e5f46604482015264105253115160da1b60648201526084016104dc565b5050505050565b60606117d3826040516020016127a991815260200190565b6040516020818303038152906040525b80516060906f181899199a1a9b1b9c1cb0b131b232b360811b906000906127e19060026133f9565b6127ec9060026131f4565b67ffffffffffffffff81111561280457612804612b7c565b6040519080825280601f01601f19166020018201604052801561282e576020820181803683370190505b509050600360fc1b816000815181106128495761284961309d565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106128785761287861309d565b60200101906001600160f81b031916908160001a90535060005b8451811015612999578260048683815181106128b0576128b061309d565b01602001516001600160f81b031916901c60f81c601081106128d4576128d461309d565b1a60f81b826128e48360026133f9565b6128ef9060026131f4565b815181106128ff576128ff61309d565b60200101906001600160f81b031916908160001a905350828582815181106129295761292961309d565b60209101015160f81c600f16601081106129455761294561309d565b1a60f81b826129558360026133f9565b6129609060036131f4565b815181106129705761297061309d565b60200101906001600160f81b031916908160001a90535080612991816130c9565b915050612892565b509392505050565b60055460ff166109265760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016104dc565b600080836001600160a01b03166000632e1a7d4d85604051602401612a1191815260200190565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612a4a9190613035565b60006040518083038185875af1925050503d8060008114612a87576040519150601f19603f3d011682016040523d82523d6000602084013e612a8c565b606091505b5091509150818015612ab6575080511580612ab6575080806020019051810190612ab6919061333e565b612b025760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a2057495448445241575f4641494c45440060448201526064016104dc565b50505050565b60008060408385031215612b1b57600080fd5b823567ffffffffffffffff80821115612b3357600080fd5b908401906101408287031215612b4857600080fd5b90925060208401359080821115612b5e57600080fd5b50830160608186031215612b7157600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612bbb57612bbb612b7c565b604052919050565b600067ffffffffffffffff821115612bdd57612bdd612b7c565b5060051b60200190565b80356001600160a01b0381168114612bfe57600080fd5b919050565b60008060408385031215612c1657600080fd5b823567ffffffffffffffff811115612c2d57600080fd5b8301601f81018513612c3e57600080fd5b80356020612c53612c4e83612bc3565b612b92565b82815260059290921b83018101918181019088841115612c7257600080fd5b938201935b83851015612c9757612c8885612be7565b82529382019390820190612c77565b9550612ca69050868201612be7565b93505050509250929050565b600060208284031215612cc457600080fd5b612ccd82612be7565b9392505050565b801515811461090957600080fd5b600060208284031215612cf457600080fd5b8135612ccd81612cd4565b803560ff81168114612bfe57600080fd5b60006020808385031215612d2357600080fd5b823567ffffffffffffffff811115612d3a57600080fd5b8301601f81018513612d4b57600080fd5b8035612d59612c4e82612bc3565b81815260059190911b82018301908381019087831115612d7857600080fd5b928401925b82841015612d9d57612d8e84612cff565b82529284019290840190612d7d565b979650505050505050565b600060208284031215612dba57600080fd5b612ccd82612cff565b60008060208385031215612dd657600080fd5b823567ffffffffffffffff80821115612dee57600080fd5b818501915085601f830112612e0257600080fd5b813581811115612e1157600080fd5b8660208260051b8501011115612e2657600080fd5b60209290920196919550909350505050565b6000808335601e19843603018112612e4f57600080fd5b83018035915067ffffffffffffffff821115612e6a57600080fd5b602001915036819003821315612e7f57600080fd5b9250929050565b60208082526024908201527f5472616e736974537761703a20646174612073686f756c64206265206e6f74206040820152637a65726f60e01b606082015260800190565b6020808252602c908201527f5472616e736974537761703a20616d6f756e742073686f756c6420626520677260408201526b06561746572207468616e20360a41b606082015260800190565b60208082526022908201527f5472616e736974537761703a20696e76616c69642063616c6c62797465734465604082015261736360f01b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260ff612f9083612cff565b16602082015260018060a01b03612fa960208401612be7565b16604082015260006040830135601e19843603018112612fc857600080fd5b830160208101903567ffffffffffffffff811115612fe557600080fd5b803603821315612ff457600080fd5b606080850152613008608085018284612f58565b95945050505050565b60005b8381101561302c578181015183820152602001613014565b50506000910152565b60008251613047818460208701613011565b9190910192915050565b6020815260008251806020840152613070816040850160208701613011565b601f01601f19169190910160400192915050565b60006020828403121561309657600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016130db576130db6130b3565b5060010190565b600081518084526020808501945080840160005b838110156131145781511515875295820195908201906001016130f6565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b8281101561315b57815160ff168452928401929084019060010161313c565b50505083810382850152611ad981866130e2565b6040808252810183905260008460608301825b868110156131b0576001600160a01b0361319b84612be7565b16825260209283019290910190600101613182565b508381036020850152612d9d81866130e2565b60018060a01b038616815284602082015260ff84166040820152608060608201526000612d9d608083018486612f58565b808201808211156117d3576117d36130b3565b60008351613219818460208801613011565b6508ae4e4dee4560d31b908301908152835161323c816006840160208801613011565b602960f81b60069290910191820152600701949350505050565b60008351613268818460208801613011565b650a0c2dcd2c6560d31b908301908152835161323c816006840160208801613011565b6000835161329d818460208801613011565b670aadcd6dcdeeedc560c31b90830190815283516132c2816008840160208801613011565b602960f81b60089290910191820152600901949350505050565b600061012060018060a01b038d1683528b151560208401528a60408401528960608401528860808401528760a08401528660c08401528060e08401526133258184018688612f58565b915050826101008301529b9a5050505050505050505050565b60006020828403121561335057600080fd5b8151612ccd81612cd4565b60208082526024908201527f5472616e736974537761703a20696e76616c69642077726170706564206164646040820152637265737360e01b606082015260800190565b60208082526027908201527f5472616e736974537761703a20696e73756666696369656e742072657475726e60408201526608185b5bdd5b9d60ca1b606082015260800190565b818103818111156117d3576117d36130b3565b80820281158282048414176117d3576117d36130b356fea2646970667358221220e17c9f74d89f6274faaf48b4224f03f82f32783ebfdadf5d8ffbf445abc1ded064736f6c63430008110033000000000000000000000000f7a2f863299c17dfa11cd8a14e7c7dca92f315b90000000000000000000000008755773dc777b9f9b2e2c86402a03f099f8236910000000000000000000000001f6e41c47349634fe261403a18f8515546f58826000000000000000000000000280333c41a9302448ebc070ed0300ad2ed4b8244

Check out more smart contracts

Build blockchain magic with Alchemy

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.