Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(SwapRouter): add swap router #36

Merged
merged 2 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/CellarRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.13;
import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
import { ERC4626 } from "./base/ERC4626.sol";
import { ISwapRouter as UniswapV3Router } from "./interfaces/ISwapRouter.sol";
import { IUniswapV3Router as UniswapV3Router } from "./interfaces/IUniswapV3Router.sol";
import { IUniswapV2Router02 as UniswapV2Router } from "./interfaces/IUniswapV2Router02.sol";
import { ICellarRouter } from "./interfaces/ICellarRouter.sol";

Expand Down
100 changes: 100 additions & 0 deletions src/SwapRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.13;

import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
import { IUniswapV2Router02 as UniswapV2Router } from "./interfaces/IUniswapV2Router02.sol";
import { IUniswapV3Router as UniswapV3Router } from "./interfaces/IUniswapV3Router.sol";

contract SwapRouter {
using SafeTransferLib for ERC20;

enum Exchanges {
UNIV2,
UNIV3
}
/** @notice Planned additions
BALANCERV2,
CURVE,
ONEINCH
*/
mapping(Exchanges => bytes4) public idToSelector;

// ========================================== CONSTRUCTOR ==========================================

/**
* @notice Uniswap V2 swap router contract. Used for swapping if pool fees are not specified.
*/
UniswapV2Router public immutable uniswapV2Router; // 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D

/**
* @notice Uniswap V3 swap router contract. Used for swapping if pool fees are specified.
*/
UniswapV3Router public immutable uniswapV3Router; // 0xE592427A0AEce92De3Edee1F18E0157C05861564

/**
*
*/
constructor(UniswapV2Router _uniswapV2Router, UniswapV3Router _uniswapV3Router) {
//set up all exchanges
uniswapV2Router = _uniswapV2Router;
uniswapV3Router = _uniswapV3Router;

//set up mapping between ids and selectors
idToSelector[Exchanges.UNIV2] = SwapRouter(this).swapWithUniV2.selector;
idToSelector[Exchanges.UNIV3] = SwapRouter(this).swapWithUniV3.selector;
}

// ======================================= SWAP OPERATIONS =======================================

function swap(Exchanges id, bytes memory swapData) external returns (uint256 swapOutAmount) {
(bool success, bytes memory result) = address(this).call(abi.encodeWithSelector(idToSelector[id], swapData));
require(success, "Failed to perform swap");
swapOutAmount = abi.decode(result, (uint256));
}

function swapWithUniV2(bytes memory swapData) public returns (uint256 swapOutAmount) {
(address[] memory path, uint256 assets, uint256 assetsOutMin, address recipient) = abi.decode(
swapData,
(address[], uint256, uint256, address)
);
ERC20 assetIn = ERC20(path[0]);
// Approve assets to be swapped through the router.
assetIn.safeApprove(address(uniswapV2Router), assets);

// Execute the swap.
uint256[] memory amountsOut = uniswapV2Router.swapExactTokensForTokens(
assets,
assetsOutMin,
path,
recipient,
block.timestamp + 60
);
swapOutAmount = amountsOut[1];
}

function swapWithUniV3(bytes memory swapData) public returns (uint256 swapOutAmount) {
(address[] memory path, uint24[] memory poolFees, uint256 assets, uint256 assetsOutMin, address recipient) = abi
.decode(swapData, (address[], uint24[], uint256, uint256, address));
ERC20 assetIn = ERC20(path[0]);

// Approve assets to be swapped through the router.
assetIn.safeApprove(address(uniswapV3Router), assets);

// Encode swap parameters.
bytes memory encodePackedPath = abi.encodePacked(address(assetIn));
for (uint256 i = 1; i < path.length; i++)
encodePackedPath = abi.encodePacked(encodePackedPath, poolFees[i - 1], path[i]);

// Execute the swap.
swapOutAmount = uniswapV3Router.exactInput(
UniswapV3Router.ExactInputParams({
path: encodePackedPath,
recipient: recipient,
deadline: block.timestamp + 60,
amountIn: assets,
amountOutMinimum: assetsOutMin
})
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface IUniswapV3SwapCallback {

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
interface IUniswapV3Router is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
Expand Down
4 changes: 2 additions & 2 deletions src/mocks/MockSwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity 0.8.13;

import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { Math } from "src/utils/Math.sol";
import { ISwapRouter } from "../interfaces/ISwapRouter.sol";
import { IUniswapV3Router } from "../interfaces/IUniswapV3Router.sol";

library BytesLib {
function slice(
Expand Down Expand Up @@ -202,7 +202,7 @@ contract MockSwapRouter {
return amountOut;
}

function exactInput(ISwapRouter.ExactInputParams memory params) external returns (uint256) {
function exactInput(IUniswapV3Router.ExactInputParams memory params) external returns (uint256) {
(address tokenIn, address tokenOut, ) = params.path.decodeFirstPool();

while (params.path.hasMultiplePools()) {
Expand Down
2 changes: 1 addition & 1 deletion test/CellarRouter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.13;
import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { ERC4626 } from "src/base/ERC4626.sol";
import { CellarRouter } from "src/CellarRouter.sol";
import { ISwapRouter as UniswapV3Router } from "src/interfaces/ISwapRouter.sol";
import { IUniswapV3Router as UniswapV3Router } from "src/interfaces/IUniswapV3Router.sol";
import { IUniswapV2Router02 as UniswapV2Router } from "src/interfaces/IUniswapV2Router02.sol";
import { MockERC20 } from "src/mocks/MockERC20.sol";
import { MockERC4626 } from "src/mocks/MockERC4626.sol";
Expand Down