Skip to content

Instantly share code, notes, and snippets.

@gg2001
Created June 19, 2021 02:10
Show Gist options
  • Save gg2001/d368cf21e9c16757db72af6813c7fad7 to your computer and use it in GitHub Desktop.
Save gg2001/d368cf21e9c16757db72af6813c7fad7 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.6;
pragma abicoder v2;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IUniswapV3FlashCallback } from "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import { LowGasSafeMath } from "@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { PoolAddress } from "@uniswap/v3-periphery/contracts/libraries/PoolAddress.sol";
import { CallbackValidation } from "@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol";
import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
interface CErc20Interface {
function mint(uint256 mintAmount) external returns (uint256);
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
function underlying() external returns (address);
}
contract FuseCollateralSwap is IUniswapV3FlashCallback {
using LowGasSafeMath for uint256;
using LowGasSafeMath for int256;
using SafeERC20 for IERC20;
address public immutable uniswapV3Factory;
address public immutable swapRouter;
constructor(address _uniswapV3Factory, address _swapRouter) {
uniswapV3Factory = _uniswapV3Factory;
swapRouter = _swapRouter;
}
// Initialise flash loan
// User must approve cToken0 before calling
function collateralSwap(
address cToken0,
address cToken1,
uint256 amount0,
uint256 amount1,
address pool,
PoolAddress.PoolKey calldata poolKey,
ISwapRouter.ExactOutputParams memory params
) external {
bytes memory data = abi.encode(msg.sender, cToken0, cToken1, amount0, amount1, poolKey, params);
IUniswapV3Pool(pool).flash(address(this), amount0, amount1, data);
}
// Flash loan callback
function uniswapV3FlashCallback(
uint256 fee0,
uint256 fee1,
bytes calldata data
) external override {
(
address user,
address cToken0,
address cToken1,
uint256 amount0,
uint256 amount1,
PoolAddress.PoolKey memory poolKey,
ISwapRouter.ExactOutputParams memory params
) =
abi.decode(
data,
(address, address, address, uint256, uint256, PoolAddress.PoolKey, ISwapRouter.ExactOutputParams)
);
CallbackValidation.verifyCallback(uniswapV3Factory, poolKey);
// Flash loan funds received
(address token, uint256 amount, uint256 fee) =
fee0 > fee1 ? (poolKey.token0, amount0, fee0) : (poolKey.token1, amount1, fee1);
// Approve flash loaned token to Fuse pool token
IERC20(token).safeApprove(cToken1, amount1);
// Mint new cToken
CErc20Interface(cToken1).mint(amount1);
// Transfer new cToken to user
IERC20(cToken1).safeTransfer(user, IERC20(cToken1).balanceOf(address(this)));
// Transfer old cToken from user to contract
IERC20(cToken0).safeTransferFrom(user, address(this), amount0);
// Redeem old cToken
CErc20Interface(cToken0).redeemUnderlying(amount0);
// Approve old token to be swapped on V3
IERC20(cToken0).safeApprove(swapRouter, IERC20(cToken0).balanceOf(address(this)));
// Swap old token on V3
ISwapRouter(swapRouter).exactOutput(params);
// Repay flash loan
IERC20(token).safeTransfer(msg.sender, LowGasSafeMath.add(amount, fee));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment