LCOV - code coverage report
Current view: top level - extensions/paraswap-adapters - ParaSwapRepayAdapter.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 93.0 % 43 40
Test Date: 2024-09-24 09:34:24 Functions: 80.0 % 5 4
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: BUSL-1.1
       2                 :             : pragma solidity ^0.8.10;
       3                 :             : 
       4                 :             : import {DataTypes} from '../../protocol/libraries/types/DataTypes.sol';
       5                 :             : import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
       6                 :             : import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
       7                 :             : import {IERC20WithPermit} from '../../interfaces/IERC20WithPermit.sol';
       8                 :             : import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
       9                 :             : import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol';
      10                 :             : import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol';
      11                 :             : import {BaseParaSwapBuyAdapter} from './BaseParaSwapBuyAdapter.sol';
      12                 :             : import {IParaSwapAugustusRegistry} from './interfaces/IParaSwapAugustusRegistry.sol';
      13                 :             : import {IParaSwapAugustus} from './interfaces/IParaSwapAugustus.sol';
      14                 :             : import {ReentrancyGuard} from '../../dependencies/openzeppelin/ReentrancyGuard.sol';
      15                 :             : 
      16                 :             : /**
      17                 :             :  * @title ParaSwapRepayAdapter
      18                 :             :  * @notice ParaSwap Adapter to perform a repay of a debt with collateral.
      19                 :             :  * @author Aave
      20                 :             :  **/
      21                 :             : contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
      22                 :             :   using SafeMath for uint256;
      23                 :             :   using SafeERC20 for IERC20;
      24                 :             : 
      25                 :             :   struct RepayParams {
      26                 :             :     address collateralAsset;
      27                 :             :     uint256 collateralAmount;
      28                 :             :     uint256 rateMode;
      29                 :             :     PermitSignature permitSignature;
      30                 :             :     bool useEthPath;
      31                 :             :   }
      32                 :             : 
      33                 :             :   constructor(
      34                 :             :     IPoolAddressesProvider addressesProvider,
      35                 :             :     IParaSwapAugustusRegistry augustusRegistry,
      36                 :             :     address owner
      37                 :             :   ) BaseParaSwapBuyAdapter(addressesProvider, augustusRegistry) {
      38                 :           0 :     transferOwnership(owner);
      39                 :             :   }
      40                 :             : 
      41                 :             :   /**
      42                 :             :    * @dev Uses the received funds from the flash loan to repay a debt on the protocol on behalf of the user. Then pulls
      43                 :             :    * the collateral from the user and swaps it to the debt asset to repay the flash loan.
      44                 :             :    * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset, swap it
      45                 :             :    * and repay the flash loan.
      46                 :             :    * Supports only one asset on the flash loan.
      47                 :             :    * @param asset The address of the flash-borrowed asset
      48                 :             :    * @param amount The amount of the flash-borrowed asset
      49                 :             :    * @param premium The fee of the flash-borrowed asset
      50                 :             :    * @param initiator The address of the flashloan initiator
      51                 :             :    * @param params The byte-encoded params passed when initiating the flashloan
      52                 :             :    * @return True if the execution of the operation succeeds, false otherwise
      53                 :             :    *   IERC20Detailed debtAsset Address of the debt asset
      54                 :             :    *   uint256 debtAmount Amount of debt to be repaid
      55                 :             :    *   uint256 rateMode Rate modes of the debt to be repaid
      56                 :             :    *   uint256 deadline Deadline for the permit signature
      57                 :             :    *   uint256 debtRateMode Rate mode of the debt to be repaid
      58                 :             :    *   bytes paraswapData Paraswap Data
      59                 :             :    *                    * bytes buyCallData Call data for augustus
      60                 :             :    *                    * IParaSwapAugustus augustus Address of Augustus Swapper
      61                 :             :    *   PermitSignature permitParams Struct containing the permit signatures, set to all zeroes if not used
      62                 :             :    */
      63                 :             :   function executeOperation(
      64                 :             :     address asset,
      65                 :             :     uint256 amount,
      66                 :             :     uint256 premium,
      67                 :             :     address initiator,
      68                 :             :     bytes calldata params
      69                 :             :   ) external override nonReentrant returns (bool) {
      70                 :           2 :     require(msg.sender == address(POOL), 'CALLER_MUST_BE_POOL');
      71                 :             : 
      72                 :           2 :     uint256 collateralAmount = amount;
      73                 :           2 :     address initiatorLocal = initiator;
      74                 :             : 
      75                 :           2 :     IERC20Detailed collateralAsset = IERC20Detailed(asset);
      76                 :             : 
      77                 :           2 :     _swapAndRepay(params, premium, initiatorLocal, collateralAsset, collateralAmount);
      78                 :             : 
      79                 :           2 :     return true;
      80                 :             :   }
      81                 :             : 
      82                 :             :   /**
      83                 :             :    * @dev Swaps the user collateral for the debt asset and then repay the debt on the protocol on behalf of the user
      84                 :             :    * without using flash loans. This method can be used when the temporary transfer of the collateral asset to this
      85                 :             :    * contract does not affect the user position.
      86                 :             :    * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset
      87                 :             :    * @param collateralAsset Address of asset to be swapped
      88                 :             :    * @param debtAsset Address of debt asset
      89                 :             :    * @param collateralAmount max Amount of the collateral to be swapped
      90                 :             :    * @param debtRepayAmount Amount of the debt to be repaid, or maximum amount when repaying entire debt
      91                 :             :    * @param debtRateMode Rate mode of the debt to be repaid
      92                 :             :    * @param buyAllBalanceOffset Set to offset of toAmount in Augustus calldata if wanting to pay entire debt, otherwise 0
      93                 :             :    * @param paraswapData Data for Paraswap Adapter
      94                 :             :    * @param permitSignature struct containing the permit signature
      95                 :             :    */
      96                 :             :   function swapAndRepay(
      97                 :             :     IERC20Detailed collateralAsset,
      98                 :             :     IERC20Detailed debtAsset,
      99                 :             :     uint256 collateralAmount,
     100                 :             :     uint256 debtRepayAmount,
     101                 :             :     uint256 debtRateMode,
     102                 :             :     uint256 buyAllBalanceOffset,
     103                 :             :     bytes calldata paraswapData,
     104                 :             :     PermitSignature calldata permitSignature
     105                 :             :   ) external nonReentrant {
     106                 :           4 :     debtRepayAmount = getDebtRepayAmount(
     107                 :             :       debtAsset,
     108                 :             :       debtRateMode,
     109                 :             :       buyAllBalanceOffset,
     110                 :             :       debtRepayAmount,
     111                 :             :       msg.sender
     112                 :             :     );
     113                 :             : 
     114                 :             :     // Pull aTokens from user
     115                 :           4 :     _pullATokenAndWithdraw(address(collateralAsset), msg.sender, collateralAmount, permitSignature);
     116                 :             :     //buy debt asset using collateral asset
     117                 :           4 :     (uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
     118                 :             :       buyAllBalanceOffset,
     119                 :             :       paraswapData,
     120                 :             :       collateralAsset,
     121                 :             :       debtAsset,
     122                 :             :       collateralAmount,
     123                 :             :       debtRepayAmount
     124                 :             :     );
     125                 :             : 
     126                 :           3 :     uint256 collateralBalanceLeft = collateralAmount - amountSold;
     127                 :             : 
     128                 :             :     //deposit collateral back in the pool, if left after the swap(buy)
     129                 :           3 :     if (collateralBalanceLeft > 0) {
     130                 :           1 :       IERC20(collateralAsset).safeApprove(address(POOL), collateralBalanceLeft);
     131                 :           1 :       POOL.deposit(address(collateralAsset), collateralBalanceLeft, msg.sender, 0);
     132                 :           1 :       IERC20(collateralAsset).safeApprove(address(POOL), 0);
     133                 :             :     }
     134                 :             : 
     135                 :             :     // Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
     136                 :           3 :     IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
     137                 :           3 :     POOL.repay(address(debtAsset), debtRepayAmount, debtRateMode, msg.sender);
     138                 :           3 :     IERC20(debtAsset).safeApprove(address(POOL), 0);
     139                 :             : 
     140                 :             :     {
     141                 :             :       //transfer excess of debtAsset back to the user, if any
     142                 :           3 :       uint256 debtAssetExcess = amountBought - debtRepayAmount;
     143                 :           3 :       if (debtAssetExcess > 0) {
     144                 :           0 :         IERC20(debtAsset).safeTransfer(msg.sender, debtAssetExcess);
     145                 :             :       }
     146                 :             :     }
     147                 :             :   }
     148                 :             : 
     149                 :             :   /**
     150                 :             :    * @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan
     151                 :             :    * @param premium Fee of the flash loan
     152                 :             :    * @param initiator Address of the user
     153                 :             :    * @param collateralAsset Address of token to be swapped
     154                 :             :    * @param collateralAmount Amount of the reserve to be swapped(flash loan amount)
     155                 :             :    */
     156                 :             : 
     157                 :             :   function _swapAndRepay(
     158                 :             :     bytes calldata params,
     159                 :             :     uint256 premium,
     160                 :             :     address initiator,
     161                 :             :     IERC20Detailed collateralAsset,
     162                 :             :     uint256 collateralAmount
     163                 :             :   ) private {
     164                 :           2 :     (
     165                 :             :       IERC20Detailed debtAsset,
     166                 :             :       uint256 debtRepayAmount,
     167                 :             :       uint256 buyAllBalanceOffset,
     168                 :             :       uint256 rateMode,
     169                 :             :       bytes memory paraswapData,
     170                 :             :       PermitSignature memory permitSignature
     171                 :           2 :     ) = abi.decode(params, (IERC20Detailed, uint256, uint256, uint256, bytes, PermitSignature));
     172                 :             : 
     173                 :           2 :     debtRepayAmount = getDebtRepayAmount(
     174                 :             :       debtAsset,
     175                 :             :       rateMode,
     176                 :             :       buyAllBalanceOffset,
     177                 :             :       debtRepayAmount,
     178                 :             :       initiator
     179                 :             :     );
     180                 :             : 
     181                 :           2 :     (uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
     182                 :             :       buyAllBalanceOffset,
     183                 :             :       paraswapData,
     184                 :             :       collateralAsset,
     185                 :             :       debtAsset,
     186                 :             :       collateralAmount,
     187                 :             :       debtRepayAmount
     188                 :             :     );
     189                 :             : 
     190                 :             :     // Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
     191                 :           2 :     IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
     192                 :           2 :     POOL.repay(address(debtAsset), debtRepayAmount, rateMode, initiator);
     193                 :           2 :     IERC20(debtAsset).safeApprove(address(POOL), 0);
     194                 :             : 
     195                 :           2 :     uint256 neededForFlashLoanRepay = amountSold.add(premium);
     196                 :             : 
     197                 :             :     // Pull aTokens from user
     198                 :           2 :     _pullATokenAndWithdraw(
     199                 :             :       address(collateralAsset),
     200                 :             :       initiator,
     201                 :             :       neededForFlashLoanRepay,
     202                 :             :       permitSignature
     203                 :             :     );
     204                 :             : 
     205                 :             :     {
     206                 :             :       //transfer excess of debtAsset back to the user, if any
     207                 :           2 :       uint256 debtAssetExcess = amountBought - debtRepayAmount;
     208                 :           2 :       if (debtAssetExcess > 0) {
     209                 :           0 :         IERC20(debtAsset).safeTransfer(initiator, debtAssetExcess);
     210                 :             :       }
     211                 :             :     }
     212                 :             : 
     213                 :             :     // Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
     214                 :           2 :     IERC20(collateralAsset).safeApprove(address(POOL), 0);
     215                 :           2 :     IERC20(collateralAsset).safeApprove(address(POOL), collateralAmount.add(premium));
     216                 :             :   }
     217                 :             : 
     218                 :             :   function getDebtRepayAmount(
     219                 :             :     IERC20Detailed debtAsset,
     220                 :             :     uint256 rateMode,
     221                 :             :     uint256 buyAllBalanceOffset,
     222                 :             :     uint256 debtRepayAmount,
     223                 :             :     address initiator
     224                 :             :   ) private view returns (uint256) {
     225                 :           6 :     require(
     226                 :             :       DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE,
     227                 :             :       'INVALID_RATE_MODE'
     228                 :             :     );
     229                 :           6 :     DataTypes.ReserveDataLegacy memory debtReserveData = _getReserveData(address(debtAsset));
     230                 :             : 
     231                 :           6 :     uint256 currentDebt = IERC20(debtReserveData.variableDebtTokenAddress).balanceOf(initiator);
     232                 :             : 
     233                 :           6 :     if (buyAllBalanceOffset != 0) {
     234                 :           1 :       require(currentDebt <= debtRepayAmount, 'INSUFFICIENT_AMOUNT_TO_REPAY');
     235                 :           1 :       debtRepayAmount = currentDebt;
     236                 :             :     } else {
     237                 :           5 :       require(debtRepayAmount <= currentDebt, 'INVALID_DEBT_REPAY_AMOUNT');
     238                 :             :     }
     239                 :             : 
     240                 :           6 :     return debtRepayAmount;
     241                 :             :   }
     242                 :             : }
        

Generated by: LCOV version 2.1-1