From 62413849338780f7f471d95583df3d9ceb870b07 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 4 Mar 2022 17:44:36 +0530 Subject: [PATCH] removed executeOperation func + refactored code --- .../connectors/aave/v3-import/helpers.sol | 257 +++++++++++- .../connectors/aave/v3-import/interface.sol | 12 +- .../connectors/aave/v3-import/main.sol | 391 +++--------------- package.json | 6 +- 4 files changed, 304 insertions(+), 362 deletions(-) diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol index 19d464dd..41073f7d 100644 --- a/contracts/mainnet/connectors/aave/v3-import/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -2,11 +2,12 @@ pragma solidity ^0.7.0; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; -import { AaveInterface, IFlashLoan, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; -abstract contract Helpers is DSMath, Basic { +abstract contract AaveResolver is DSMath, Basic { /** * @dev Aave referal code */ @@ -17,16 +18,14 @@ abstract contract Helpers is DSMath, Basic { */ AaveLendingPoolProviderInterface internal constant aaveProvider = AaveLendingPoolProviderInterface( - 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 + 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this ); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); - - address flashloanAddr = 0x619Ad2D02dBeE6ebA3CDbDA3F98430410e892882; + AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this function getIsColl(address token, address user) internal @@ -35,4 +34,246 @@ abstract contract Helpers is DSMath, Basic { { (, , , , , , , , isCol) = aaveData.getUserReserveData(token, user); } + + struct ImportData { + address[] _supplyTokens; + address[] _borrowTokens; + ATokenInterface[] aTokens; + uint256[] supplyAmts; + uint256[] variableBorrowAmts; + uint256[] variableBorrowAmtsWithFee; + uint256[] stableBorrowAmts; + uint256[] stableBorrowAmtsWithFee; + uint256[] totalBorrowAmts; + uint256[] totalBorrowAmtsWithFee; + bool convertStable; + } + + struct ImportInputData { + address[] supplyTokens; + address[] borrowTokens; + bool convertStable; + uint256[] flashLoanFees; + } +} + +contract AaveHelpers is AaveResolver { + function getBorrowAmount(address _token, address userAccount) + internal + view + returns (uint256 stableBorrow, uint256 variableBorrow) + { + ( + , + address stableDebtTokenAddress, + address variableDebtTokenAddress + ) = aaveData.getReserveTokensAddresses(_token); + + stableBorrow = ATokenInterface(stableDebtTokenAddress).balanceOf( + userAccount + ); + variableBorrow = ATokenInterface(variableDebtTokenAddress).balanceOf( + userAccount + ); + } + + function getBorrowAmounts( + address userAccount, + AaveInterface aave, + ImportInputData memory inputData, + ImportData memory data + ) internal returns (ImportData memory) { + if (inputData.borrowTokens.length > 0) { + data._borrowTokens = new address[](inputData.borrowTokens.length); + data.variableBorrowAmts = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmts = new uint256[]( + inputData.borrowTokens.length + ); + data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + for (uint256 i = 0; i < inputData.borrowTokens.length; i++) { + for (uint256 j = i; j < inputData.borrowTokens.length; j++) { + if (j != i) { + require( + inputData.borrowTokens[i] != + inputData.borrowTokens[j], + "token-repeated" + ); + } + } + } + for (uint256 i = 0; i < inputData.borrowTokens.length; i++) { + address _token = inputData.borrowTokens[i] == ethAddr + ? wethAddr + : inputData.borrowTokens[i]; + data._borrowTokens[i] = _token; + + ( + data.stableBorrowAmts[i], + data.variableBorrowAmts[i] + ) = getBorrowAmount(_token, userAccount); + + if (data.variableBorrowAmts[i] != 0) { + data.variableBorrowAmtsWithFee[i] = add( + data.variableBorrowAmts[i], + inputData.flashLoanFees[i] + ); + data.stableBorrowAmtsWithFee[i] = data.stableBorrowAmts[i]; + } else { + data.stableBorrowAmtsWithFee[i] = add( + data.stableBorrowAmts[i], + inputData.flashLoanFees[i] + ); + } + + data.totalBorrowAmts[i] = add( + data.stableBorrowAmts[i], + data.variableBorrowAmts[i] + ); + data.totalBorrowAmtsWithFee[i] = add( + data.stableBorrowAmtsWithFee[i], + data.variableBorrowAmtsWithFee[i] + ); + + if (data.totalBorrowAmts[i] > 0) { + uint256 _amt = data.totalBorrowAmts[i]; + TokenInterface(_token).approve(address(aave), _amt); + } + } + } + return data; + } + + function getSupplyAmounts( + address userAccount, + ImportInputData memory inputData, + ImportData memory data + ) internal view returns (ImportData memory) { + data.supplyAmts = new uint256[](inputData.supplyTokens.length); + data._supplyTokens = new address[](inputData.supplyTokens.length); + data.aTokens = new ATokenInterface[](inputData.supplyTokens.length); + + for (uint256 i = 0; i < inputData.supplyTokens.length; i++) { + for (uint256 j = i; j < inputData.supplyTokens.length; j++) { + if (j != i) { + require( + inputData.supplyTokens[i] != inputData.supplyTokens[j], + "token-repeated" + ); + } + } + } + for (uint256 i = 0; i < inputData.supplyTokens.length; i++) { + address _token = inputData.supplyTokens[i] == ethAddr + ? wethAddr + : inputData.supplyTokens[i]; + (address _aToken, , ) = aaveData.getReserveTokensAddresses(_token); + data._supplyTokens[i] = _token; + data.aTokens[i] = ATokenInterface(_aToken); + data.supplyAmts[i] = data.aTokens[i].balanceOf(userAccount); + } + + return data; + } + + function _paybackBehalfOne( + AaveInterface aave, + address token, + uint256 amt, + uint256 rateMode, + address user + ) private { + aave.repay(token, amt, rateMode, user); + } + + function _PaybackStable( + uint256 _length, + AaveInterface aave, + address[] memory tokens, + uint256[] memory amts, + address user + ) internal { + for (uint256 i = 0; i < _length; i++) { + if (amts[i] > 0) { + _paybackBehalfOne(aave, tokens[i], amts[i], 1, user); + } + } + } + + function _PaybackVariable( + uint256 _length, + AaveInterface aave, + address[] memory tokens, + uint256[] memory amts, + address user + ) internal { + for (uint256 i = 0; i < _length; i++) { + if (amts[i] > 0) { + _paybackBehalfOne(aave, tokens[i], amts[i], 2, user); + } + } + } + + function _TransferAtokens( + uint256 _length, + AaveInterface aave, + ATokenInterface[] memory atokenContracts, + uint256[] memory amts, + address[] memory tokens, + address userAccount + ) internal { + for (uint256 i = 0; i < _length; i++) { + if (amts[i] > 0) { + uint256 _amt = amts[i]; + require( + atokenContracts[i].transferFrom( + userAccount, + address(this), + _amt + ), + "allowance?" + ); + + if (!getIsColl(tokens[i], address(this))) { + aave.setUserUseReserveAsCollateral(tokens[i], true); + } + } + } + } + + function _BorrowVariable( + uint256 _length, + AaveInterface aave, + address[] memory tokens, + uint256[] memory amts + ) internal { + for (uint256 i = 0; i < _length; i++) { + if (amts[i] > 0) { + _borrowOne(aave, tokens[i], amts[i], 2); + } + } + } + + function _BorrowStable( + uint256 _length, + AaveInterface aave, + address[] memory tokens, + uint256[] memory amts + ) internal { + for (uint256 i = 0; i < _length; i++) { + if (amts[i] > 0) { + _borrowOne(aave, tokens[i], amts[i], 1); + } + } + } + + function _borrowOne( + AaveInterface aave, + address token, + uint256 amt, + uint256 rateMode + ) private { + aave.borrow(token, amt, rateMode, referalCode, address(this)); + } } diff --git a/contracts/mainnet/connectors/aave/v3-import/interface.sol b/contracts/mainnet/connectors/aave/v3-import/interface.sol index 7bef374b..26a9fcaa 100644 --- a/contracts/mainnet/connectors/aave/v3-import/interface.sol +++ b/contracts/mainnet/connectors/aave/v3-import/interface.sol @@ -37,16 +37,6 @@ interface AaveInterface { function swapBorrowRateMode(address _asset, uint256 _rateMode) external; } -interface IFlashLoan { - function flashLoan( - address[] memory tokens_, - uint256[] memory amts_, - uint256 route, - bytes calldata data_, - bytes calldata instaData_ - ) external; -} - interface ATokenInterface { function scaledBalanceOf(address _user) external view returns (uint256); @@ -67,7 +57,7 @@ interface ATokenInterface { } interface AaveLendingPoolProviderInterface { - function getLendingPool() external view returns (address); + function getPool() external view returns (address); } interface AaveDataProviderInterface { diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index b4dc4849..8c0de43f 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -2,342 +2,9 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; -import { Helpers } from "./helpers.sol"; -import { AaveInterface, ATokenInterface, IFlashLoan } from "./interface.sol"; -import { Events } from "./events.sol"; - -contract AaveResolver is Helpers, Events { - struct ImportData { - address[] _supplyTokens; - address[] _borrowTokens; - ATokenInterface[] aTokens; - uint256[] supplyAmts; - uint256[] variableBorrowAmts; - uint256[] variableBorrowAmtsWithFee; - uint256[] stableBorrowAmts; - uint256[] stableBorrowAmtsWithFee; - uint256[] totalBorrowAmts; - uint256[] totalBorrowAmtsWithFee; - bool convertStable; - address userAccount; - } - - struct ImportInputData { - address userAccount; - address[] supplyTokens; - address[] borrowTokens; - bool convertStable; - } - - function _paybackBehalfOne( - AaveInterface aave, - address token, - uint256 amt, - uint256 rateMode, - address user - ) private { - aave.repay(token, amt, rateMode, user); - } - - function _PaybackStable( - uint256 _length, - AaveInterface aave, - address[] memory tokens, - uint256[] memory amts, - address user - ) internal { - for (uint256 i = 0; i < _length; i++) { - if (amts[i] > 0) { - _paybackBehalfOne(aave, tokens[i], amts[i], 1, user); - } - } - } - - function _PaybackVariable( - uint256 _length, - AaveInterface aave, - address[] memory tokens, - uint256[] memory amts, - address user - ) internal { - for (uint256 i = 0; i < _length; i++) { - if (amts[i] > 0) { - _paybackBehalfOne(aave, tokens[i], amts[i], 2, user); - } - } - } - - function _TransferAtokens( - uint256 _length, - AaveInterface aave, - ATokenInterface[] memory atokenContracts, - uint256[] memory amts, - address[] memory tokens, - address userAccount - ) internal { - for (uint256 i = 0; i < _length; i++) { - if (amts[i] > 0) { - uint256 _amt = amts[i]; - require( - atokenContracts[i].transferFrom( - userAccount, - address(this), - _amt - ), - "allowance?" - ); - - if (!getIsColl(tokens[i], address(this))) { - aave.setUserUseReserveAsCollateral(tokens[i], true); - } - } - } - } - - function _BorrowVariable( - uint256 _length, - AaveInterface aave, - address[] memory tokens, - uint256[] memory amts - ) internal { - for (uint256 i = 0; i < _length; i++) { - if (amts[i] > 0) { - _borrowOne(aave, tokens[i], amts[i], 2); - } - } - } - - function _BorrowStable( - uint256 _length, - AaveInterface aave, - address[] memory tokens, - uint256[] memory amts - ) internal { - for (uint256 i = 0; i < _length; i++) { - if (amts[i] > 0) { - _borrowOne(aave, tokens[i], amts[i], 1); - } - } - } - - function _borrowOne( - AaveInterface aave, - address token, - uint256 amt, - uint256 rateMode - ) private { - aave.borrow(token, amt, rateMode, referalCode, address(this)); - } - - function _includeFee(ImportData memory Data, uint256[] calldata premiums) - internal - returns (ImportData memory) - { - for (uint256 i = 0; i < Data._borrowTokens.length; i++) { - Data.totalBorrowAmtsWithFee[i] = - Data.totalBorrowAmts[i] + - premiums[i]; - Data.variableBorrowAmtsWithFee[i] = - Data.variableBorrowAmts[i] + - premiums[i]; - } - return Data; - } - - function _balance(address token) internal view returns (uint256 balance) { - balance = TokenInterface(token).balanceOf(address(this)); - } - - function _repay( - address[] memory tokens, - uint256[] memory amounts, - address recepient - ) internal { - for (uint256 i = 0; i < tokens.length; i++) { - require(_balance(tokens[i]) >= amounts[i], "Repay failed!"); - TokenInterface(tokens[i]).transfer(recepient, amounts[i]); - } - } -} - -contract AaveHelpers is AaveResolver { - function getBorrowAmount(address _token, address userAccount) - internal - view - returns (uint256 stableBorrow, uint256 variableBorrow) - { - ( - , - address stableDebtTokenAddress, - address variableDebtTokenAddress - ) = aaveData.getReserveTokensAddresses(_token); - - stableBorrow = ATokenInterface(stableDebtTokenAddress).balanceOf( - userAccount - ); - variableBorrow = ATokenInterface(variableDebtTokenAddress).balanceOf( - userAccount - ); - } - - function getBorrowAmounts( - address userAccount, - AaveInterface aave, - ImportInputData memory inputData, - ImportData memory data - ) internal returns (ImportData memory) { - if (inputData.borrowTokens.length > 0) { - data._borrowTokens = new address[](inputData.borrowTokens.length); - data.variableBorrowAmts = new uint256[]( - inputData.borrowTokens.length - ); - data.stableBorrowAmts = new uint256[]( - inputData.borrowTokens.length - ); - data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); - for (uint256 i = 0; i < inputData.borrowTokens.length; i++) { - for (uint256 j = i; j < inputData.borrowTokens.length; j++) { - if (j != i) { - require( - inputData.borrowTokens[i] != - inputData.borrowTokens[j], - "token-repeated" - ); - } - } - } - for (uint256 i = 0; i < inputData.borrowTokens.length; i++) { - address _token = inputData.borrowTokens[i] == ethAddr - ? wethAddr - : inputData.borrowTokens[i]; - data._borrowTokens[i] = _token; - - ( - data.stableBorrowAmts[i], - data.variableBorrowAmts[i] - ) = getBorrowAmount(_token, inputData.userAccount); - - data.totalBorrowAmts[i] = add( - data.stableBorrowAmts[i], - data.variableBorrowAmts[i] - ); - - if (data.totalBorrowAmts[i] > 0) { - uint256 _amt = data.totalBorrowAmts[i]; - TokenInterface(_token).approve(address(aave), _amt); - } - } - } - return data; - } - - function getSupplyAmounts( - address userAccount, - ImportInputData memory inputData, - ImportData memory data - ) internal view returns (ImportData memory) { - data.supplyAmts = new uint256[](inputData.supplyTokens.length); - data._supplyTokens = new address[](inputData.supplyTokens.length); - data.aTokens = new ATokenInterface[](inputData.supplyTokens.length); - - for (uint256 i = 0; i < inputData.supplyTokens.length; i++) { - for (uint256 j = i; j < inputData.supplyTokens.length; j++) { - if (j != i) { - require( - inputData.supplyTokens[i] != inputData.supplyTokens[j], - "token-repeated" - ); - } - } - } - for (uint256 i = 0; i < inputData.supplyTokens.length; i++) { - address _token = inputData.supplyTokens[i] == ethAddr - ? wethAddr - : inputData.supplyTokens[i]; - (address _aToken, , ) = aaveData.getReserveTokensAddresses(_token); - data._supplyTokens[i] = _token; - data.aTokens[i] = ATokenInterface(_aToken); - data.supplyAmts[i] = data.aTokens[i].balanceOf(userAccount); - } - - return data; - } - - function flashBorrow( - address[] memory _tokens, - uint256[] memory _amts, - uint256 _route, - bytes memory _data - ) public { - bytes memory instaData; - IFlashLoan flashLoan = IFlashLoan(flashloanAddr); - flashLoan.flashLoan(_tokens, _amts, _route, _data, instaData); - } - - function executeOperation( - address[] calldata tokens, - uint256[] calldata amounts, - uint256[] calldata premiums, - address initiator, - bytes calldata params - ) external returns (bool) { - ImportData memory data; - (data) = abi.decode(params, (ImportData)); - - // 1. payback borrowed amount; - AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); - _PaybackStable( - data._borrowTokens.length, - aave, - data._borrowTokens, - data.stableBorrowAmts, - data.userAccount - ); - _PaybackVariable( - data._borrowTokens.length, - aave, - data._borrowTokens, - data.variableBorrowAmts, - data.userAccount - ); - - // 2. transfer atokens to this address; - _TransferAtokens( - data._supplyTokens.length, - aave, - data.aTokens, - data.supplyAmts, - data._supplyTokens, - data.userAccount - ); - // 3. take debt including flashloan fee; - data = _includeFee(data, premiums); - - if (data.convertStable) { - _BorrowVariable( - data._borrowTokens.length, - aave, - data._borrowTokens, - data.totalBorrowAmtsWithFee - ); - } else { - _BorrowStable( - data._borrowTokens.length, - aave, - data._borrowTokens, - data.stableBorrowAmts - ); - _BorrowVariable( - data._borrowTokens.length, - aave, - data._borrowTokens, - data.variableBorrowAmtsWithFee - ); - } - // 4. repay flashloan with the borrowed assets - _repay(data._borrowTokens, data.totalBorrowAmtsWithFee, flashloanAddr); - } -} +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; contract AaveV3ImportResolver is AaveHelpers { function _importAave(address userAccount, ImportInputData memory inputData) @@ -353,15 +20,59 @@ contract AaveV3ImportResolver is AaveHelpers { ImportData memory data; - AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + AaveInterface aave = AaveInterface(aaveProvider.getPool()); data = getBorrowAmounts(userAccount, aave, inputData, data); data = getSupplyAmounts(userAccount, inputData, data); - data.convertStable = inputData.convertStable; - bytes memory _callData = abi.encode(data); + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); - flashBorrow(data._borrowTokens, data.totalBorrowAmts, 5, _callData); + // transfer atokens to this address; + _TransferAtokens( + data._supplyTokens.length, + aave, + data.aTokens, + data.supplyAmts, + data._supplyTokens, + userAccount + ); + + // borrow assets after migrating position + if (data.convertStable) { + _BorrowVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.totalBorrowAmtsWithFee + ); + } else { + _BorrowStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmtsWithFee + ); + _BorrowVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmtsWithFee + ); + } _eventName = "LogAaveV2Import(address,bool,address[],address[],uint256[],uint256[],uint256[])"; _eventParam = abi.encode( diff --git a/package.json b/package.json index 2e73b9a1..aae8f5ba 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "scripts": { "test": "hardhat run scripts/tests/global-test.ts", "coverage": "./node_modules/.bin/solidity-coverage", - "check": "node status-checks/huskyCheck.js", - "check-husky": "node status-checks/huskyCheck.js", + "check": "node status-checks/huskyCheck.ts", + "check-husky": "node status-checks/huskyCheck.ts", "deploy": "node scripts/deployConnectorsFromCmd.js", "test:runner": "hardhat run scripts/tests/run-tests.ts", "typechain": "hardhat typechain", @@ -35,7 +35,7 @@ "chalk": "^5.0.0", "dotenv": "^10.0.0", "hardhat-docgen": "^1.2.0", - "inquirer": "^8.2.0", + "inquirer": "^8.2.0", "minimist": "^1.2.5", "solc": "^0.8.10", "typechain": "^6.0.5"