This contract's source code is verified! Compiler
0.8.18+commit.87f61d96
File 1 of 15: AggregateRouter.sol
pragma solidity ^0.8.0;
import "./BaseCore.sol" ;
contract AggregateRouter is BaseCore {
using SafeMath for uint256 ;
constructor ( ) {
}
function aggregateAndGasUsed (TransitSwapDescription calldata desc, CallbytesDescription calldata callbytesDesc ) external payable returns (uint256 returnAmount, uint256 gasUsed ) {
uint256 gasLeftBefore = gasleft ();
returnAmount = _executeAggregate(desc, callbytesDesc);
gasUsed = gasLeftBefore - gasleft ();
}
function aggregate (TransitSwapDescription calldata desc, CallbytesDescription calldata callbytesDesc ) external payable returns (uint256 returnAmount ) {
returnAmount = _executeAggregate(desc, callbytesDesc);
}
function _executeAggregate (TransitSwapDescription calldata desc, CallbytesDescription calldata callbytesDesc ) internal nonReentrant whenNotPaused returns (uint256 returnAmount ) {
require (callbytesDesc.calldatas.length > 0 , "data should be not zero" );
require (desc.amount > 0 , "amount should be greater than 0" );
require (desc.dstReceiver ! = address (0 ), "receiver should be not address(0)" );
require (desc.minReturnAmount > 0 , "minReturnAmount should be greater than 0" );
require (_wrapped_allowed[desc.wrappedToken], "invalid wrapped address" );
uint256 actualAmountIn = calculateTradeFee(true , desc.amount, desc.fee, desc.signature);
uint256 swapAmount;
uint256 toBeforeBalance;
address bridgeAddress = _aggregate_bridge;
if (TransferHelper.isETH(desc.srcToken)) {
require (msg .value = = desc.amount, "invalid msg.value" );
swapAmount = actualAmountIn;
} else {
TransferHelper.safeTransferFrom(desc.srcToken, msg .sender , address (this ), desc.amount);
TransferHelper.safeTransfer(desc.srcToken, bridgeAddress, actualAmountIn);
}
if (TransferHelper.isETH(desc.dstToken)) {
toBeforeBalance = desc.dstReceiver.balance ;
} else {
toBeforeBalance = IERC20(desc.dstToken).balanceOf(desc.dstReceiver);
}
{
(bool success, bytes memory result) = bridgeAddress.call {value : swapAmount}(abi .encodeWithSelector (0x3f3204d2 , callbytesDesc));
if (! success) {
revert (RevertReasonParser.parse(result, "TransitSwap:" ));
}
}
if (TransferHelper.isETH(desc.dstToken)) {
returnAmount = desc.dstReceiver.balance .sub(toBeforeBalance);
} else {
returnAmount = IERC20(desc.dstToken).balanceOf(desc.dstReceiver).sub(toBeforeBalance);
}
require (returnAmount > = desc.minReturnAmount, "Too little received" );
_emitTransit(desc.srcToken, desc.dstToken, desc.dstReceiver, desc.amount, returnAmount, 0 , desc.channel);
}
} File 2 of 15: BaseCore.sol
pragma solidity ^0.8.0;
import "./libs/Pausable.sol" ;
import "./libs/ReentrancyGuard.sol" ;
import "./libs/TransferHelper.sol" ;
import "./libs/RevertReasonParser.sol" ;
import "./libs/SafeMath.sol" ;
import "./libs/Ownable.sol" ;
import "./interfaces/IERC20.sol" ;
import "./interfaces/IUniswapV2.sol" ;
import "./interfaces/IUniswapV3Pool.sol" ;
contract BaseCore is Ownable , Pausable , ReentrancyGuard {
using SafeMath for uint256 ;
struct ExactInputV2SwapParams {
address dstReceiver;
address wrappedToken;
uint256 router;
uint256 amount;
uint256 minReturnAmount;
uint256 fee;
address [] path;
address [] pool;
bytes signature;
string channel;
}
struct ExactInputV3SwapParams {
address srcToken;
address dstToken;
address dstReceiver;
address wrappedToken;
uint256 amount;
uint256 minReturnAmount;
uint256 fee;
uint256 deadline;
uint256 [] pools;
bytes signature;
string channel;
}
struct TransitSwapDescription {
address srcToken;
address dstToken;
address dstReceiver;
address wrappedToken;
uint256 amount;
uint256 minReturnAmount;
uint256 fee;
string channel;
bytes signature;
}
struct CrossDescription {
address srcToken;
address dstToken;
address caller;
address dstReceiver;
address wrappedToken;
uint256 amount;
uint256 fee;
uint256 toChain;
string channel;
bytes calls;
bytes signature;
}
struct CallbytesDescription {
address srcToken;
bytes calldatas;
}
struct UniswapV3Pool {
address factory;
bytes initCodeHash;
}
uint256 internal _aggregate_fee;
uint256 internal _cross_fee;
address internal _aggregate_bridge;
address internal _fee_signer;
bytes32 public DOMAIN_SEPARATOR;
mapping (address = > bool ) internal _cross_caller_allowed;
mapping (address = > bool ) internal _wrapped_allowed;
mapping (uint = > UniswapV3Pool) internal _uniswapV3_factory_allowed;
bytes32 public constant CHECKFEE_TYPEHASH = keccak256 ("CheckFee(address payer,uint256 amount,uint256 fee)" );
event Receipt (address from , uint256 amount ) ;
event Withdraw (address indexed token, address indexed executor, address indexed recipient, uint amount ) ;
event ChangeWrappedAllowed (address [] wrappedTokens, bool [] newAllowed ) ;
event ChangeV3FactoryAllowed (uint256 [] poolIndex, address [] factories, bytes [] initCodeHash ) ;
event ChangeCrossCallerAllowed (address [] callers ) ;
event ChangeFeeRate (bool isAggregate, uint256 newRate ) ;
event ChangeSigner (address preSigner, address newSigner ) ;
event ChangeAggregateBridge (address newBridge ) ;
event TransitSwapped (address indexed srcToken, address indexed dstToken, address indexed dstReceiver, uint256 amount, uint256 returnAmount, uint256 toChainID, string channel ) ;
constructor ( ) Ownable (msg .sender ) {
DOMAIN_SEPARATOR = keccak256 (
abi .encode (
keccak256 ("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ),
keccak256 (bytes ("TransitSwapV5" )),
keccak256 (bytes ("5" )),
block .chainid ,
address (this )
)
);
}
receive ( ) external payable {
emit Receipt(msg .sender , msg .value );
}
function calculateTradeFee (bool isAggregate, uint256 tradeAmount, uint256 fee, bytes calldata signature ) internal view returns (uint256 ) {
uint256 thisFee;
if (isAggregate) {
thisFee = tradeAmount.mul(_aggregate_fee).div(10000 );
} else {
thisFee = tradeAmount.mul(_cross_fee).div(10000 );
}
if (fee < thisFee) {
require (verifySignature(tradeAmount, fee, signature), "Invalid signature fee" );
}
return tradeAmount.sub(fee);
}
function _emitTransit (address srcToken, address dstToken, address dstReceiver, uint256 amount, uint256 returnAmount, uint256 toChainID, string memory channel ) internal {
emit TransitSwapped (
srcToken,
dstToken,
dstReceiver,
amount,
returnAmount,
toChainID,
channel
);
}
function changeFee (bool [] memory isAggregate, uint256 [] memory newRate ) external onlyExecutor {
for (uint i; i < isAggregate.length ; i+ + ) {
require (newRate[i] > = 0 & & newRate[i] < = 1000 , "fee rate is:0-1000" );
if (isAggregate[i]) {
_aggregate_fee = newRate[i];
} else {
_cross_fee = newRate[i];
}
emit ChangeFeeRate(isAggregate[i], newRate[i]);
}
}
function changeTransitProxy (address aggregator, address signer ) external onlyExecutor {
if (aggregator ! = address (0 )) {
_aggregate_bridge = aggregator;
emit ChangeAggregateBridge(aggregator);
}
if (signer ! = address (0 )) {
address preSigner = _fee_signer;
_fee_signer = signer;
emit ChangeSigner(preSigner, signer);
}
}
function changeAllowed (address [] calldata crossCallers, address [] calldata wrappedTokens ) public onlyExecutor {
if (crossCallers.length ! = 0 ){
for (uint i; i < crossCallers.length ; i+ + ) {
_cross_caller_allowed[crossCallers[i]] = ! _cross_caller_allowed[crossCallers[i]];
}
emit ChangeCrossCallerAllowed(crossCallers);
}
if (wrappedTokens.length ! = 0 ) {
bool [] memory newAllowed = new bool [](wrappedTokens.length );
for (uint index; index < wrappedTokens.length ; index+ + ) {
_wrapped_allowed[wrappedTokens[index]] = ! _wrapped_allowed[wrappedTokens[index]];
newAllowed[index] = _wrapped_allowed[wrappedTokens[index]];
}
emit ChangeWrappedAllowed(wrappedTokens, newAllowed);
}
}
function changeUniswapV3FactoryAllowed (uint [] calldata poolIndex, address [] calldata factories, bytes [] calldata initCodeHash ) public onlyExecutor {
require (poolIndex.length = = initCodeHash.length , "invalid data" );
require (factories.length = = initCodeHash.length , "invalid data" );
uint len = factories.length ;
for (uint i; i < len; i+ + ) {
_uniswapV3_factory_allowed[poolIndex[i]] = UniswapV3Pool(factories[i],initCodeHash[i]);
}
emit ChangeV3FactoryAllowed(poolIndex, factories, initCodeHash);
}
function changePause (bool paused ) external onlyExecutor {
if (paused) {
_pause();
} else {
_unpause();
}
}
function transitProxyAddress ( ) external view returns (address bridgeProxy, address feeSigner ) {
bridgeProxy = _aggregate_bridge;
feeSigner = _fee_signer;
}
function transitFee ( ) external view returns (uint256 , uint256 ) {
return (_aggregate_fee, _cross_fee);
}
function transitAllowedQuery (address crossCaller, address wrappedToken, uint256 poolIndex ) external view returns (bool isCrossCallerAllowed, bool isWrappedAllowed, UniswapV3Pool memory pool ) {
isCrossCallerAllowed = _cross_caller_allowed[crossCaller];
isWrappedAllowed = _wrapped_allowed[wrappedToken];
pool = _uniswapV3_factory_allowed[poolIndex];
}
function verifySignature (uint256 amount, uint256 fee, bytes calldata signature ) internal view returns (bool ) {
bytes32 digest = keccak256 (
abi .encodePacked (
"\x19\x01" ,
DOMAIN_SEPARATOR,
keccak256 (abi .encode (CHECKFEE_TYPEHASH, msg .sender , amount, fee))
)
);
(uint8 v, bytes32 r, bytes32 s) = splitSignature(signature);
address recovered = ecrecover (digest, v, r, s);
return recovered = = _fee_signer;
}
function splitSignature (bytes memory _signature ) internal pure returns (uint8 v, bytes32 r, bytes32 s ) {
require (bytes (_signature).length = = 65 , "Invalid signature length" );
assembly {
r := mload (add (_signature, 0x20 ))
s := mload (add (_signature, 0x40 ))
v := byte (0 , mload (add (_signature, 0x60 )))
}
return (v, r, s);
}
} File 3 of 15: CrossRouter.sol
pragma solidity ^0.8.0;
import "./BaseCore.sol" ;
contract CrossRouter is BaseCore {
using SafeMath for uint256 ;
constructor ( ) {}
function cross (CrossDescription calldata desc ) external payable nonReentrant whenNotPaused {
require (desc.calls.length > 0 , "data should be not zero" );
require (desc.amount > 0 , "amount should be greater than 0" );
require (_cross_caller_allowed[desc.caller], "invalid caller" );
uint256 swapAmount;
uint256 actualAmountIn = calculateTradeFee(false , desc.amount, desc.fee, desc.signature);
if (TransferHelper.isETH(desc.srcToken)) {
require (msg .value = = desc.amount, "invalid msg.value" );
swapAmount = actualAmountIn;
if (desc.wrappedToken ! = address (0 )) {
require (_wrapped_allowed[desc.wrappedToken], "Invalid wrapped address" );
TransferHelper.safeDeposit(desc.wrappedToken, swapAmount);
TransferHelper.safeApprove(desc.wrappedToken, desc.caller, swapAmount);
swapAmount = 0 ;
}
} else {
TransferHelper.safeTransferFrom(desc.srcToken, msg .sender , address (this ), desc.amount);
TransferHelper.safeApprove(desc.srcToken, desc.caller, actualAmountIn);
}
{
(bool success, bytes memory result) = desc.caller.call {value :swapAmount}(desc.calls);
if (! success) {
revert (RevertReasonParser.parse(result, "TransitCrossV5:" ));
}
}
_emitTransit(desc.srcToken, desc.dstToken, desc.dstReceiver, desc.amount, 0 , desc.toChain, desc.channel);
}
} File 4 of 15: IERC20.sol
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 ) ;
} File 5 of 15: IUniswapV2.sol
pragma solidity >=0.6.9;
interface IUniswapV2 {
function getAmountOut (uint amountIn, uint reserveIn, uint reserveOut ) external pure returns (uint amountOut ) ;
function getAmountsOut (uint amountIn, address [] memory path ) external view returns (uint [] memory amounts ) ;
function getReserves ( ) external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ) ;
function swap (uint amount0Out, uint amount1Out, address to, bytes calldata data ) external ;
} File 6 of 15: IUniswapV3Pool.sol
pragma solidity >=0.5.0;
interface IUniswapV3Pool {
function token0 ( ) external view returns (address ) ;
function token1 ( ) external view returns (address ) ;
function fee ( ) external view returns (uint24 ) ;
function swap (
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1 ) ;
} File 7 of 15: Ownable.sol
pragma solidity ^0.8.0;
abstract contract Ownable {
address private _executor;
address private _pendingExecutor;
bool internal _initialized;
event ExecutorshipTransferStarted (address indexed previousExecutor, address indexed newExecutor ) ;
event ExecutorshipTransferred (address indexed previousExecutor, address indexed newExecutor ) ;
constructor (address newExecutor ) {
require (! _initialized, "Ownable: initialized" );
_transferExecutorship(newExecutor);
_initialized = true ;
}
modifier onlyExecutor ( ) {
_checkExecutor();
_ ;
}
function executor ( ) public view virtual returns (address ) {
return _executor;
}
function pendingExecutor ( ) public view virtual returns (address ) {
return _pendingExecutor;
}
function _checkExecutor ( ) internal view virtual {
require (executor() = = msg .sender , "Ownable: caller is not the executor" );
}
function transferExecutorship (address newExecutor ) public virtual onlyExecutor {
_pendingExecutor = newExecutor;
emit ExecutorshipTransferStarted(executor(), newExecutor);
}
function _transferExecutorship (address newExecutor ) internal virtual {
delete _pendingExecutor;
address oldExecutor = _executor;
_executor = newExecutor;
emit ExecutorshipTransferred(oldExecutor, newExecutor);
}
function acceptExecutorship ( ) external {
address sender = msg .sender ;
require (pendingExecutor() = = sender, "Ownable: caller is not the new executor" );
_transferExecutorship(sender);
}
} File 8 of 15: Pausable.sol
pragma solidity ^0.8.0;
abstract contract Pausable {
event Paused (address account ) ;
event Unpaused (address account ) ;
bool private _paused;
constructor ( ) {
_paused = false ;
}
modifier whenNotPaused ( ) {
_requireNotPaused();
_ ;
}
modifier whenPaused ( ) {
_requirePaused();
_ ;
}
function paused ( ) public view virtual returns (bool ) {
return _paused;
}
function _requireNotPaused ( ) internal view virtual {
require (! paused(), "Pausable: paused" );
}
function _requirePaused ( ) internal view virtual {
require (paused(), "Pausable: not paused" );
}
function _pause ( ) internal virtual whenNotPaused {
_paused = true ;
emit Paused(msg .sender );
}
function _unpause ( ) internal virtual whenPaused {
_paused = false ;
emit Unpaused(msg .sender );
}
} File 9 of 15: ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1 ;
uint256 private constant _ENTERED = 2 ;
uint256 private _status;
constructor ( ) {
_status = _NOT_ENTERED;
}
modifier nonReentrant ( ) {
require (_status ! = _ENTERED, "ReentrancyGuard: reentrant call" );
assembly {
sstore (_status.slot , _ENTERED)
}
_ ;
assembly {
sstore (_status.slot , _NOT_ENTERED)
}
}
function _nonReentrantBefore ( ) private {
require (_status ! = _ENTERED, "ReentrancyGuard: reentrant call" );
_status = _ENTERED;
}
function _nonReentrantAfter ( ) private {
_status = _NOT_ENTERED;
}
} File 10 of 15: RevertReasonParser.sol
pragma solidity >=0.6.0;
library RevertReasonParser {
function parse (bytes memory data, string memory prefix ) internal pure returns (string memory ) {
if (data.length > = 68 & & data[0 ] = = "\x08" & & data[1 ] = = "\xc3" & & data[2 ] = = "\x79" & & data[3 ] = = "\xa0" ) {
string memory reason;
assembly {
reason := add (data, 68 )
}
require (data.length > = 68 + bytes (reason).length , "Invalid revert reason" );
return string (abi .encodePacked (prefix, "Error(" , reason, ")" ));
}
else if (data.length = = 36 & & data[0 ] = = "\x4e" & & data[1 ] = = "\x48" & & data[2 ] = = "\x7b" & & data[3 ] = = "\x71" ) {
uint256 code;
assembly {
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);
}
} File 11 of 15: SafeMath.sol
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;
}
function toInt256 (uint256 value ) internal pure returns (int256 ) {
require (value < = uint256 (type (int256 ).max ), "SafeCast: value doesn't fit in an int256" );
return int256 (value);
}
function toUint256 (int256 value ) internal pure returns (uint256 ) {
require (value > = 0 , "SafeCast: value must be positive" );
return uint256 (value);
}
} File 12 of 15: TransferHelper.sol
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 {
(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 {
(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 ) {
(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 {
(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 {
(bool success,) = to.call {value :value}(new bytes (0 ));
require (success, 'TransferHelper: TRANSFER_FAILED' );
}
function safeDeposit (address wrapped, uint value ) internal {
(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 {
(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' );
}
} File 13 of 15: TransitSwapRouterV5.sol
pragma solidity ^0.8.0;
import "./UniswapV2Router.sol" ;
import "./UniswapV3Router.sol" ;
import "./AggregateRouter.sol" ;
import "./CrossRouter.sol" ;
contract TransitSwapRouterV5 is UniswapV2Router , UniswapV3Router , AggregateRouter , CrossRouter {
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);
}
}
} File 14 of 15: UniswapV2Router.sol
pragma solidity ^0.8.0;
import "./BaseCore.sol" ;
contract UniswapV2Router is BaseCore {
using SafeMath for uint256 ;
constructor ( ) {
}
function _beforeSwap (ExactInputV2SwapParams calldata exactInput, bool supportingFeeOn ) internal returns (bool isToETH, uint256 actualAmountIn, address [] memory paths, uint256 thisAddressBeforeBalance, uint256 toBeforeBalance ) {
require (exactInput.path.length = = exactInput.pool.length + 1 , "Invalid path" );
require (_wrapped_allowed[exactInput.wrappedToken], "Invalid wrapped address" );
actualAmountIn = calculateTradeFee(true , exactInput.amount, exactInput.fee, exactInput.signature);
address [] memory path = exactInput.path;
address dstToken = path[exactInput.path.length - 1 ];
if (TransferHelper.isETH(exactInput.path[0 ])) {
require (msg .value = = exactInput.amount, "Invalid msg.value" );
path[0 ] = exactInput.wrappedToken;
TransferHelper.safeDeposit(exactInput.wrappedToken, actualAmountIn);
} else {
if (supportingFeeOn) {
actualAmountIn = IERC20(path[0 ]).balanceOf(address (this ));
TransferHelper.safeTransferFrom(path[0 ], msg .sender , address (this ), exactInput.amount);
actualAmountIn = IERC20(path[0 ]).balanceOf(address (this )).sub(actualAmountIn).sub(exactInput.fee);
} else {
TransferHelper.safeTransferFrom(path[0 ], msg .sender , address (this ), exactInput.amount);
}
}
if (TransferHelper.isETH(dstToken)) {
path[path.length - 1 ] = exactInput.wrappedToken;
isToETH = true ;
thisAddressBeforeBalance = IERC20(exactInput.wrappedToken).balanceOf(address (this ));
} else {
if (supportingFeeOn) {
toBeforeBalance = IERC20(dstToken).balanceOf(exactInput.dstReceiver);
}
}
paths = path;
}
function exactInputV2SwapAndGasUsed (ExactInputV2SwapParams calldata exactInput, uint256 deadline ) external payable returns (uint256 returnAmount, uint256 gasUsed ) {
uint256 gasLeftBefore = gasleft ();
returnAmount = _executeV2Swap(exactInput, deadline);
gasUsed = gasLeftBefore - gasleft ();
}
function exactInputV2Swap (ExactInputV2SwapParams calldata exactInput, uint256 deadline ) external payable returns (uint256 returnAmount ) {
returnAmount = _executeV2Swap(exactInput, deadline);
}
function _executeV2Swap (ExactInputV2SwapParams calldata exactInput, uint256 deadline ) internal nonReentrant whenNotPaused returns (uint256 returnAmount ) {
require (deadline > = block .timestamp , "Expired" );
bool supportingFeeOn = exactInput.router > > 248 & 0xf = = 1 ;
{
(bool isToETH, uint256 actualAmountIn, address [] memory paths, uint256 thisAddressBeforeBalance, uint256 toBeforeBalance) = _beforeSwap(exactInput, supportingFeeOn);
TransferHelper.safeTransfer(paths[0 ], exactInput.pool[0 ], actualAmountIn);
if (supportingFeeOn) {
if (isToETH) {
_swapSupportingFeeOnTransferTokens(address (uint160 (exactInput.router)), paths, exactInput.pool, address (this ));
returnAmount = IERC20(exactInput.wrappedToken).balanceOf(address (this )).sub(thisAddressBeforeBalance);
} else {
_swapSupportingFeeOnTransferTokens(address (uint160 (exactInput.router)), paths, exactInput.pool, exactInput.dstReceiver);
returnAmount = IERC20(paths[paths.length - 1 ]).balanceOf(exactInput.dstReceiver).sub(toBeforeBalance);
}
} else {
uint [] memory amounts = IUniswapV2(address (uint160 (exactInput.router))).getAmountsOut(actualAmountIn, paths);
if (isToETH) {
_swap(amounts, paths, exactInput.pool, address (this ));
returnAmount = IERC20(exactInput.wrappedToken).balanceOf(address (this )).sub(thisAddressBeforeBalance);
} else {
_swap(amounts, paths, exactInput.pool, exactInput.dstReceiver);
returnAmount = amounts[amounts.length - 1 ];
}
}
require (returnAmount > = exactInput.minReturnAmount, "Too little received" );
if (isToETH) {
TransferHelper.safeWithdraw(exactInput.wrappedToken, returnAmount);
TransferHelper.safeTransferETH(exactInput.dstReceiver, returnAmount);
}
}
string memory channel = exactInput.channel;
_emitTransit(exactInput.path[0 ], exactInput.path[exactInput.path.length - 1 ], exactInput.dstReceiver, exactInput.amount, returnAmount, 0 , channel);
}
function _swap (uint [] memory amounts, address [] memory path, address [] memory pool, address _to ) internal {
for (uint i; i < path.length - 1 ; i+ + ) {
(address input, address output) = (path[i], path[i + 1 ]);
(address token0,) = input < output ? (input, output) : (output, input);
uint amountOut = amounts[i + 1 ];
(uint amount0Out, uint amount1Out) = input = = token0 ? (uint (0 ), amountOut) : (amountOut, uint (0 ));
address to = i < path.length - 2 ? pool[i + 1 ] : _to;
IUniswapV2(pool[i]).swap(
amount0Out, amount1Out, to, new bytes (0 )
);
}
}
function _swapSupportingFeeOnTransferTokens (address router, address [] memory path, address [] memory pool, address _to ) internal virtual {
for (uint i; i < path.length - 1 ; i+ + ) {
(address input, address output) = (path[i], path[i + 1 ]);
(address token0,) = input < output ? (input, output) : (output, input);
IUniswapV2 pair = IUniswapV2(pool[i]);
uint amountInput;
uint amountOutput;
{
(uint reserve0, uint reserve1,) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input = = token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address (pair)).sub(reserveInput);
amountOutput = IUniswapV2(router).getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input = = token0 ? (uint (0 ), amountOutput) : (amountOutput, uint (0 ));
address to = i < path.length - 2 ? pool[i + 1 ] : _to;
pair.swap(amount0Out, amount1Out, to, new bytes (0 ));
}
}
} File 15 of 15: UniswapV3Router.sol
pragma solidity ^0.8.0;
import "./BaseCore.sol" ;
contract UniswapV3Router is BaseCore {
using SafeMath for uint256 ;
uint256 private constant _ZERO_FOR_ONE_MASK = 1 < < 255 ;
uint160 private constant MIN_SQRT_RATIO = 4295128739 ;
uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 ;
constructor ( ) {}
fallback ( ) external {
(int256 amount0Delta, int256 amount1Delta, bytes memory _data) = abi .decode (msg .data [4 :], (int256 ,int256 ,bytes ));
_executeCallback(amount0Delta, amount1Delta, _data);
}
function pancakeV3SwapCallback (
int256 amount0Delta,
int256 amount1Delta,
bytes calldata _data
) external {
_executeCallback(amount0Delta, amount1Delta, _data);
}
function uniswapV3SwapCallback (
int256 amount0Delta,
int256 amount1Delta,
bytes calldata _data
) external {
_executeCallback(amount0Delta, amount1Delta, _data);
}
function _executeCallback (
int256 amount0Delta,
int256 amount1Delta,
bytes memory _data
) internal {
require (amount0Delta > 0 | | amount1Delta > 0 , "M0 or M1" );
(uint256 pool, bytes memory tokenInAndPoolSalt) = abi .decode (_data, (uint256 , bytes ));
(address tokenIn, bytes32 poolSalt) = abi .decode (tokenInAndPoolSalt, (address , bytes32 ));
_verifyCallback(pool, poolSalt, msg .sender );
uint256 amountToPay = uint256 (amount1Delta);
if (amount0Delta > 0 ) {
amountToPay = uint256 (amount0Delta);
}
TransferHelper.safeTransfer(tokenIn, msg .sender , amountToPay);
}
function exactInputV3SwapAndGasUsed (ExactInputV3SwapParams calldata params ) external payable returns (uint256 returnAmount, uint256 gasUsed ) {
uint256 gasLeftBefore = gasleft ();
returnAmount = _executeV3Swap(params);
gasUsed = gasLeftBefore - gasleft ();
}
function exactInputV3Swap (ExactInputV3SwapParams calldata params ) external payable returns (uint256 returnAmount ) {
returnAmount = _executeV3Swap(params);
}
function _executeV3Swap (ExactInputV3SwapParams calldata params ) internal nonReentrant whenNotPaused returns (uint256 returnAmount ) {
require (params.pools.length > 0 , "Empty pools" );
require (params.deadline > = block .timestamp , "Expired" );
require (_wrapped_allowed[params.wrappedToken], "Invalid wrapped address" );
address tokenIn = params.srcToken;
address tokenOut = params.dstToken;
uint256 actualAmountIn = calculateTradeFee(true , params.amount, params.fee, params.signature);
uint256 toBeforeBalance;
bool isToETH;
if (TransferHelper.isETH(params.srcToken)) {
tokenIn = params.wrappedToken;
require (msg .value = = params.amount, "Invalid msg.value" );
TransferHelper.safeDeposit(params.wrappedToken, actualAmountIn);
} else {
TransferHelper.safeTransferFrom(params.srcToken, msg .sender , address (this ), params.amount);
}
if (TransferHelper.isETH(params.dstToken)) {
tokenOut = params.wrappedToken;
toBeforeBalance = IERC20(params.wrappedToken).balanceOf(address (this ));
isToETH = true ;
} else {
toBeforeBalance = IERC20(params.dstToken).balanceOf(params.dstReceiver);
}
{
uint256 len = params.pools.length ;
address recipient = address (this );
bytes memory tokenInAndPoolSalt;
if (len > 1 ) {
address thisTokenIn = tokenIn;
address thisTokenOut = address (0 );
for (uint256 i; i < len; i+ + ) {
uint256 thisPool = params.pools[i];
(thisTokenIn, tokenInAndPoolSalt) = _verifyPool(thisTokenIn, thisTokenOut, thisPool);
if (i = = len - 1 & & ! isToETH) {
recipient = params.dstReceiver;
thisTokenOut = tokenOut;
}
actualAmountIn = _swap(recipient, thisPool, tokenInAndPoolSalt, actualAmountIn);
}
returnAmount = actualAmountIn;
} else {
(, tokenInAndPoolSalt) = _verifyPool(tokenIn, tokenOut, params.pools[0 ]);
if (! isToETH) {
recipient = params.dstReceiver;
}
returnAmount = _swap(recipient, params.pools[0 ], tokenInAndPoolSalt, actualAmountIn);
}
}
if (isToETH) {
returnAmount = IERC20(params.wrappedToken).balanceOf(address (this )).sub(toBeforeBalance);
require (returnAmount > = params.minReturnAmount, "Too little received" );
TransferHelper.safeWithdraw(params.wrappedToken, returnAmount);
TransferHelper.safeTransferETH(params.dstReceiver, returnAmount);
} else {
returnAmount = IERC20(params.dstToken).balanceOf(params.dstReceiver).sub(toBeforeBalance);
require (returnAmount > = params.minReturnAmount, "Too little received" );
}
_emitTransit(params.srcToken, params.dstToken, params.dstReceiver, params.amount, returnAmount, 0 , params.channel);
}
function _swap (address recipient, uint256 pool, bytes memory tokenInAndPoolSalt, uint256 amount ) internal returns (uint256 amountOut ) {
bool zeroForOne = pool & _ZERO_FOR_ONE_MASK = = 0 ;
if (zeroForOne) {
(, int256 amount1) =
IUniswapV3Pool(address (uint160 (pool))).swap(
recipient,
zeroForOne,
amount.toInt256(),
MIN_SQRT_RATIO + 1 ,
abi .encode (pool, tokenInAndPoolSalt)
);
amountOut = SafeMath.toUint256(- amount1);
} else {
(int256 amount0,) =
IUniswapV3Pool(address (uint160 (pool))).swap(
recipient,
zeroForOne,
amount.toInt256(),
MAX_SQRT_RATIO - 1 ,
abi .encode (pool, tokenInAndPoolSalt)
);
amountOut = SafeMath.toUint256(- amount0);
}
}
function _verifyPool (address tokenIn, address tokenOut, uint256 pool ) internal view returns (address nextTokenIn, bytes memory tokenInAndPoolSalt ) {
IUniswapV3Pool iPool = IUniswapV3Pool(address (uint160 (pool)));
address token0 = iPool.token0();
address token1 = iPool.token1();
uint24 fee = iPool.fee();
bytes32 poolSalt = keccak256 (abi .encode (token0, token1, fee));
bool zeroForOne = pool & _ZERO_FOR_ONE_MASK = = 0 ;
if (zeroForOne) {
require (tokenIn = = token0, "Bad pool" );
if (tokenOut ! = address (0 )) {
require (tokenOut = = token1, "Bad pool" );
}
nextTokenIn = token1;
tokenInAndPoolSalt = abi .encode (token0, poolSalt);
} else {
require (tokenIn = = token1, "Bad pool" );
if (tokenOut ! = address (0 )) {
require (tokenOut = = token0, "Bad pool" );
}
nextTokenIn = token0;
tokenInAndPoolSalt = abi .encode (token1, poolSalt);
}
}
function _verifyCallback (uint256 pool, bytes32 poolSalt, address caller ) internal view {
uint poolDigit = pool > > 248 & 0xf ;
UniswapV3Pool memory v3Pool = _uniswapV3_factory_allowed[poolDigit];
require (v3Pool.factory ! = address (0 ), "Callback bad pool indexed" );
address calcPool = address (
uint160 (
uint256 (
keccak256 (
abi .encodePacked (
hex'ff' ,
v3Pool.factory,
poolSalt,
v3Pool.initCodeHash
)
)
)
)
);
require (calcPool = = caller, "Callback bad pool" );
}
} {
"compilationTarget" : {
"TransitSwapRouterV5.sol" : "TransitSwapRouterV5"
} ,
"evmVersion" : "paris" ,
"libraries" : { } ,
"metadata" : {
"bytecodeHash" : "ipfs"
} ,
"optimizer" : {
"enabled" : true ,
"runs" : 200
} ,
"remappings" : [ ]
} [{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBridge","type":"address"}],"name":"ChangeAggregateBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"callers","type":"address[]"}],"name":"ChangeCrossCallerAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isAggregate","type":"bool"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"ChangeFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"preSigner","type":"address"},{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"ChangeSigner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"poolIndex","type":"uint256[]"},{"indexed":false,"internalType":"address[]","name":"factories","type":"address[]"},{"indexed":false,"internalType":"bytes[]","name":"initCodeHash","type":"bytes[]"}],"name":"ChangeV3FactoryAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"wrappedTokens","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":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":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChainID","type":"uint256"},{"indexed":false,"internalType":"string","name":"channel","type":"string"}],"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"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"CHECKFEE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct BaseCore.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct BaseCore.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct BaseCore.TransitSwapDescription","name":"desc","type":"tuple"},{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"bytes","name":"calldatas","type":"bytes"}],"internalType":"struct BaseCore.CallbytesDescription","name":"callbytesDesc","type":"tuple"}],"name":"aggregateAndGasUsed","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"crossCallers","type":"address[]"},{"internalType":"address[]","name":"wrappedTokens","type":"address[]"}],"name":"changeAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool[]","name":"isAggregate","type":"bool[]"},{"internalType":"uint256[]","name":"newRate","type":"uint256[]"}],"name":"changeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"changePause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"address","name":"signer","type":"address"}],"name":"changeTransitProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"poolIndex","type":"uint256[]"},{"internalType":"address[]","name":"factories","type":"address[]"},{"internalType":"bytes[]","name":"initCodeHash","type":"bytes[]"}],"name":"changeUniswapV3FactoryAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"toChain","type":"uint256"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"bytes","name":"calls","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct BaseCore.CrossDescription","name":"desc","type":"tuple"}],"name":"cross","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"router","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"pool","type":"address[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"string","name":"channel","type":"string"}],"internalType":"struct BaseCore.ExactInputV2SwapParams","name":"exactInput","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"exactInputV2Swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"router","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address[]","name":"pool","type":"address[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"string","name":"channel","type":"string"}],"internalType":"struct BaseCore.ExactInputV2SwapParams","name":"exactInput","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"exactInputV2SwapAndGasUsed","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"pools","type":"uint256[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"string","name":"channel","type":"string"}],"internalType":"struct BaseCore.ExactInputV3SwapParams","name":"params","type":"tuple"}],"name":"exactInputV3Swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"pools","type":"uint256[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"string","name":"channel","type":"string"}],"internalType":"struct BaseCore.ExactInputV3SwapParams","name":"params","type":"tuple"}],"name":"exactInputV3SwapAndGasUsed","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"pancakeV3SwapCallback","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"address","name":"newExecutor","type":"address"}],"name":"transferExecutorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"crossCaller","type":"address"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"transitAllowedQuery","outputs":[{"internalType":"bool","name":"isCrossCallerAllowed","type":"bool"},{"internalType":"bool","name":"isWrappedAllowed","type":"bool"},{"components":[{"internalType":"address","name":"factory","type":"address"},{"internalType":"bytes","name":"initCodeHash","type":"bytes"}],"internalType":"struct BaseCore.UniswapV3Pool","name":"pool","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transitProxyAddress","outputs":[{"internalType":"address","name":"bridgeProxy","type":"address"},{"internalType":"address","name":"feeSigner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]