Skip to content

Instantly share code, notes, and snippets.

@korrio
Created October 22, 2024 06:21
Show Gist options
  • Save korrio/8bd3792f3dad661d25ba2247d1917500 to your computer and use it in GitHub Desktop.
Save korrio/8bd3792f3dad661d25ba2247d1917500 to your computer and use it in GitHub Desktop.
V3.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IQuoter.sol";
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
contract CrossDexAtomicSwap is Ownable {
// Router addresses for Base chain
address public constant UNISWAP_V3_ROUTER = 0x2626664c2603336E57B271c5C0b26F421741e481;
address public constant SUSHISWAP_V3_ROUTER = 0x0BE808376Ecb75a5CF9bB6D237d16cd37893d904;
// Quoter addresses
address public constant UNISWAP_QUOTER = 0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a;
address public constant SUSHISWAP_QUOTER = 0xb1E835Dc2785b52265711e17fCCb0fd018226a6e;
ISwapRouter public immutable uniswapRouter;
ISwapRouter public immutable sushiswapRouter;
IQuoter public immutable uniswapQuoter;
IQuoter public immutable sushiswapQuoter;
uint24 public constant poolFee = 3000; // 0.3%
constructor() Ownable(msg.sender) {
uniswapRouter = ISwapRouter(UNISWAP_V3_ROUTER);
sushiswapRouter = ISwapRouter(SUSHISWAP_V3_ROUTER);
uniswapQuoter = IQuoter(UNISWAP_QUOTER);
sushiswapQuoter = IQuoter(SUSHISWAP_QUOTER);
}
function atomicSwapWithBestRate(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 minAmountOut,
bool checkUniswapFirst
) external returns (uint256 amountOut) {
// Transfer tokens from user to contract
require(
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn),
"TransferFrom failed"
);
// Approve routers
TransferHelper.safeApprove(tokenIn, UNISWAP_V3_ROUTER, amountIn);
TransferHelper.safeApprove(tokenIn, SUSHISWAP_V3_ROUTER, amountIn);
// Prepare swap parameters
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: tokenIn,
tokenOut: tokenOut,
fee: poolFee,
recipient: address(this),
deadline: block.timestamp + 300,
amountIn: amountIn,
amountOutMinimum: 0, // We'll check total amount at the end
sqrtPriceLimitX96: 0
});
// Try first DEX
uint256 firstAmount;
try
(checkUniswapFirst ? uniswapRouter : sushiswapRouter).exactInputSingle(
params
)
returns (uint256 amount) {
firstAmount = amount;
} catch {
firstAmount = 0;
}
// Try second DEX
uint256 secondAmount;
if (firstAmount == 0) {
try
(checkUniswapFirst ? sushiswapRouter : uniswapRouter)
.exactInputSingle(params)
returns (uint256 amount) {
secondAmount = amount;
} catch {
secondAmount = 0;
}
}
// Get best amount
amountOut = firstAmount > secondAmount ? firstAmount : secondAmount;
require(amountOut >= minAmountOut, "Insufficient output amount");
// Transfer tokens back to user
require(
IERC20(tokenOut).transfer(msg.sender, amountOut),
"Transfer failed"
);
// Refund unused tokenIn if any
uint256 remainingBalance = IERC20(tokenIn).balanceOf(address(this));
if (remainingBalance > 0) {
require(
IERC20(tokenIn).transfer(msg.sender, remainingBalance),
"Refund failed"
);
}
}
// Function to get quote from both DEXes using Quoter contracts
function getQuotes(
address tokenIn,
address tokenOut,
uint256 amountIn
) external returns (uint256 uniswapQuote, uint256 sushiswapQuote) {
try uniswapQuoter.quoteExactInputSingle(
tokenIn,
tokenOut,
poolFee,
amountIn,
0
) returns (uint256 amount) {
uniswapQuote = amount;
} catch {
uniswapQuote = 0;
}
try sushiswapQuoter.quoteExactInputSingle(
tokenIn,
tokenOut,
poolFee,
amountIn,
0
) returns (uint256 amount) {
sushiswapQuote = amount;
} catch {
sushiswapQuote = 0;
}
}
// Emergency withdraw function
function emergencyWithdraw(
address token,
address to
) external onlyOwner {
uint256 balance = IERC20(token).balanceOf(address(this));
require(balance > 0, "No balance to withdraw");
require(IERC20(token).transfer(to, balance), "Withdraw failed");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment