From 7bf7174c7a4c4d62ba45b93ca6a583d7d3164d65 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sun, 27 Feb 2022 02:14:41 +0530 Subject: [PATCH 01/16] wip: import connector --- .../connectors/aave/v3-import/events.sol | 13 + .../connectors/aave/v3-import/helpers.sol | 38 ++ .../connectors/aave/v3-import/interface.sol | 89 ++++ .../connectors/aave/v3-import/main.sol | 401 ++++++++++++++++++ 4 files changed, 541 insertions(+) create mode 100644 contracts/mainnet/connectors/aave/v3-import/events.sol create mode 100644 contracts/mainnet/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/mainnet/connectors/aave/v3-import/interface.sol create mode 100644 contracts/mainnet/connectors/aave/v3-import/main.sol diff --git a/contracts/mainnet/connectors/aave/v3-import/events.sol b/contracts/mainnet/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..2036cf81 --- /dev/null +++ b/contracts/mainnet/connectors/aave/v3-import/events.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveImport( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..19d464dd --- /dev/null +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,38 @@ +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"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AaveLendingPoolProviderInterface internal constant aaveProvider = + AaveLendingPoolProviderInterface( + 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 + ); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); + + address flashloanAddr = 0x619Ad2D02dBeE6ebA3CDbDA3F98430410e892882; + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , isCol) = aaveData.getUserReserveData(token, user); + } +} diff --git a/contracts/mainnet/connectors/aave/v3-import/interface.sol b/contracts/mainnet/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..e0775894 --- /dev/null +++ b/contracts/mainnet/connectors/aave/v3-import/interface.sol @@ -0,0 +1,89 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function deposit( + address _asset, + uint256 _amount, + address _onBehalfOf, + uint16 _referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + 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 AaveLendingPoolProviderInterface { + function getLendingPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} + +interface ATokenInterface { + function balanceOf(address _user) external view returns (uint256); +} diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..de125b4d --- /dev/null +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -0,0 +1,401 @@ +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[] tokens, + uint256[] 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.supplyAssets.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.totalBorrowAmtsFinalAmtsWithFee + ); + } else { + _BorrowStable( + inputData.borrowTokens.length, + aave, + Data._borrowTokens, + Data.stableBorrowFinalAmts + ); + _BorrowVariable( + inputData.borrowTokens.length, + aave, + Data._borrowTokens, + Data.variableBorrowFinalAmtsWithFee + ); + } + // 4. repay flashloan with the borrowed assets + _repay( + Data._borrowTokens, + Data.totalBorrowAmtsAmtsWithFee, + flashloanAddr + ); + } +} + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + data.convertStable = inputData.convertStable; + + bytes memory _callData = abi.encode(data); + + flashborrow(data._borrowTokens, data.totalBorrowAmts, 5, _calldata); + + _eventName = "LogAaveV2Import(address,bool,address[],address[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } + + function migrateAave(ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(msg.sender, inputData); + } +} + +contract ConnectV2AaveV3Import is AaveV3ImportResolver { + string public constant name = "Aave-v3-Import-v2"; +} From 6abaee5bf92afe931b279e2bb1a3f7edb3efc123 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sun, 27 Feb 2022 02:28:09 +0530 Subject: [PATCH 02/16] minor fix --- .../connectors/aave/v3-import/interface.sol | 23 +++++-- .../connectors/aave/v3-import/main.sol | 68 +++++++++---------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/contracts/mainnet/connectors/aave/v3-import/interface.sol b/contracts/mainnet/connectors/aave/v3-import/interface.sol index e0775894..7bef374b 100644 --- a/contracts/mainnet/connectors/aave/v3-import/interface.sol +++ b/contracts/mainnet/connectors/aave/v3-import/interface.sol @@ -47,6 +47,25 @@ interface IFlashLoan { ) external; } +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + interface AaveLendingPoolProviderInterface { function getLendingPool() external view returns (address); } @@ -83,7 +102,3 @@ interface AaveAddressProviderRegistryInterface { view returns (address[] memory); } - -interface ATokenInterface { - function balanceOf(address _user) external view returns (uint256); -} diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index de125b4d..b4dc4849 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -149,13 +149,13 @@ contract AaveResolver is Helpers, Events { } function _repay( - address[] tokens, - uint256[] amounts, + 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]); + TokenInterface(tokens[i]).transfer(recepient, amounts[i]); } } } @@ -236,7 +236,7 @@ contract AaveHelpers is AaveResolver { ImportInputData memory inputData, ImportData memory data ) internal view returns (ImportData memory) { - data.supplyAmts = new uint256[](inputData.supplyAssets.length); + data.supplyAmts = new uint256[](inputData.supplyTokens.length); data._supplyTokens = new address[](inputData.supplyTokens.length); data.aTokens = new ATokenInterface[](inputData.supplyTokens.length); @@ -281,65 +281,61 @@ contract AaveHelpers is AaveResolver { address initiator, bytes calldata params ) external returns (bool) { - ImportData memory Data; - (Data) = abi.decode(params, (ImportData)); + ImportData memory data; + (data) = abi.decode(params, (ImportData)); // 1. payback borrowed amount; AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); _PaybackStable( - Data._borrowTokens.length, + data._borrowTokens.length, aave, - Data._borrowTokens, - Data.stableBorrowAmts, - Data.userAccount + data._borrowTokens, + data.stableBorrowAmts, + data.userAccount ); _PaybackVariable( - Data._borrowTokens.length, + data._borrowTokens.length, aave, - Data._borrowTokens, - Data.variableBorrowAmts, - Data.userAccount + data._borrowTokens, + data.variableBorrowAmts, + data.userAccount ); // 2. transfer atokens to this address; _TransferAtokens( - Data._supplyTokens.length, + data._supplyTokens.length, aave, - Data.aTokens, - Data.supplyAmts, - Data._supplyTokens, - Data.userAccount + data.aTokens, + data.supplyAmts, + data._supplyTokens, + data.userAccount ); // 3. take debt including flashloan fee; - Data = _includeFee(Data, premiums); + data = _includeFee(data, premiums); - if (Data.convertStable) { + if (data.convertStable) { _BorrowVariable( - Data._borrowTokens.length, + data._borrowTokens.length, aave, - Data._borrowTokens, - Data.totalBorrowAmtsFinalAmtsWithFee + data._borrowTokens, + data.totalBorrowAmtsWithFee ); } else { _BorrowStable( - inputData.borrowTokens.length, + data._borrowTokens.length, aave, - Data._borrowTokens, - Data.stableBorrowFinalAmts + data._borrowTokens, + data.stableBorrowAmts ); _BorrowVariable( - inputData.borrowTokens.length, + data._borrowTokens.length, aave, - Data._borrowTokens, - Data.variableBorrowFinalAmtsWithFee + data._borrowTokens, + data.variableBorrowAmtsWithFee ); } // 4. repay flashloan with the borrowed assets - _repay( - Data._borrowTokens, - Data.totalBorrowAmtsAmtsWithFee, - flashloanAddr - ); + _repay(data._borrowTokens, data.totalBorrowAmtsWithFee, flashloanAddr); } } @@ -365,7 +361,7 @@ contract AaveV3ImportResolver is AaveHelpers { bytes memory _callData = abi.encode(data); - flashborrow(data._borrowTokens, data.totalBorrowAmts, 5, _calldata); + flashBorrow(data._borrowTokens, data.totalBorrowAmts, 5, _callData); _eventName = "LogAaveV2Import(address,bool,address[],address[],uint256[],uint256[],uint256[])"; _eventParam = abi.encode( From 62413849338780f7f471d95583df3d9ceb870b07 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 4 Mar 2022 17:44:36 +0530 Subject: [PATCH 03/16] 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" From 2a20443390349b66353e079fcfef78c450197216 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sun, 6 Mar 2022 18:31:15 +0530 Subject: [PATCH 04/16] added flashloan fee parameter in event --- contracts/mainnet/connectors/aave/v3-import/events.sol | 2 +- contracts/mainnet/connectors/aave/v3-import/helpers.sol | 4 ++-- contracts/mainnet/connectors/aave/v3-import/main.sol | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/mainnet/connectors/aave/v3-import/events.sol b/contracts/mainnet/connectors/aave/v3-import/events.sol index 2036cf81..26850be7 100644 --- a/contracts/mainnet/connectors/aave/v3-import/events.sol +++ b/contracts/mainnet/connectors/aave/v3-import/events.sol @@ -2,7 +2,7 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; contract Events { - event LogAaveImport( + event LogAaveV3Import( address indexed user, address[] ctokens, string[] supplyIds, diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol index 41073f7d..157559cd 100644 --- a/contracts/mainnet/connectors/aave/v3-import/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -7,7 +7,7 @@ import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterf import "./events.sol"; import "./interface.sol"; -abstract contract AaveResolver is DSMath, Basic { +abstract contract Helper is DSMath, Basic { /** * @dev Aave referal code */ @@ -57,7 +57,7 @@ abstract contract AaveResolver is DSMath, Basic { } } -contract AaveHelpers is AaveResolver { +contract AaveHelpers is Helper { function getBorrowAmount(address _token, address userAccount) internal view diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index 8c0de43f..bc5a4d38 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -74,12 +74,13 @@ contract AaveV3ImportResolver is AaveHelpers { ); } - _eventName = "LogAaveV2Import(address,bool,address[],address[],uint256[],uint256[],uint256[])"; + _eventName = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; _eventParam = abi.encode( userAccount, inputData.convertStable, inputData.supplyTokens, inputData.borrowTokens, + inputData.flashLoanFees, data.supplyAmts, data.stableBorrowAmts, data.variableBorrowAmts @@ -104,5 +105,5 @@ contract AaveV3ImportResolver is AaveHelpers { } contract ConnectV2AaveV3Import is AaveV3ImportResolver { - string public constant name = "Aave-v3-Import-v2"; + string public constant name = "Aave-v3-import-v1"; } From 45cf2a8f3708b1f5580e0551eaeb09a87b86af4e Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sun, 6 Mar 2022 18:31:34 +0530 Subject: [PATCH 05/16] added connector on avalanche --- .../connectors/aave/v3-import/events.sol | 13 + .../connectors/aave/v3-import/helpers.sol | 279 ++++++++++++++++++ .../connectors/aave/v3-import/interface.sol | 94 ++++++ .../connectors/aave/v3-import/main.sol | 109 +++++++ 4 files changed, 495 insertions(+) create mode 100644 contracts/avalanche/connectors/aave/v3-import/events.sol create mode 100644 contracts/avalanche/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/avalanche/connectors/aave/v3-import/interface.sol create mode 100644 contracts/avalanche/connectors/aave/v3-import/main.sol diff --git a/contracts/avalanche/connectors/aave/v3-import/events.sol b/contracts/avalanche/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..26850be7 --- /dev/null +++ b/contracts/avalanche/connectors/aave/v3-import/events.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveV3Import( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/avalanche/connectors/aave/v3-import/helpers.sol b/contracts/avalanche/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..272c1ee7 --- /dev/null +++ b/contracts/avalanche/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,279 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; + +abstract contract Helper is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AaveLendingPoolProviderInterface internal constant aaveProvider = + AaveLendingPoolProviderInterface( + 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this + ); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , 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 Helper { + 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] == avaxAddr + ? wavaxAddr + : 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] == avaxAddr + ? wavaxAddr + : 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/avalanche/connectors/aave/v3-import/interface.sol b/contracts/avalanche/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..26a9fcaa --- /dev/null +++ b/contracts/avalanche/connectors/aave/v3-import/interface.sol @@ -0,0 +1,94 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function deposit( + address _asset, + uint256 _amount, + address _onBehalfOf, + uint16 _referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + function swapBorrowRateMode(address _asset, uint256 _rateMode) external; +} + +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + +interface AaveLendingPoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..523adfa7 --- /dev/null +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -0,0 +1,109 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); + + // 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 = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + inputData.flashLoanFees, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } + + function migrateAave(ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(msg.sender, inputData); + } +} + +contract ConnectV2AaveV3ImportAvalanche is AaveV3ImportResolver { + string public constant name = "Aave-v3-import-v1"; +} From a666b90ebeb04b53c43e2811afe44088bd07e845 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sun, 6 Mar 2022 18:31:49 +0530 Subject: [PATCH 06/16] added connector on polygon --- .../connectors/aave/v3-import/events.sol | 13 + .../connectors/aave/v3-import/helpers.sol | 279 ++++++++++++++++++ .../connectors/aave/v3-import/interface.sol | 94 ++++++ .../connectors/aave/v3-import/main.sol | 109 +++++++ 4 files changed, 495 insertions(+) create mode 100644 contracts/polygon/connectors/aave/v3-import/events.sol create mode 100644 contracts/polygon/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/polygon/connectors/aave/v3-import/interface.sol create mode 100644 contracts/polygon/connectors/aave/v3-import/main.sol diff --git a/contracts/polygon/connectors/aave/v3-import/events.sol b/contracts/polygon/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..26850be7 --- /dev/null +++ b/contracts/polygon/connectors/aave/v3-import/events.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveV3Import( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/polygon/connectors/aave/v3-import/helpers.sol b/contracts/polygon/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..9729183f --- /dev/null +++ b/contracts/polygon/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,279 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; + +abstract contract Helper is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AaveLendingPoolProviderInterface internal constant aaveProvider = + AaveLendingPoolProviderInterface( + 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this + ); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , 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 Helper { + 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] == maticAddr + ? wmaticAddr + : 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] == maticAddr + ? wmaticAddr + : 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/polygon/connectors/aave/v3-import/interface.sol b/contracts/polygon/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..26a9fcaa --- /dev/null +++ b/contracts/polygon/connectors/aave/v3-import/interface.sol @@ -0,0 +1,94 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function deposit( + address _asset, + uint256 _amount, + address _onBehalfOf, + uint16 _referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + function swapBorrowRateMode(address _asset, uint256 _rateMode) external; +} + +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + +interface AaveLendingPoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..3cb1d1e4 --- /dev/null +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -0,0 +1,109 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); + + // 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 = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + inputData.flashLoanFees, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } + + function migrateAave(ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(msg.sender, inputData); + } +} + +contract ConnectV2AaveV3ImportPolygon is AaveV3ImportResolver { + string public constant name = "Aave-v3-import-v1"; +} From 5083d84d51315f46dfe87dcae09c48887acda57c Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Wed, 9 Mar 2022 21:52:14 +0530 Subject: [PATCH 07/16] removed migration func --- contracts/avalanche/connectors/aave/v3-import/main.sol | 8 -------- contracts/mainnet/connectors/aave/v3-import/main.sol | 8 -------- contracts/polygon/connectors/aave/v3-import/main.sol | 8 -------- 3 files changed, 24 deletions(-) diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol index 523adfa7..64e3ea8d 100644 --- a/contracts/avalanche/connectors/aave/v3-import/main.sol +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -94,14 +94,6 @@ contract AaveV3ImportResolver is AaveHelpers { { (_eventName, _eventParam) = _importAave(userAccount, inputData); } - - function migrateAave(ImportInputData memory inputData) - external - payable - returns (string memory _eventName, bytes memory _eventParam) - { - (_eventName, _eventParam) = _importAave(msg.sender, inputData); - } } contract ConnectV2AaveV3ImportAvalanche is AaveV3ImportResolver { diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index bc5a4d38..f920e361 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -94,14 +94,6 @@ contract AaveV3ImportResolver is AaveHelpers { { (_eventName, _eventParam) = _importAave(userAccount, inputData); } - - function migrateAave(ImportInputData memory inputData) - external - payable - returns (string memory _eventName, bytes memory _eventParam) - { - (_eventName, _eventParam) = _importAave(msg.sender, inputData); - } } contract ConnectV2AaveV3Import is AaveV3ImportResolver { diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol index 3cb1d1e4..cee64400 100644 --- a/contracts/polygon/connectors/aave/v3-import/main.sol +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -94,14 +94,6 @@ contract AaveV3ImportResolver is AaveHelpers { { (_eventName, _eventParam) = _importAave(userAccount, inputData); } - - function migrateAave(ImportInputData memory inputData) - external - payable - returns (string memory _eventName, bytes memory _eventParam) - { - (_eventName, _eventParam) = _importAave(msg.sender, inputData); - } } contract ConnectV2AaveV3ImportPolygon is AaveV3ImportResolver { From 0a13c8e5cf485579fe0e1b8345e67e5bd5ac8c9a Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Wed, 9 Mar 2022 21:56:51 +0530 Subject: [PATCH 08/16] added comments --- contracts/avalanche/connectors/aave/v3-import/main.sol | 6 ++++++ contracts/mainnet/connectors/aave/v3-import/main.sol | 6 ++++++ contracts/polygon/connectors/aave/v3-import/main.sol | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol index 64e3ea8d..561229cd 100644 --- a/contracts/avalanche/connectors/aave/v3-import/main.sol +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -87,6 +87,12 @@ contract AaveV3ImportResolver is AaveHelpers { ); } + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ function importAave(address userAccount, ImportInputData memory inputData) external payable diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index f920e361..134cde67 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -87,6 +87,12 @@ contract AaveV3ImportResolver is AaveHelpers { ); } + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ function importAave(address userAccount, ImportInputData memory inputData) external payable diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol index cee64400..7de9ab61 100644 --- a/contracts/polygon/connectors/aave/v3-import/main.sol +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -87,6 +87,12 @@ contract AaveV3ImportResolver is AaveHelpers { ); } + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ function importAave(address userAccount, ImportInputData memory inputData) external payable From b7bffb41a839355e460f3311d9b33199af59a24c Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Wed, 9 Mar 2022 22:02:57 +0530 Subject: [PATCH 09/16] added comments --- contracts/avalanche/connectors/aave/v3-import/main.sol | 5 ++++- contracts/mainnet/connectors/aave/v3-import/main.sol | 5 ++++- contracts/polygon/connectors/aave/v3-import/main.sol | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol index 561229cd..8d183d87 100644 --- a/contracts/avalanche/connectors/aave/v3-import/main.sol +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -1,6 +1,9 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; - +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; import { AaveInterface, ATokenInterface } from "./interface.sol"; import "./helpers.sol"; diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index 134cde67..244238e9 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -1,6 +1,9 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; - +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; import { AaveInterface, ATokenInterface } from "./interface.sol"; import "./helpers.sol"; diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol index 7de9ab61..a43102c5 100644 --- a/contracts/polygon/connectors/aave/v3-import/main.sol +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -1,5 +1,9 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; import { AaveInterface, ATokenInterface } from "./interface.sol"; From c04011e8baef2f52f7be96c6eb43a4a90d928f9a Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Thu, 10 Mar 2022 23:22:04 +0530 Subject: [PATCH 10/16] updated solidity version --- contracts/avalanche/connectors/aave/v3-import/events.sol | 2 +- contracts/avalanche/connectors/aave/v3-import/helpers.sol | 2 +- contracts/avalanche/connectors/aave/v3-import/interface.sol | 2 +- contracts/avalanche/connectors/aave/v3-import/main.sol | 2 +- contracts/mainnet/connectors/aave/v3-import/events.sol | 2 +- contracts/mainnet/connectors/aave/v3-import/helpers.sol | 2 +- contracts/mainnet/connectors/aave/v3-import/interface.sol | 2 +- contracts/mainnet/connectors/aave/v3-import/main.sol | 2 +- contracts/polygon/connectors/aave/v3-import/events.sol | 2 +- contracts/polygon/connectors/aave/v3-import/helpers.sol | 2 +- contracts/polygon/connectors/aave/v3-import/interface.sol | 2 +- contracts/polygon/connectors/aave/v3-import/main.sol | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/avalanche/connectors/aave/v3-import/events.sol b/contracts/avalanche/connectors/aave/v3-import/events.sol index 26850be7..2f45fcaa 100644 --- a/contracts/avalanche/connectors/aave/v3-import/events.sol +++ b/contracts/avalanche/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; contract Events { diff --git a/contracts/avalanche/connectors/aave/v3-import/helpers.sol b/contracts/avalanche/connectors/aave/v3-import/helpers.sol index 272c1ee7..9ae1c826 100644 --- a/contracts/avalanche/connectors/aave/v3-import/helpers.sol +++ b/contracts/avalanche/connectors/aave/v3-import/helpers.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; diff --git a/contracts/avalanche/connectors/aave/v3-import/interface.sol b/contracts/avalanche/connectors/aave/v3-import/interface.sol index 26a9fcaa..3a77a892 100644 --- a/contracts/avalanche/connectors/aave/v3-import/interface.sol +++ b/contracts/avalanche/connectors/aave/v3-import/interface.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; interface AaveInterface { function deposit( diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol index 8d183d87..cfc45ac2 100644 --- a/contracts/avalanche/connectors/aave/v3-import/main.sol +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . diff --git a/contracts/mainnet/connectors/aave/v3-import/events.sol b/contracts/mainnet/connectors/aave/v3-import/events.sol index 26850be7..2f45fcaa 100644 --- a/contracts/mainnet/connectors/aave/v3-import/events.sol +++ b/contracts/mainnet/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; contract Events { diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol index 157559cd..1337867f 100644 --- a/contracts/mainnet/connectors/aave/v3-import/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; diff --git a/contracts/mainnet/connectors/aave/v3-import/interface.sol b/contracts/mainnet/connectors/aave/v3-import/interface.sol index 26a9fcaa..3a77a892 100644 --- a/contracts/mainnet/connectors/aave/v3-import/interface.sol +++ b/contracts/mainnet/connectors/aave/v3-import/interface.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; interface AaveInterface { function deposit( diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index 244238e9..3a71d0a9 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . diff --git a/contracts/polygon/connectors/aave/v3-import/events.sol b/contracts/polygon/connectors/aave/v3-import/events.sol index 26850be7..2f45fcaa 100644 --- a/contracts/polygon/connectors/aave/v3-import/events.sol +++ b/contracts/polygon/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; contract Events { diff --git a/contracts/polygon/connectors/aave/v3-import/helpers.sol b/contracts/polygon/connectors/aave/v3-import/helpers.sol index 9729183f..d09fddd8 100644 --- a/contracts/polygon/connectors/aave/v3-import/helpers.sol +++ b/contracts/polygon/connectors/aave/v3-import/helpers.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; diff --git a/contracts/polygon/connectors/aave/v3-import/interface.sol b/contracts/polygon/connectors/aave/v3-import/interface.sol index 26a9fcaa..3a77a892 100644 --- a/contracts/polygon/connectors/aave/v3-import/interface.sol +++ b/contracts/polygon/connectors/aave/v3-import/interface.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; interface AaveInterface { function deposit( diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol index a43102c5..7a0303a0 100644 --- a/contracts/polygon/connectors/aave/v3-import/main.sol +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.6; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . From ca187d5fe55e8186b7123cb497225cdfdbdb24fb Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 11 Mar 2022 01:40:00 +0530 Subject: [PATCH 11/16] updated aave v3 addr, added flashloan fee in events, changed solidity version --- .../connectors/aave/v3-import/events.sol | 3 ++- .../connectors/aave/v3-import/helpers.sol | 15 ++++++--------- .../connectors/aave/v3-import/interface.sol | 6 +++--- .../avalanche/connectors/aave/v3-import/main.sol | 2 +- .../mainnet/connectors/aave/v3-import/events.sol | 3 ++- .../mainnet/connectors/aave/v3-import/helpers.sol | 12 +++++------- .../connectors/aave/v3-import/interface.sol | 14 +++++++------- .../mainnet/connectors/aave/v3-import/main.sol | 2 +- .../polygon/connectors/aave/v3-import/events.sol | 3 ++- .../polygon/connectors/aave/v3-import/helpers.sol | 12 +++++------- .../connectors/aave/v3-import/interface.sol | 14 +++++++------- .../polygon/connectors/aave/v3-import/main.sol | 2 +- 12 files changed, 42 insertions(+), 46 deletions(-) diff --git a/contracts/avalanche/connectors/aave/v3-import/events.sol b/contracts/avalanche/connectors/aave/v3-import/events.sol index 2f45fcaa..08013251 100644 --- a/contracts/avalanche/connectors/aave/v3-import/events.sol +++ b/contracts/avalanche/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; contract Events { @@ -7,6 +7,7 @@ contract Events { address[] ctokens, string[] supplyIds, string[] borrowIds, + uint256[] flashLoanFees, uint256[] supplyAmts, uint256[] borrowAmts ); diff --git a/contracts/avalanche/connectors/aave/v3-import/helpers.sol b/contracts/avalanche/connectors/aave/v3-import/helpers.sol index 9ae1c826..72586c51 100644 --- a/contracts/avalanche/connectors/aave/v3-import/helpers.sol +++ b/contracts/avalanche/connectors/aave/v3-import/helpers.sol @@ -1,9 +1,8 @@ -pragma solidity ^0.8.6; - +pragma solidity ^0.7.0; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; -import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; import "./events.sol"; import "./interface.sol"; @@ -14,18 +13,16 @@ abstract contract Helper is DSMath, Basic { uint16 internal constant referalCode = 3228; /** - * @dev Aave Lending Pool Provider + * @dev Aave Pool Provider */ - AaveLendingPoolProviderInterface internal constant aaveProvider = - AaveLendingPoolProviderInterface( - 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this - ); + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this + AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); function getIsColl(address token, address user) internal diff --git a/contracts/avalanche/connectors/aave/v3-import/interface.sol b/contracts/avalanche/connectors/aave/v3-import/interface.sol index 3a77a892..4cce4a80 100644 --- a/contracts/avalanche/connectors/aave/v3-import/interface.sol +++ b/contracts/avalanche/connectors/aave/v3-import/interface.sol @@ -1,7 +1,7 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; interface AaveInterface { - function deposit( + function supply( address _asset, uint256 _amount, address _onBehalfOf, @@ -56,7 +56,7 @@ interface ATokenInterface { function allowance(address, address) external returns (uint256); } -interface AaveLendingPoolProviderInterface { +interface AavePoolProviderInterface { function getPool() external view returns (address); } diff --git a/contracts/avalanche/connectors/aave/v3-import/main.sol b/contracts/avalanche/connectors/aave/v3-import/main.sol index cfc45ac2..8d183d87 100644 --- a/contracts/avalanche/connectors/aave/v3-import/main.sol +++ b/contracts/avalanche/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . diff --git a/contracts/mainnet/connectors/aave/v3-import/events.sol b/contracts/mainnet/connectors/aave/v3-import/events.sol index 2f45fcaa..08013251 100644 --- a/contracts/mainnet/connectors/aave/v3-import/events.sol +++ b/contracts/mainnet/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; contract Events { @@ -7,6 +7,7 @@ contract Events { address[] ctokens, string[] supplyIds, string[] borrowIds, + uint256[] flashLoanFees, uint256[] supplyAmts, uint256[] borrowAmts ); diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol index 1337867f..6c400105 100644 --- a/contracts/mainnet/connectors/aave/v3-import/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -1,9 +1,9 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; -import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; import "./events.sol"; import "./interface.sol"; @@ -16,16 +16,14 @@ abstract contract Helper is DSMath, Basic { /** * @dev Aave Lending Pool Provider */ - AaveLendingPoolProviderInterface internal constant aaveProvider = - AaveLendingPoolProviderInterface( - 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this - ); + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this + AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); function getIsColl(address token, address user) internal diff --git a/contracts/mainnet/connectors/aave/v3-import/interface.sol b/contracts/mainnet/connectors/aave/v3-import/interface.sol index 3a77a892..2085007b 100644 --- a/contracts/mainnet/connectors/aave/v3-import/interface.sol +++ b/contracts/mainnet/connectors/aave/v3-import/interface.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; interface AaveInterface { - function deposit( - address _asset, - uint256 _amount, - address _onBehalfOf, - uint16 _referralCode + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode ) external; function withdraw( @@ -56,7 +56,7 @@ interface ATokenInterface { function allowance(address, address) external returns (uint256); } -interface AaveLendingPoolProviderInterface { +interface AavePoolProviderInterface { function getPool() external view returns (address); } diff --git a/contracts/mainnet/connectors/aave/v3-import/main.sol b/contracts/mainnet/connectors/aave/v3-import/main.sol index 3a71d0a9..244238e9 100644 --- a/contracts/mainnet/connectors/aave/v3-import/main.sol +++ b/contracts/mainnet/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . diff --git a/contracts/polygon/connectors/aave/v3-import/events.sol b/contracts/polygon/connectors/aave/v3-import/events.sol index 2f45fcaa..08013251 100644 --- a/contracts/polygon/connectors/aave/v3-import/events.sol +++ b/contracts/polygon/connectors/aave/v3-import/events.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; contract Events { @@ -7,6 +7,7 @@ contract Events { address[] ctokens, string[] supplyIds, string[] borrowIds, + uint256[] flashLoanFees, uint256[] supplyAmts, uint256[] borrowAmts ); diff --git a/contracts/polygon/connectors/aave/v3-import/helpers.sol b/contracts/polygon/connectors/aave/v3-import/helpers.sol index d09fddd8..47437037 100644 --- a/contracts/polygon/connectors/aave/v3-import/helpers.sol +++ b/contracts/polygon/connectors/aave/v3-import/helpers.sol @@ -1,9 +1,9 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; import { DSMath } from "../../../common/math.sol"; import { Basic } from "../../../common/basic.sol"; import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; -import { AaveInterface, AaveLendingPoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; import "./events.sol"; import "./interface.sol"; @@ -16,16 +16,14 @@ abstract contract Helper is DSMath, Basic { /** * @dev Aave Lending Pool Provider */ - AaveLendingPoolProviderInterface internal constant aaveProvider = - AaveLendingPoolProviderInterface( - 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 // v2 address TODO: need to update this - ); + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); // TODO: need to update this + AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); function getIsColl(address token, address user) internal diff --git a/contracts/polygon/connectors/aave/v3-import/interface.sol b/contracts/polygon/connectors/aave/v3-import/interface.sol index 3a77a892..2085007b 100644 --- a/contracts/polygon/connectors/aave/v3-import/interface.sol +++ b/contracts/polygon/connectors/aave/v3-import/interface.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; interface AaveInterface { - function deposit( - address _asset, - uint256 _amount, - address _onBehalfOf, - uint16 _referralCode + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode ) external; function withdraw( @@ -56,7 +56,7 @@ interface ATokenInterface { function allowance(address, address) external returns (uint256); } -interface AaveLendingPoolProviderInterface { +interface AavePoolProviderInterface { function getPool() external view returns (address); } diff --git a/contracts/polygon/connectors/aave/v3-import/main.sol b/contracts/polygon/connectors/aave/v3-import/main.sol index 7a0303a0..a43102c5 100644 --- a/contracts/polygon/connectors/aave/v3-import/main.sol +++ b/contracts/polygon/connectors/aave/v3-import/main.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.6; +pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; /** * @title Aave v3 import connector . From 1133f10fbce3bc5b42842d3e7c26af8de8eca4ba Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 11 Mar 2022 01:52:31 +0530 Subject: [PATCH 12/16] minor fix --- .../avalanche/connectors/aave/v3-import/helpers.sol | 12 ++++++++++++ .../mainnet/connectors/aave/v3-import/helpers.sol | 9 +++++++++ .../polygon/connectors/aave/v3-import/helpers.sol | 9 +++++++++ 3 files changed, 30 insertions(+) diff --git a/contracts/avalanche/connectors/aave/v3-import/helpers.sol b/contracts/avalanche/connectors/aave/v3-import/helpers.sol index 72586c51..0668ab36 100644 --- a/contracts/avalanche/connectors/aave/v3-import/helpers.sol +++ b/contracts/avalanche/connectors/aave/v3-import/helpers.sol @@ -85,10 +85,19 @@ contract AaveHelpers is Helper { data.variableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.stableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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) { @@ -122,6 +131,9 @@ contract AaveHelpers is Helper { data.stableBorrowAmts[i], inputData.flashLoanFees[i] ); + data.variableBorrowAmtsWithFee[i] = data.variableBorrowAmts[ + i + ]; } data.totalBorrowAmts[i] = add( diff --git a/contracts/mainnet/connectors/aave/v3-import/helpers.sol b/contracts/mainnet/connectors/aave/v3-import/helpers.sol index 6c400105..591394b5 100644 --- a/contracts/mainnet/connectors/aave/v3-import/helpers.sol +++ b/contracts/mainnet/connectors/aave/v3-import/helpers.sol @@ -86,10 +86,19 @@ contract AaveHelpers is Helper { data.variableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.stableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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) { diff --git a/contracts/polygon/connectors/aave/v3-import/helpers.sol b/contracts/polygon/connectors/aave/v3-import/helpers.sol index 47437037..44fa5360 100644 --- a/contracts/polygon/connectors/aave/v3-import/helpers.sol +++ b/contracts/polygon/connectors/aave/v3-import/helpers.sol @@ -86,10 +86,19 @@ contract AaveHelpers is Helper { data.variableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.stableBorrowAmts = new uint256[]( inputData.borrowTokens.length ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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) { From 1eafc29fa231dbf51c0ec2aeca44bdbcb0385a16 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 11 Mar 2022 15:38:38 +0530 Subject: [PATCH 13/16] added import connector on arb --- .../connectors/aave/v3-import/events.sol | 14 + .../connectors/aave/v3-import/helpers.sol | 286 ++++++++++++++++++ .../connectors/aave/v3-import/interface.sol | 94 ++++++ .../connectors/aave/v3-import/main.sol | 110 +++++++ 4 files changed, 504 insertions(+) create mode 100644 contracts/arbitrum/connectors/aave/v3-import/events.sol create mode 100644 contracts/arbitrum/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/arbitrum/connectors/aave/v3-import/interface.sol create mode 100644 contracts/arbitrum/connectors/aave/v3-import/main.sol diff --git a/contracts/arbitrum/connectors/aave/v3-import/events.sol b/contracts/arbitrum/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..08013251 --- /dev/null +++ b/contracts/arbitrum/connectors/aave/v3-import/events.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveV3Import( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] flashLoanFees, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/arbitrum/connectors/aave/v3-import/helpers.sol b/contracts/arbitrum/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..a2949919 --- /dev/null +++ b/contracts/arbitrum/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,286 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; + +abstract contract Helper is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0x7B291364Ce799edd4CD471E5C023FF965347E1E1); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x224cD29570ED4Bfb2b55fF3eE27bEd28c58BBa86); + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , 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 Helper { + 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.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmts = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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/arbitrum/connectors/aave/v3-import/interface.sol b/contracts/arbitrum/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..2085007b --- /dev/null +++ b/contracts/arbitrum/connectors/aave/v3-import/interface.sol @@ -0,0 +1,94 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + function swapBorrowRateMode(address _asset, uint256 _rateMode) external; +} + +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + +interface AavePoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} diff --git a/contracts/arbitrum/connectors/aave/v3-import/main.sol b/contracts/arbitrum/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..55227773 --- /dev/null +++ b/contracts/arbitrum/connectors/aave/v3-import/main.sol @@ -0,0 +1,110 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); + + // 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 = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + inputData.flashLoanFees, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } +} + +contract ConnectV2AaveV3ImportArbitrum is AaveV3ImportResolver { + string public constant name = "Aave-v3-import-v1"; +} From 3ccca453a5387a7fe31019be7d0ca4c89c2c522d Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Fri, 11 Mar 2022 15:38:49 +0530 Subject: [PATCH 14/16] added import connector on opt --- .../connectors/aave/v3-import/events.sol | 14 + .../connectors/aave/v3-import/helpers.sol | 286 ++++++++++++++++++ .../connectors/aave/v3-import/interface.sol | 94 ++++++ .../connectors/aave/v3-import/main.sol | 110 +++++++ 4 files changed, 504 insertions(+) create mode 100644 contracts/optimism/connectors/aave/v3-import/events.sol create mode 100644 contracts/optimism/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/optimism/connectors/aave/v3-import/interface.sol create mode 100644 contracts/optimism/connectors/aave/v3-import/main.sol diff --git a/contracts/optimism/connectors/aave/v3-import/events.sol b/contracts/optimism/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..08013251 --- /dev/null +++ b/contracts/optimism/connectors/aave/v3-import/events.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveV3Import( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] flashLoanFees, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/optimism/connectors/aave/v3-import/helpers.sol b/contracts/optimism/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..4351c714 --- /dev/null +++ b/contracts/optimism/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,286 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; + +abstract contract Helper is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , 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 Helper { + 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.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmts = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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/optimism/connectors/aave/v3-import/interface.sol b/contracts/optimism/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..2085007b --- /dev/null +++ b/contracts/optimism/connectors/aave/v3-import/interface.sol @@ -0,0 +1,94 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + function swapBorrowRateMode(address _asset, uint256 _rateMode) external; +} + +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + +interface AavePoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} diff --git a/contracts/optimism/connectors/aave/v3-import/main.sol b/contracts/optimism/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..052fdcc6 --- /dev/null +++ b/contracts/optimism/connectors/aave/v3-import/main.sol @@ -0,0 +1,110 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); + + // 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 = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + inputData.flashLoanFees, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } +} + +contract ConnectV2AaveV3ImportOptimism is AaveV3ImportResolver { + string public constant name = "Aave-v3-import-v1"; +} From ad7c5f11c4c6ea2c953f7f6207368d350178f561 Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sat, 12 Mar 2022 14:00:41 +0530 Subject: [PATCH 15/16] updated aave v3 addresses --- contracts/arbitrum/connectors/aave/v3-import/helpers.sol | 4 ++-- contracts/avalanche/connectors/aave/v3-import/helpers.sol | 4 ++-- contracts/optimism/connectors/aave/v3-import/helpers.sol | 4 ++-- contracts/polygon/connectors/aave/v3-import/helpers.sol | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/arbitrum/connectors/aave/v3-import/helpers.sol b/contracts/arbitrum/connectors/aave/v3-import/helpers.sol index a2949919..41afc79e 100644 --- a/contracts/arbitrum/connectors/aave/v3-import/helpers.sol +++ b/contracts/arbitrum/connectors/aave/v3-import/helpers.sol @@ -17,13 +17,13 @@ abstract contract Helper is DSMath, Basic { * @dev Aave Lending Pool Provider */ AavePoolProviderInterface internal constant aaveProvider = - AavePoolProviderInterface(0x7B291364Ce799edd4CD471E5C023FF965347E1E1); + AavePoolProviderInterface(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x224cD29570ED4Bfb2b55fF3eE27bEd28c58BBa86); + AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); function getIsColl(address token, address user) internal diff --git a/contracts/avalanche/connectors/aave/v3-import/helpers.sol b/contracts/avalanche/connectors/aave/v3-import/helpers.sol index 0668ab36..357de5f4 100644 --- a/contracts/avalanche/connectors/aave/v3-import/helpers.sol +++ b/contracts/avalanche/connectors/aave/v3-import/helpers.sol @@ -16,13 +16,13 @@ abstract contract Helper is DSMath, Basic { * @dev Aave Pool Provider */ AavePoolProviderInterface internal constant aaveProvider = - AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); + AavePoolProviderInterface(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); + AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); function getIsColl(address token, address user) internal diff --git a/contracts/optimism/connectors/aave/v3-import/helpers.sol b/contracts/optimism/connectors/aave/v3-import/helpers.sol index 4351c714..41afc79e 100644 --- a/contracts/optimism/connectors/aave/v3-import/helpers.sol +++ b/contracts/optimism/connectors/aave/v3-import/helpers.sol @@ -17,13 +17,13 @@ abstract contract Helper is DSMath, Basic { * @dev Aave Lending Pool Provider */ AavePoolProviderInterface internal constant aaveProvider = - AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); + AavePoolProviderInterface(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); + AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); function getIsColl(address token, address user) internal diff --git a/contracts/polygon/connectors/aave/v3-import/helpers.sol b/contracts/polygon/connectors/aave/v3-import/helpers.sol index 44fa5360..eb054b6f 100644 --- a/contracts/polygon/connectors/aave/v3-import/helpers.sol +++ b/contracts/polygon/connectors/aave/v3-import/helpers.sol @@ -17,13 +17,13 @@ abstract contract Helper is DSMath, Basic { * @dev Aave Lending Pool Provider */ AavePoolProviderInterface internal constant aaveProvider = - AavePoolProviderInterface(0x7013523049CeC8b06F594edb8c5fb7F232c0Df7C); + AavePoolProviderInterface(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); /** * @dev Aave Protocol Data Provider */ AaveDataProviderInterface internal constant aaveData = - AaveDataProviderInterface(0x44C7324E9d84D6534DD6f292Cc08f1816e45Ff6e); + AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); function getIsColl(address token, address user) internal From 68e007e26fbfddbbc152b773f8f663899bc53e6a Mon Sep 17 00:00:00 2001 From: bhavik-m Date: Sat, 12 Mar 2022 22:24:50 +0530 Subject: [PATCH 16/16] added connector on fanto, --- contracts/fantom/common/basic.sol | 91 ++++++ contracts/fantom/common/interfaces.sol | 35 +++ contracts/fantom/common/math.sol | 54 ++++ contracts/fantom/common/stores.sol | 40 +++ .../connectors/aave/v3-import/events.sol | 14 + .../connectors/aave/v3-import/helpers.sol | 286 ++++++++++++++++++ .../connectors/aave/v3-import/interface.sol | 94 ++++++ .../fantom/connectors/aave/v3-import/main.sol | 111 +++++++ hardhat.config.ts | 66 ++-- 9 files changed, 756 insertions(+), 35 deletions(-) create mode 100644 contracts/fantom/common/basic.sol create mode 100644 contracts/fantom/common/interfaces.sol create mode 100644 contracts/fantom/common/math.sol create mode 100644 contracts/fantom/common/stores.sol create mode 100644 contracts/fantom/connectors/aave/v3-import/events.sol create mode 100644 contracts/fantom/connectors/aave/v3-import/helpers.sol create mode 100644 contracts/fantom/connectors/aave/v3-import/interface.sol create mode 100644 contracts/fantom/connectors/aave/v3-import/main.sol diff --git a/contracts/fantom/common/basic.sol b/contracts/fantom/common/basic.sol new file mode 100644 index 00000000..ba834cfd --- /dev/null +++ b/contracts/fantom/common/basic.sol @@ -0,0 +1,91 @@ +pragma solidity ^0.7.0; + +import { TokenInterface } from "./interfaces.sol"; +import { Stores } from "./stores.sol"; +import { DSMath } from "./math.sol"; + +abstract contract Basic is DSMath, Stores { + function convert18ToDec(uint256 _dec, uint256 _amt) + internal + pure + returns (uint256 amt) + { + amt = (_amt / 10**(18 - _dec)); + } + + function convertTo18(uint256 _dec, uint256 _amt) + internal + pure + returns (uint256 amt) + { + amt = mul(_amt, 10**(18 - _dec)); + } + + function getTokenBal(TokenInterface token) + internal + view + returns (uint256 _amt) + { + _amt = address(token) == ftmAddr + ? address(this).balance + : token.balanceOf(address(this)); + } + + function getTokensDec(TokenInterface buyAddr, TokenInterface sellAddr) + internal + view + returns (uint256 buyDec, uint256 sellDec) + { + buyDec = address(buyAddr) == ftmAddr ? 18 : buyAddr.decimals(); + sellDec = address(sellAddr) == ftmAddr ? 18 : sellAddr.decimals(); + } + + function encodeEvent(string memory eventName, bytes memory eventParam) + internal + pure + returns (bytes memory) + { + return abi.encode(eventName, eventParam); + } + + function approve( + TokenInterface token, + address spender, + uint256 amount + ) internal { + try token.approve(spender, amount) {} catch { + token.approve(spender, 0); + token.approve(spender, amount); + } + } + + function changeftmAddress(address buy, address sell) + internal + pure + returns (TokenInterface _buy, TokenInterface _sell) + { + _buy = buy == ftmAddr ? TokenInterface(wftmAddr) : TokenInterface(buy); + _sell = sell == ftmAddr + ? TokenInterface(wftmAddr) + : TokenInterface(sell); + } + + function convertFtmToWftm( + bool isFtm, + TokenInterface token, + uint256 amount + ) internal { + if (isFtm) token.deposit{ value: amount }(); + } + + function convertWftmToFtm( + bool isFtm, + TokenInterface token, + uint256 amount + ) internal { + if (isFtm) { + approve(token, address(token), amount); + token.withdraw(amount); + } + } +} diff --git a/contracts/fantom/common/interfaces.sol b/contracts/fantom/common/interfaces.sol new file mode 100644 index 00000000..ff92c278 --- /dev/null +++ b/contracts/fantom/common/interfaces.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.7.0; + +interface TokenInterface { + function approve(address, uint256) external; + + function transfer(address, uint256) external; + + function transferFrom( + address, + address, + uint256 + ) external; + + function deposit() external payable; + + function withdraw(uint256) external; + + function balanceOf(address) external view returns (uint256); + + function decimals() external view returns (uint256); +} + +interface MemoryInterface { + function getUint(uint256 id) external returns (uint256 num); + + function setUint(uint256 id, uint256 val) external; +} + +interface AccountInterface { + function enable(address) external; + + function disable(address) external; + + function isAuth(address) external view returns (bool); +} diff --git a/contracts/fantom/common/math.sol b/contracts/fantom/common/math.sol new file mode 100644 index 00000000..81f0bd38 --- /dev/null +++ b/contracts/fantom/common/math.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.7.0; + +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + +contract DSMath { + uint256 constant WAD = 10**18; + uint256 constant RAY = 10**27; + + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.add(x, y); + } + + function sub(uint256 x, uint256 y) + internal + pure + virtual + returns (uint256 z) + { + z = SafeMath.sub(x, y); + } + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.mul(x, y); + } + + function div(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.div(x, y); + } + + function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y; + } + + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y; + } + + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY; + } + + function toInt(uint256 x) internal pure returns (int256 y) { + y = int256(x); + require(y >= 0, "int-overflow"); + } + + function toRad(uint256 wad) internal pure returns (uint256 rad) { + rad = mul(wad, 10**27); + } +} diff --git a/contracts/fantom/common/stores.sol b/contracts/fantom/common/stores.sol new file mode 100644 index 00000000..0b261c7f --- /dev/null +++ b/contracts/fantom/common/stores.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.7.0; + +import { MemoryInterface } from "./interfaces.sol"; + +abstract contract Stores { + /** + * @dev Return FTM address + */ + address internal constant ftmAddr = + 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + /** + * @dev Return Wrapped FTM address + */ + address internal constant wftmAddr = + 0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83; + + /** + * @dev Return memory variable address + */ + MemoryInterface internal constant instaMemory = + MemoryInterface(0x56439117379A53bE3CC2C55217251e2481B7a1C8); + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint256 getId, uint256 val) + internal + returns (uint256 returnVal) + { + returnVal = getId == 0 ? val : instaMemory.getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint256 setId, uint256 val) internal virtual { + if (setId != 0) instaMemory.setUint(setId, val); + } +} diff --git a/contracts/fantom/connectors/aave/v3-import/events.sol b/contracts/fantom/connectors/aave/v3-import/events.sol new file mode 100644 index 00000000..08013251 --- /dev/null +++ b/contracts/fantom/connectors/aave/v3-import/events.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogAaveV3Import( + address indexed user, + address[] ctokens, + string[] supplyIds, + string[] borrowIds, + uint256[] flashLoanFees, + uint256[] supplyAmts, + uint256[] borrowAmts + ); +} diff --git a/contracts/fantom/connectors/aave/v3-import/helpers.sol b/contracts/fantom/connectors/aave/v3-import/helpers.sol new file mode 100644 index 00000000..3928644f --- /dev/null +++ b/contracts/fantom/connectors/aave/v3-import/helpers.sol @@ -0,0 +1,286 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol"; +import "./events.sol"; +import "./interface.sol"; + +abstract contract Helper is DSMath, Basic { + /** + * @dev Aave referal code + */ + uint16 internal constant referalCode = 3228; + + /** + * @dev Aave Lending Pool Provider + */ + AavePoolProviderInterface internal constant aaveProvider = + AavePoolProviderInterface(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); + + /** + * @dev Aave Protocol Data Provider + */ + AaveDataProviderInterface internal constant aaveData = + AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); + + function getIsColl(address token, address user) + internal + view + returns (bool isCol) + { + (, , , , , , , , 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 Helper { + 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.variableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmts = new uint256[]( + inputData.borrowTokens.length + ); + data.stableBorrowAmtsWithFee = new uint256[]( + inputData.borrowTokens.length + ); + data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length); + data.totalBorrowAmtsWithFee = 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] == ftmAddr + ? wftmAddr + : 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] == ftmAddr + ? wftmAddr + : 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/fantom/connectors/aave/v3-import/interface.sol b/contracts/fantom/connectors/aave/v3-import/interface.sol new file mode 100644 index 00000000..2085007b --- /dev/null +++ b/contracts/fantom/connectors/aave/v3-import/interface.sol @@ -0,0 +1,94 @@ +pragma solidity ^0.7.0; + +interface AaveInterface { + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; + + function withdraw( + address _asset, + uint256 _amount, + address _to + ) external; + + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + + function repay( + address _asset, + uint256 _amount, + uint256 _rateMode, + address _onBehalfOf + ) external; + + function setUserUseReserveAsCollateral( + address _asset, + bool _useAsCollateral + ) external; + + function swapBorrowRateMode(address _asset, uint256 _rateMode) external; +} + +interface ATokenInterface { + function scaledBalanceOf(address _user) external view returns (uint256); + + function isTransferAllowed(address _user, uint256 _amount) + external + view + returns (bool); + + function balanceOf(address _user) external view returns (uint256); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); + + function allowance(address, address) external returns (uint256); +} + +interface AavePoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses(address _asset) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData(address _asset, address _user) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); +} + +interface AaveAddressProviderRegistryInterface { + function getAddressesProvidersList() + external + view + returns (address[] memory); +} diff --git a/contracts/fantom/connectors/aave/v3-import/main.sol b/contracts/fantom/connectors/aave/v3-import/main.sol new file mode 100644 index 00000000..112845b6 --- /dev/null +++ b/contracts/fantom/connectors/aave/v3-import/main.sol @@ -0,0 +1,111 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; +/** + * @title Aave v3 import connector . + * @dev Import EOA's aave V3 position to DSA's aave v3 position + */ + +import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol"; +import { AaveInterface, ATokenInterface } from "./interface.sol"; +import "./helpers.sol"; +import "./events.sol"; + +contract AaveV3ImportResolver is AaveHelpers { + function _importAave(address userAccount, ImportInputData memory inputData) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + require( + AccountInterface(address(this)).isAuth(userAccount), + "user-account-not-auth" + ); + + require(inputData.supplyTokens.length > 0, "0-length-not-allowed"); + + ImportData memory data; + + AaveInterface aave = AaveInterface(aaveProvider.getPool()); + + data = getBorrowAmounts(userAccount, aave, inputData, data); + data = getSupplyAmounts(userAccount, inputData, data); + + // payback borrowed amount; + _PaybackStable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.stableBorrowAmts, + userAccount + ); + _PaybackVariable( + data._borrowTokens.length, + aave, + data._borrowTokens, + data.variableBorrowAmts, + userAccount + ); + + // 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 = "LogAaveV3Import(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[])"; + _eventParam = abi.encode( + userAccount, + inputData.convertStable, + inputData.supplyTokens, + inputData.borrowTokens, + inputData.flashLoanFees, + data.supplyAmts, + data.stableBorrowAmts, + data.variableBorrowAmts + ); + } + + /** + * @dev Import aave V3 position . + * @notice Import EOA's aave V3 position to DSA's aave v3 position + * @param userAccount The address of the EOA from which aave position will be imported + * @param inputData The struct containing all the neccessary input data + */ + function importAave(address userAccount, ImportInputData memory inputData) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _importAave(userAccount, inputData); + } +} + +contract ConnectV2AaveV3ImportFantom is AaveV3ImportResolver { + string public constant name = "Aave-v3-import-v1"; +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 1b5b30a4..be42f40d 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -36,36 +36,31 @@ const PRIVATE_KEY = process.env.PRIVATE_KEY; const ETHERSCAN_API = process.env.ETHERSCAN_API_KEY; const POLYGONSCAN_API = process.env.POLYGON_API_KEY; const ARBISCAN_API = process.env.ARBISCAN_API_KEY; -const OPTIMISM_API = process.env.OPTIMISM_API_KEY; const SNOWTRACE_API = process.env.SNOWTRACE_API_KEY; -const mnemonic = - process.env.MNEMONIC ?? - "test test test test test test test test test test test junk"; +const FANTOMSCAN_API = process.env.FANTOM_API_KEY; +const mnemonic = process.env.MNEMONIC ?? "test test test test test test test test test test test junk"; const networkGasPriceConfig: Record = { - "mainnet": "160", - "polygon": "50", - "avalanche": "50", - "arbitrum": "2" -} + mainnet: "160", + polygon: "50", + avalanche: "50", + arbitrum: "2" +}; function createConfig(network: string) { return { url: getNetworkUrl(network), accounts: !!PRIVATE_KEY ? [`0x${PRIVATE_KEY}`] : { mnemonic }, - gasPrice: 1000000, // 0.0001 GWEI + gasPrice: 220000000000 // 0.0001 GWEI }; } function getNetworkUrl(networkType: string) { - if (networkType === "avalanche") - return "https://api.avax.network/ext/bc/C/rpc"; - else if (networkType === "polygon") - return `https://polygon-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; - else if (networkType === "arbitrum") - return `https://arb-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; - else if (networkType === "optimism") - return `https://opt-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; + if (networkType === "avalanche") return "https://api.avax.network/ext/bc/C/rpc"; + else if (networkType === "polygon") return `https://polygon-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; + else if (networkType === "arbitrum") return `https://arb-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; + else if (networkType === "optimism") return `https://opt-mainnet.g.alchemy.com/v2/${alchemyApiKey}`; + else if (networkType === "fantom") return `https://rpc.ftm.tools/`; else return `https://eth-mainnet.alchemyapi.io/v2/${alchemyApiKey}`; } @@ -73,7 +68,7 @@ function getScanApiKey(networkType: string) { if (networkType === "avalanche") return SNOWTRACE_API; else if (networkType === "polygon") return POLYGONSCAN_API; else if (networkType === "arbitrum") return ARBISCAN_API; - else if (networkType === "optimism") return OPTIMISM_API; + else if (networkType === "fantom") return FANTOMSCAN_API; else return ETHERSCAN_API; } @@ -88,53 +83,54 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 200, - }, - }, + runs: 200 + } + } }, { - version: "0.6.0", + version: "0.6.0" }, { - version: "0.6.2", + version: "0.6.2" }, { - version: "0.6.5", - }, - ], + version: "0.6.5" + } + ] }, networks: { hardhat: { accounts: { - mnemonic, + mnemonic }, chainId: chainIds.hardhat, forking: { - url: String(getNetworkUrl(String(process.env.networkType))), - }, + url: String(getNetworkUrl(String(process.env.networkType))) + } }, mainnet: createConfig("mainnet"), polygon: createConfig("polygon"), avalanche: createConfig("avalanche"), arbitrum: createConfig("arbitrum"), optimism: createConfig("optimism"), + fantom: createConfig("optimism") }, paths: { artifacts: "./artifacts", cache: "./cache", sources: "./contracts", - tests: "./test", + tests: "./test" }, etherscan: { - apiKey: getScanApiKey(String(process.env.networkType)), + apiKey: getScanApiKey(String(process.env.networkType)) }, typechain: { outDir: "typechain", - target: "ethers-v5", + target: "ethers-v5" }, mocha: { - timeout: 10000 * 1000, // 10,000 seconds - }, + timeout: 10000 * 1000 // 10,000 seconds + } // tenderly: { // project: process.env.TENDERLY_PROJECT, // username: process.env.TENDERLY_USERNAME,