// SPDX-License-Identifier: GPL-2.0-or-laterpragmasolidity =0.8.20;import'@cryptoalgebra/integral-core/contracts/interfaces/callback/IAlgebraFlashCallback.sol';import'@cryptoalgebra/integral-periphery/contracts/base/PeripheryPayments.sol';import'@cryptoalgebra/integral-periphery/contracts/base/PeripheryImmutableState.sol';import'@cryptoalgebra/integral-periphery/contracts/libraries/PoolAddress.sol';import'@cryptoalgebra/integral-periphery/contracts/libraries/CallbackValidation.sol';import'@cryptoalgebra/integral-periphery/contracts/libraries/TransferHelper.sol';import'@cryptoalgebra/integral-periphery/contracts/interfaces/ISwapRouter.sol';/// @title Flash contract implementation/// @notice An example contract using the Algebra flash functioncontractPairFlashisIAlgebraFlashCallback, PeripheryImmutableState, PeripheryPayments { ISwapRouter publicimmutable swapRouter;constructor(ISwapRouter_swapRouter,address_factory,address_WMATIC,address_poolDeployer ) PeripheryImmutableState(_factory, _WMATIC, _poolDeployer) { swapRouter = _swapRouter; }/// @param fee0 The fee from calling flash for token0/// @param fee1 The fee from calling flash for token1/// @param data The data needed in the callback passed as FlashCallbackData from `initFlash`/// @notice implements the callback called from flash /// @dev fails if the flash is not profitable, meaning the amountOut from the flash is less than the amount borrowed
functionIAlgebraFlashCallback(uint256 fee0,uint256 fee1,bytescalldata data ) externaloverride { FlashCallbackData memory decoded = abi.decode(data, (FlashCallbackData)); CallbackValidation.verifyCallback(poolDeployer, decoded.poolKey);address token0 = decoded.poolKey.token0;address token1 = decoded.poolKey.token1; TransferHelper.safeApprove(token0,address(swapRouter), decoded.amount0); TransferHelper.safeApprove(token1,address(swapRouter), decoded.amount1);// profitable check// exactInputSingle will fail if this amount not metuint256 amount1Min = decoded.amount1 + fee1;uint256 amount0Min = decoded.amount0 + fee0;// call exactInputSingle for swapping token1 for token0 in pooluint256 amountOut0 = swapRouter.exactInputSingle( ISwapRouter.ExactInputSingleParams({ tokenIn: token1, tokenOut: token0, recipient:address(this), deadline: block.timestamp, amountIn: decoded.amount1, amountOutMinimum: amount0Min, sqrtPriceLimitX96:0 }) );// call exactInputSingle for swapping token0 for token 1 in pooluint256 amountOut1 = swapRouter.exactInputSingle( ISwapRouter.ExactInputSingleParams({ tokenIn: token0, tokenOut: token1, recipient:address(this), deadline: block.timestamp, amountIn: decoded.amount0, amountOutMinimum: amount1Min, sqrtPriceLimitX96:0 }) );// end up with amountOut0 of token0 from first swap and amountOut1 of token1 from second swapuint256 amount0Owed = decoded.amount0 + fee0;uint256 amount1Owed = decoded.amount1 + fee1; TransferHelper.safeApprove(token0,address(this), amount0Owed); TransferHelper.safeApprove(token1,address(this), amount1Owed);if (amount0Owed >0) pay(token0,address(this), msg.sender, amount0Owed);if (amount1Owed >0) pay(token1,address(this), msg.sender, amount1Owed);// if profitable pay profits to payerif (amountOut0 > amount0Owed) {uint256 profit0 = amountOut0 - amount0Owed; TransferHelper.safeApprove(token0,address(this), profit0);pay(token0,address(this), decoded.payer, profit0); }if (amountOut1 > amount1Owed) {uint256 profit1 = amountOut1 - amount1Owed; TransferHelper.safeApprove(token0,address(this), profit1);pay(token1,address(this), decoded.payer, profit1); } }structFlashParams {address token0;address token1;uint256 amount0;uint256 amount1; }structFlashCallbackData {uint256 amount0;uint256 amount1;address payer; PoolAddress.PoolKey poolKey; }/// @param params The parameters necessary for flash and the callback, passed in as FlashParams/// @notice Calls the pools flash function with data needed in `algebraFlashCallback`functioninitFlash(FlashParamsmemory params) external { PoolAddress.PoolKey memory poolKey = PoolAddress.PoolKey({token0: params.token0, token1: params.token1}); IAlgebraPool pool =IAlgebraPool(PoolAddress.computeAddress(poolDeployer, poolKey));// recipient of borrowed amounts// amount of token0 requested to borrow// amount of token1 requested to borrow// need amount 0 and amount1 in callback to pay back pool// recipient of flash should be THIS contract pool.flash(address(this), params.amount0, params.amount1, abi.encode(FlashCallbackData({ amount0: params.amount0, amount1: params.amount1, payer: msg.sender, poolKey: poolKey, }) ) ); }}