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

Adaptation of Repay with Collateral contract for Aave V2 #55

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
14 changes: 14 additions & 0 deletions src/core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ abstract contract FlashLoanSimpleReceiverBase is IFlashLoanSimpleReceiver {
POOL = IPool(provider.getPool());
}
}

interface IPoolAddressesProviderV2 {
function getLendingPool() external returns (address);
}

abstract contract FlashLoanSimpleReceiverBaseV2 is IFlashLoanSimpleReceiver {
IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER;
IPool public immutable override POOL;

constructor(IPoolAddressesProvider provider) {
ADDRESSES_PROVIDER = provider;
POOL = IPool(IPoolAddressesProviderV2(address(provider)).getLendingPool());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
pragma solidity ^0.8.10;

import {DataTypes} from 'aave-v3-core/contracts/protocol/libraries/types/DataTypes.sol';
import {FlashLoanSimpleReceiverBase} from 'aave-v3-core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol';
import {FlashLoanSimpleReceiverBase, FlashLoanSimpleReceiverBaseV2} from 'aave-v3-core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol';
import {ILendingPool, DataTypes as DataTypesV2} from './interfaces/ILendingPool.sol';
import {GPv2SafeERC20} from 'aave-v3-core/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {IERC20Detailed} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol';
Expand All @@ -17,7 +18,7 @@ import {Ownable} from 'aave-v3-core/contracts/dependencies/openzeppelin/contract
* @notice Utility functions for adapters using ParaSwap
* @author Jason Raymond Bell
*/
abstract contract BaseParaSwapAdapter is FlashLoanSimpleReceiverBase, Ownable {
abstract contract BaseParaSwapAdapter is FlashLoanSimpleReceiverBaseV2, Ownable {
using SafeMath for uint256;
using GPv2SafeERC20 for IERC20;
using GPv2SafeERC20 for IERC20Detailed;
Expand Down Expand Up @@ -51,7 +52,7 @@ abstract contract BaseParaSwapAdapter is FlashLoanSimpleReceiverBase, Ownable {

constructor(
IPoolAddressesProvider addressesProvider
) FlashLoanSimpleReceiverBase(addressesProvider) {
) FlashLoanSimpleReceiverBaseV2(addressesProvider) {
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
}

Expand Down Expand Up @@ -81,8 +82,8 @@ abstract contract BaseParaSwapAdapter is FlashLoanSimpleReceiverBase, Ownable {
*/
function _getReserveData(
address asset
) internal view returns (DataTypes.ReserveDataLegacy memory) {
return POOL.getReserveData(asset);
) internal view returns (DataTypesV2.ReserveData memory) {
return ILendingPool(address(POOL)).getReserveData(asset);
}

function _pullATokenAndWithdraw(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
* @param maxAmountToSwap Max amount to be swapped
* @param amountToReceive Amount to be received from the swap
* @return amountSold The amount sold during the swap
* @return amountBought The amount bought during the swap
*/
function _buyOnParaSwap(
uint256 toAmountOffset,
Expand All @@ -47,7 +48,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
IERC20Detailed assetToSwapTo,
uint256 maxAmountToSwap,
uint256 amountToReceive
) internal returns (uint256 amountSold) {
) internal returns (uint256 amountSold, uint256 amountBought) {
(bytes memory buyCalldata, IParaSwapAugustus augustus) = abi.decode(
paraswapData,
(bytes, IParaSwapAugustus)
Expand Down Expand Up @@ -75,7 +76,6 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this));

address tokenTransferProxy = augustus.getTokenTransferProxy();
assetToSwapFrom.safeApprove(tokenTransferProxy, 0);
assetToSwapFrom.safeApprove(tokenTransferProxy, maxAmountToSwap);

if (toAmountOffset != 0) {
Expand All @@ -101,12 +101,15 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
}
}

// Reset allowance
assetToSwapFrom.safeApprove(tokenTransferProxy, 0);

uint256 balanceAfterAssetFrom = assetToSwapFrom.balanceOf(address(this));
amountSold = balanceBeforeAssetFrom - balanceAfterAssetFrom;
require(amountSold <= maxAmountToSwap, 'WRONG_BALANCE_AFTER_SWAP');
uint256 amountReceived = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
require(amountReceived >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');
amountBought = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
require(amountBought >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');

emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountReceived);
emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountBought);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter {
revert(0, returndatasize())
}
}

require(
assetToSwapFrom.balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap,
'WRONG_BALANCE_AFTER_SWAP'
Expand Down
29 changes: 23 additions & 6 deletions src/periphery/contracts/adapters/paraswap/ParaSwapRepayAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {SafeMath} from 'aave-v3-core/contracts/dependencies/openzeppelin/contrac
import {BaseParaSwapBuyAdapter} from './BaseParaSwapBuyAdapter.sol';
import {IParaSwapAugustusRegistry} from './interfaces/IParaSwapAugustusRegistry.sol';
import {IParaSwapAugustus} from './interfaces/IParaSwapAugustus.sol';
import {DataTypes as DataTypesV2} from './interfaces/ILendingPool.sol';
import {ReentrancyGuard} from '../../dependencies/openzeppelin/ReentrancyGuard.sol';

/**
Expand Down Expand Up @@ -114,7 +115,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
// Pull aTokens from user
_pullATokenAndWithdraw(address(collateralAsset), msg.sender, collateralAmount, permitSignature);
//buy debt asset using collateral asset
uint256 amountSold = _buyOnParaSwap(
(uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
buyAllBalanceOffset,
paraswapData,
collateralAsset,
Expand All @@ -127,15 +128,23 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {

//deposit collateral back in the pool, if left after the swap(buy)
if (collateralBalanceLeft > 0) {
IERC20(collateralAsset).safeApprove(address(POOL), 0);
IERC20(collateralAsset).safeApprove(address(POOL), collateralBalanceLeft);
POOL.deposit(address(collateralAsset), collateralBalanceLeft, msg.sender, 0);
IERC20(collateralAsset).safeApprove(address(POOL), 0);
}

// Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
IERC20(debtAsset).safeApprove(address(POOL), 0);
IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
POOL.repay(address(debtAsset), debtRepayAmount, debtRateMode, msg.sender);
IERC20(debtAsset).safeApprove(address(POOL), 0);

{
//transfer excess of debtAsset back to the user, if any
uint256 debtAssetExcess = amountBought - debtRepayAmount;
if (debtAssetExcess > 0) {
IERC20(debtAsset).safeTransfer(msg.sender, debtAssetExcess);
}
}
}

/**
Expand Down Expand Up @@ -170,7 +179,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
initiator
);

uint256 amountSold = _buyOnParaSwap(
(uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
buyAllBalanceOffset,
paraswapData,
collateralAsset,
Expand All @@ -180,9 +189,9 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
);

// Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
IERC20(debtAsset).safeApprove(address(POOL), 0);
IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
POOL.repay(address(debtAsset), debtRepayAmount, rateMode, initiator);
IERC20(debtAsset).safeApprove(address(POOL), 0);

uint256 neededForFlashLoanRepay = amountSold.add(premium);

Expand All @@ -194,6 +203,14 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
permitSignature
);

{
//transfer excess of debtAsset back to the user, if any
uint256 debtAssetExcess = amountBought - debtRepayAmount;
if (debtAssetExcess > 0) {
IERC20(debtAsset).safeTransfer(initiator, debtAssetExcess);
}
}

// Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
IERC20(collateralAsset).safeApprove(address(POOL), 0);
IERC20(collateralAsset).safeApprove(address(POOL), collateralAmount.add(premium));
Expand All @@ -206,7 +223,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
uint256 debtRepayAmount,
address initiator
) private view returns (uint256) {
DataTypes.ReserveDataLegacy memory debtReserveData = _getReserveData(address(debtAsset));
DataTypesV2.ReserveData memory debtReserveData = _getReserveData(address(debtAsset));

address debtToken = DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE
? debtReserveData.stableDebtTokenAddress
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.0;

library DataTypes {
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}

struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
}

interface ILendingPool {
/**
* @dev Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
**/
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
}
Loading