From b4bc8dbef5f00b784c228a505d480f156278b12e Mon Sep 17 00:00:00 2001 From: kdbvier Date: Wed, 19 Jun 2024 01:42:06 -0700 Subject: [PATCH 1/3] add: same swap bsc contract added --- libs/BytesLib.sol | 101 ++++++++++++++++++++ same-swap-bsc.sol | 230 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 libs/BytesLib.sol create mode 100644 same-swap-bsc.sol diff --git a/libs/BytesLib.sol b/libs/BytesLib.sol new file mode 100644 index 0000000..82aee36 --- /dev/null +++ b/libs/BytesLib.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * @title Solidity Bytes Arrays Utils + * @author Gonçalo Sá + * + * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. + * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. + */ +pragma solidity =0.8.20; + +library BytesLib { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + require(_length + 31 >= _length, 'slice_overflow'); + require(_start + _length >= _start, 'slice_overflow'); + require(_bytes.length >= _start + _length, 'slice_outOfBounds'); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { + require(_start + 20 >= _start, 'toAddress_overflow'); + require(_bytes.length >= _start + 20, 'toAddress_outOfBounds'); + address tempAddress; + + assembly { + tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) + } + + return tempAddress; + } + + function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { + require(_start + 3 >= _start, 'toUint24_overflow'); + require(_bytes.length >= _start + 3, 'toUint24_outOfBounds'); + uint24 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x3), _start)) + } + + return tempUint; + } +} \ No newline at end of file diff --git a/same-swap-bsc.sol b/same-swap-bsc.sol new file mode 100644 index 0000000..269d2f1 --- /dev/null +++ b/same-swap-bsc.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.20; + +import '@openzeppelin/contracts/access/Ownable2Step.sol'; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; +import './libs/BytesLib.sol'; + +interface IV3SwapRouter { + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); +} + +interface IV2SwapRouter { + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + function swapExactETHForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external payable; + function swapExactTokensForETHSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; +} + +interface IWETH is IERC20 { + function deposit() external payable; + + function withdraw(uint amount) external; +} + +contract SameChainSwapBSC is Ownable2Step, ReentrancyGuard { + using SafeERC20 for IERC20; + using BytesLib for bytes; + + mapping(address => bool) public feeTokens; + uint256 public platformFee; // Fee must be by 1000, so if you want 5% this will be 5000 + address public feeReceiver; + uint256 public constant feeBps = 1000; // 1000 is 1% so we can have many decimals + + IV2SwapRouter public v2Router; + IV3SwapRouter public v3Router; + address public wethToken; + + error FailedCall(); // Used when transfer function is failed. + //////////================= Events ==================================================== + event SwapExecuted(address indexed tokenIn, address indexed tokenOut, uint amountIn, uint amountOut); + event FeeReceiverSet(address indexed _oldReceiver, address indexed _newReceiver); + event Fee(address indexed user, uint256 amount, address indexed token); + + constructor( + uint256 _fee, + address _feeReceiver, + address _v3Router, + address _v2Router, + address _weth + ) Ownable(msg.sender) { + platformFee = _fee; + feeReceiver = _feeReceiver; + v3Router = IV3SwapRouter(_v3Router); + v2Router = IV2SwapRouter(_v2Router); + wethToken = _weth; + } + uint256 public constant MAX_PLATFORM_FEE = 2000; // 20% in basis points + uint256 public threshold = 0.01 * 10 ** 18; // 20% in basis points + function changeFeeData(uint256 _fee, address _feeReceiver, uint256 _threshold) external onlyOwner { + require(_fee <= MAX_PLATFORM_FEE, 'Platform fee exceeds the maximum limit'); + address oldReceiver = feeReceiver; + platformFee = _fee; + feeReceiver = _feeReceiver; + threshold = _threshold; + emit FeeReceiverSet(oldReceiver, _feeReceiver); + } + + function swapOnce( + address _tokenA, + address _tokenB, + bool _unwrappETH, + uint256 _amountIn, + uint256 _minAmountOutV2, + uint256 _minAmountOutV3, + uint8 _buyOneTwoOrThree, // 1 means buy only v2, 2 means buy v3 only, 3 means buy first v2 then v3, 4 means buy first v3 then v2 + address[] memory _pathV2, + bytes memory _pathV3, + bool isWethIn + ) public payable nonReentrant { + // ETH -> Token + if (!isWethIn && _tokenA == wethToken) { + require(msg.value > 0, 'invalid msg.value'); + IWETH(wethToken).deposit{value: msg.value}(); + } else { + require(msg.value == 0, 'invalid msg.value'); + uint256 beforeTransfer = IERC20(_tokenA).balanceOf(address(this)); + IERC20(_tokenA).safeTransferFrom(msg.sender, address(this), _amountIn); + uint256 afterTransfer = IERC20(_tokenA).balanceOf(address(this)); + _amountIn = afterTransfer - beforeTransfer; + } + + uint256 amountIn = (msg.value > 0 ? msg.value : _amountIn); + uint256 output; + if (_buyOneTwoOrThree == 1) { + uint256 feeAmount = (amountIn * platformFee) / (feeBps * 100); + if (_pathV2[0] != wethToken) { + // WETH => Token + address[] memory path = new address[](2); + path[0] = _pathV2[0]; + path[1] = wethToken; + v2Swap(path, feeAmount, 0); + } + output = v2Swap(_pathV2, amountIn - feeAmount, _minAmountOutV2); + } else if (_buyOneTwoOrThree == 2) { + uint256 feeAmount = (amountIn * platformFee) / (feeBps * 100); + if (_pathV3.toAddress(0) == wethToken) { + // WETH => output Token + output = v3Swap(_tokenA, _pathV3, amountIn - feeAmount, _minAmountOutV3); + } else if (_pathV3.toAddress(23) == wethToken && _tokenB == wethToken) { + // Token => WETH + output = v3Swap(_tokenA, _pathV3, amountIn, _minAmountOutV3); + feeAmount = (output * platformFee) / (feeBps * 100); + output = output - feeAmount; + } else { + // Token => WETH (stable coins) => Token + v3Swap(_tokenA, _pathV3.slice(0, 43), feeAmount, 0); + output = v3Swap(_tokenA, _pathV3, amountIn - feeAmount, _minAmountOutV3); + } + } else if (_buyOneTwoOrThree == 3) { + output = v2Swap(_pathV2, amountIn, _minAmountOutV2); + uint256 feeAmount = (output * platformFee) / (feeBps * 100); + output = v3Swap(_pathV2[_pathV2.length - 1], _pathV3, output - feeAmount, _minAmountOutV3); + } else if (_buyOneTwoOrThree == 4) { + output = v3Swap(_tokenA, _pathV3, amountIn, _minAmountOutV3); + uint256 feeAmount = (output * platformFee) / (feeBps * 100); + output = v2Swap(_pathV2, output - feeAmount, _minAmountOutV2); + } + + if (_unwrappETH) { + IWETH(wethToken).withdraw(output); + // payable(msg.sender).transfer(output); + (bool success, ) = msg.sender.call{value: output}(''); + if (!success) { + revert FailedCall(); + } + } else { + IERC20(_tokenB).safeTransfer(msg.sender, output); + } + if (IWETH(wethToken).balanceOf(address(this)) >= threshold) { + IWETH(wethToken).withdraw(IWETH(wethToken).balanceOf(address(this))); + payable(feeReceiver).transfer(address(this).balance); + } + emit SwapExecuted(_tokenA, _tokenB, _amountIn, output); + } + + function checkAndApproveAll(address _token, address _target, uint256 _amountToCheck) internal { + if (IERC20(_token).allowance(address(this), _target) < _amountToCheck) { + IERC20(_token).forceApprove(_target, 0); + IERC20(_token).forceApprove(_target, ~uint256(0)); + } + } + + function v2Swap( + address[] memory _path, + uint256 _amountIn, + uint256 _minAmountOut // Slippage in base of 1000 meaning 10 is 1% and 1 is 0.1% where 1000 is 1 + ) internal returns (uint256) { + address tokenOut = _path[_path.length - 1]; + checkAndApproveAll(_path[0], address(v2Router), _amountIn); + uint256 initial = IERC20(tokenOut).balanceOf(address(this)); + v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens( + _amountIn, + _minAmountOut, + _path, + address(this), + block.timestamp * 5 minutes + ); + uint256 finalAmount = IERC20(tokenOut).balanceOf(address(this)); + return finalAmount - initial; + } + + function v3Swap( + address _tokenIn, + bytes memory _path, + uint256 _amountIn, + uint256 _minAmountOut + ) internal returns (uint256 amountOutput) { + checkAndApproveAll(_tokenIn, address(v3Router), _amountIn); + IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams( + _path, + address(this), + block.timestamp * 5 minutes, + _amountIn, + _minAmountOut + ); + amountOutput = v3Router.exactInput(params); + } + + function recoverStuckETH(address payable _beneficiary) public onlyOwner { + _beneficiary.transfer(address(this).balance); + } + + function recoverStuckTokens(address _token) external onlyOwner { + uint256 amount = IERC20(_token).balanceOf(address(this)); + IERC20(_token).safeTransfer(owner(), amount); + } + + receive() external payable {} + + fallback() external payable {} +} From 1902c64a934762eb69970acbe19f02a81b6a60cb Mon Sep 17 00:00:00 2001 From: kdbvier Date: Thu, 11 Jul 2024 02:07:53 -0700 Subject: [PATCH 2/3] update: instant swap contracts are updated --- AvaxInstantSwap.sol | 75 +++++++++++++------------- OfficialInstantSwap.sol | 115 +++++++++++++--------------------------- 2 files changed, 77 insertions(+), 113 deletions(-) diff --git a/AvaxInstantSwap.sol b/AvaxInstantSwap.sol index 2c4e9e8..c964f69 100644 --- a/AvaxInstantSwap.sol +++ b/AvaxInstantSwap.sol @@ -2,8 +2,6 @@ pragma solidity =0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; -import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; @@ -64,8 +62,8 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { ILBRouter public lbRouter; IQuoter public lbQuoter; - address public immutable wethToken; - address public immutable usdc; + address public wethToken; + address public usdc; address public executor; //////////================= Events ==================================================== @@ -73,19 +71,22 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { address indexed receiver, address indexed token, uint256 amountIn, - uint256 amountOut, uint256 time ); event ExecutorUpdated(address indexed oldExecutor, address indexed newExecutor); + modifier onlyExecutor() { + require(msg.sender == executor, "not executor"); + _; + } + constructor( address _lbRouter, address _lbQuoter, address _usdc, - address _executor, - address _owner - ) Ownable(_owner) { + address _executor + ) Ownable(msg.sender) { lbRouter = ILBRouter(_lbRouter); lbQuoter = IQuoter(_lbQuoter); wethToken = address(lbRouter.getWNATIVE()); @@ -95,7 +96,7 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { // To get the estimated path for making a swap function getQuote( - address[] calldata _path, + address[] memory _path, uint256 _amountIn ) public view returns (ILBRouter.Path memory) { // Use the quoter to find the best route for the swap @@ -121,36 +122,38 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { address _tokenB, uint256 _amountIn, uint256 _minAmountOut, - address[] calldata _path, + address[] memory _path, address _to, bool _unwrappETH - ) public nonReentrant { - require(_to != address(0), "can not send address(0)"); - require(msg.sender == executor, "not executor"); - + ) public nonReentrant onlyExecutor { if(_tokenB == usdc) { + emit SwapFromUSDC(_to, _tokenB, _amountIn, block.timestamp); IERC20(usdc).transfer(_to, _amountIn); - emit SwapFromUSDC(_to, _tokenB, _amountIn, _amountIn, block.timestamp); + return; + } + if (IERC20(usdc).allowance(address(this), address(lbRouter)) < _amountIn) { + IERC20(usdc).approve(address(lbRouter), _amountIn); + } + ILBRouter.Path memory pathQuote = getQuote(_path, _amountIn); + // Make LBRouter swap + if (_unwrappETH) { + lbRouter.swapExactTokensForNATIVESupportingFeeOnTransferTokens( + _amountIn, + _minAmountOut, // Amount out min + pathQuote, + payable(_to), + block.timestamp + 1 hours + ); } else { - checkAndApproveAll(usdc, address(lbRouter), _amountIn); - - ILBRouter.Path memory pathQuote = getQuote(_path, _amountIn); - uint256 output = lbRouter - .swapExactTokensForTokensSupportingFeeOnTransferTokens( - _amountIn, - _minAmountOut, // Amount out min - pathQuote, - _unwrappETH ? address(this) : _to, - block.timestamp + 10 minutes - ); - - if (_unwrappETH) { - IWNATIVE(wethToken).withdraw(output); - payable(_to).transfer(output); - } - - emit SwapFromUSDC(_to, _tokenB, _amountIn, output, block.timestamp); + lbRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( + _amountIn, + _minAmountOut, // Amount out min + pathQuote, + _to, + block.timestamp + 1 hours + ); } + emit SwapFromUSDC(_to, _tokenB, _amountIn, block.timestamp); } function setExecutor(address _newExecutor) external onlyOwner { @@ -165,7 +168,7 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { ) internal { if (IERC20(_token).allowance(address(this), _target) < _amountToCheck) { IERC20(_token).forceApprove(_target, 0); - IERC20(_token).forceApprove(_target, _amountToCheck); + IERC20(_token).forceApprove(_target, ~uint256(0)); } } @@ -176,10 +179,10 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { function recoverStuckTokens(address _token) external onlyOwner { uint256 amount = IERC20(_token).balanceOf(address(this)); - IERC20(_token).safeTransfer(owner(), amount); + IERC20(_token).transfer(owner(), amount); } receive() external payable {} fallback() external payable {} -} +} \ No newline at end of file diff --git a/OfficialInstantSwap.sol b/OfficialInstantSwap.sol index 92ad991..6650265 100644 --- a/OfficialInstantSwap.sol +++ b/OfficialInstantSwap.sol @@ -2,8 +2,6 @@ pragma solidity =0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; -import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; @@ -118,10 +116,10 @@ contract OfficialInstantSwap is Ownable, ReentrancyGuard { IUniswapV2Router02 public v2Router; IV3SwapRouter public v3Router; - address public immutable USDC; - address public immutable weth; + address public USDC; + address public weth; address public executor; - + error FailedCall(); modifier onlyExecutor() { require(msg.sender == executor, "not executor"); _; @@ -133,7 +131,6 @@ contract OfficialInstantSwap is Ownable, ReentrancyGuard { address indexed receiver, address indexed token, uint256 amountIn, - uint256 amountOut, uint256 time ); @@ -143,9 +140,8 @@ contract OfficialInstantSwap is Ownable, ReentrancyGuard { address _v2Router, address _executor, address _usdc, - address _weth, - address _owner - ) Ownable(_owner) { + address _weth + ) Ownable(msg.sender) { v3Router = IV3SwapRouter(_v3Router); v2Router = IUniswapV2Router02(_v2Router); executor= _executor; @@ -157,80 +153,49 @@ contract OfficialInstantSwap is Ownable, ReentrancyGuard { address _outputToken, uint256 _amountIn, uint256 _minAmountOut, + uint256 _minAmountOutV2Swap, bool _useV2, - address[] calldata _pathV2, - bytes calldata _pathV3, + address[] memory _pathV2, + bytes memory _pathV3, address to, bool unwrapETH ) public nonReentrant onlyExecutor { - require(to != address(0), "can not send address(0)"); // USDC -> Token - uint256 outputAmount; - if(_useV2) { - outputAmount = v2Swap(_pathV2, _amountIn, _minAmountOut, to, unwrapETH); - } else { - outputAmount = v3Swap(USDC, _pathV3, _amountIn, _minAmountOut, to, unwrapETH); + if(_outputToken == USDC) { + IERC20(USDC).transfer(to, _amountIn); + emit SwapFromUSDC(to, USDC, _amountIn, block.timestamp); + return; } - emit SwapFromUSDC(to, _outputToken, _amountIn, outputAmount, block.timestamp); - } - function directSendUSDC(address to, uint256 amount) external onlyExecutor { - require(to != address(0), "can not send address(0)"); - IERC20(USDC).transfer(to, amount); - emit SwapFromUSDC(to, USDC, amount,amount, block.timestamp); - } + // 1. Swap USDC to ETH (and/or final token) on v3 + IERC20(USDC).approve(address(v3Router), _amountIn); + IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams( + _pathV3, _useV2 || unwrapETH? address(this) : to, _amountIn, _minAmountOut + ); - function checkAndApproveAll(address _token, address _target, uint256 _amountToCheck) internal { - if (IERC20(_token).allowance(address(this), _target) < _amountToCheck) { - IERC20(_token).forceApprove(_target, 0); - IERC20(_token).forceApprove(_target, _amountToCheck); - } - } + uint256 wethOrFinalTokenOut = v3Router.exactInput(params); - function v2Swap( - address[] calldata _path, - uint256 _amountIn, - uint256 _minAmountOut, // Slippage in base of 1000 meaning 10 is 1% and 1 is 0.1% where 1000 is 1 - address to, - bool unwrapETH - ) internal returns (uint256) { - address tokenOut = _path[_path.length - 1]; - checkAndApproveAll(_path[0], address(v2Router), _amountIn); - uint256 initial = IERC20(tokenOut).balanceOf(to); - v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens( - _amountIn, - _minAmountOut, - _path, - unwrapETH ? address(this) : to, - block.timestamp + 10 minutes - ); - uint256 finalAmount = IERC20(tokenOut).balanceOf(to); - if (unwrapETH) { // Get ETH at the end - uint256 wethBalance = IERC20(weth).balanceOf(address(this)); - IWETH(weth).withdraw(wethBalance); - payable(to).transfer(address(this).balance); + if(_useV2) { + IERC20(weth).approve(address(v2Router), wethOrFinalTokenOut); + v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens( + wethOrFinalTokenOut, + _minAmountOutV2Swap, + _pathV2, + unwrapETH? address(this) : to, + block.timestamp + 1 hours + ); } - return finalAmount - initial; - } - function v3Swap( - address _tokenIn, - bytes calldata _path, - uint256 _amountIn, - uint256 _minAmountOut, - address to, - bool unwrapETH - ) internal returns (uint256 amountOutput) { - checkAndApproveAll(_tokenIn, address(v3Router), _amountIn); - IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams( - _path, unwrapETH ? address(this) : to, _amountIn, _minAmountOut - ); - amountOutput = v3Router.exactInput( params ); - if (unwrapETH) { // Get ETH at the end - uint256 wethBalance = IERC20(weth).balanceOf(address(this)); - IWETH(weth).withdraw(wethBalance); - payable(to).transfer(address(this).balance); + if(unwrapETH) { + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + IWETH(weth).withdraw(wethBalance); + // payable(receiverData.userReceiver).transfer(address(this).balance); + (bool success, ) = to.call{value: address(this).balance}(""); + if(!success) { + revert FailedCall(); + } } + emit SwapFromUSDC(to, _outputToken, _amountIn, block.timestamp); } function setExecutor(address _newExecutor) external onlyOwner { @@ -238,17 +203,13 @@ contract OfficialInstantSwap is Ownable, ReentrancyGuard { executor = _newExecutor; } - function recoverStuckETH(address payable _beneficiary) public onlyOwner { - _beneficiary.transfer(address(this).balance); - } - function recoverStuckTokens(address _token) external onlyOwner { uint256 amount = IERC20(_token).balanceOf(address(this)); - IERC20(_token).safeTransfer(owner(), amount); + IERC20(_token).transfer(owner(), amount); } receive() external payable {} fallback() external payable {} -} +} \ No newline at end of file From 644afe3b335874b9ec4cf7cd8b7382c8c3284224 Mon Sep 17 00:00:00 2001 From: merlox Date: Thu, 11 Jul 2024 10:00:33 -0400 Subject: [PATCH 3/3] Update AvaxInstantSwap.sol --- AvaxInstantSwap.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/AvaxInstantSwap.sol b/AvaxInstantSwap.sol index c964f69..e100050 100644 --- a/AvaxInstantSwap.sol +++ b/AvaxInstantSwap.sol @@ -60,10 +60,10 @@ interface IQuoter { contract AvaxInstantSwap is Ownable, ReentrancyGuard { using SafeERC20 for IERC20; - ILBRouter public lbRouter; - IQuoter public lbQuoter; - address public wethToken; - address public usdc; + ILBRouter public immutable lbRouter; + IQuoter public immutable lbQuoter; + address public immutable wethToken; + address public immutable usdc; address public executor; //////////================= Events ==================================================== @@ -172,9 +172,8 @@ contract AvaxInstantSwap is Ownable, ReentrancyGuard { } } - - function recoverStuckETH(address payable _beneficiary) public onlyOwner { - _beneficiary.transfer(address(this).balance); + function recoverStuckETH() public onlyOwner { + payable(owner()).transfer(address(this).balance); } function recoverStuckTokens(address _token) external onlyOwner {