Created
June 19, 2021 02:10
-
-
Save gg2001/d368cf21e9c16757db72af6813c7fad7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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