From a0ef584bd58e4c4fb9d91e0a50e28504297dd609 Mon Sep 17 00:00:00 2001
From: Shriya Tyagi <shriya243@gmail.com>
Date: Sat, 26 Aug 2023 04:35:21 +0530
Subject: [PATCH] feat: add aave v3 contracts

---
 .../aave/aave-v3-rewards/events.sol           |  13 +
 .../aave/aave-v3-rewards/helpers.sol          |  14 +
 .../aave/aave-v3-rewards/interface.sol        |  15 +
 .../connectors/aave/aave-v3-rewards/main.sol  |  78 +++
 .../base/connectors/aave/v3-import/events.sol |  25 +
 .../connectors/aave/v3-import/helpers.sol     | 315 +++++++++++
 .../connectors/aave/v3-import/interface.sol   |  95 ++++
 .../base/connectors/aave/v3-import/main.sol   | 209 ++++++++
 contracts/base/connectors/aave/v3/events.sol  |  64 +++
 contracts/base/connectors/aave/v3/helpers.sol |  99 ++++
 .../base/connectors/aave/v3/interface.sol     |  96 ++++
 contracts/base/connectors/aave/v3/main.sol    | 494 ++++++++++++++++++
 12 files changed, 1517 insertions(+)
 create mode 100644 contracts/base/connectors/aave/aave-v3-rewards/events.sol
 create mode 100644 contracts/base/connectors/aave/aave-v3-rewards/helpers.sol
 create mode 100644 contracts/base/connectors/aave/aave-v3-rewards/interface.sol
 create mode 100644 contracts/base/connectors/aave/aave-v3-rewards/main.sol
 create mode 100644 contracts/base/connectors/aave/v3-import/events.sol
 create mode 100644 contracts/base/connectors/aave/v3-import/helpers.sol
 create mode 100644 contracts/base/connectors/aave/v3-import/interface.sol
 create mode 100644 contracts/base/connectors/aave/v3-import/main.sol
 create mode 100644 contracts/base/connectors/aave/v3/events.sol
 create mode 100644 contracts/base/connectors/aave/v3/helpers.sol
 create mode 100644 contracts/base/connectors/aave/v3/interface.sol
 create mode 100644 contracts/base/connectors/aave/v3/main.sol

diff --git a/contracts/base/connectors/aave/aave-v3-rewards/events.sol b/contracts/base/connectors/aave/aave-v3-rewards/events.sol
new file mode 100644
index 00000000..683f3049
--- /dev/null
+++ b/contracts/base/connectors/aave/aave-v3-rewards/events.sol
@@ -0,0 +1,13 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+contract Events {
+	event LogClaimed(
+		address[] assets,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	);
+
+	event LogAllClaimed(address[] assets, address[] rewards, uint256[] amts);
+}
diff --git a/contracts/base/connectors/aave/aave-v3-rewards/helpers.sol b/contracts/base/connectors/aave/aave-v3-rewards/helpers.sol
new file mode 100644
index 00000000..db50b3bf
--- /dev/null
+++ b/contracts/base/connectors/aave/aave-v3-rewards/helpers.sol
@@ -0,0 +1,14 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+import { DSMath } from "../../../common/math.sol";
+import { Basic } from "../../../common/basic.sol";
+import { AaveIncentivesInterface } from "./interface.sol";
+
+abstract contract Helpers is DSMath, Basic {
+	/**
+	 * @dev Aave v3 Incentives
+	 */
+	AaveIncentivesInterface internal constant incentives =
+		AaveIncentivesInterface(0xf9cc4F0D883F1a1eb2c253bdb46c254Ca51E1F44);
+}
diff --git a/contracts/base/connectors/aave/aave-v3-rewards/interface.sol b/contracts/base/connectors/aave/aave-v3-rewards/interface.sol
new file mode 100644
index 00000000..f2ab4704
--- /dev/null
+++ b/contracts/base/connectors/aave/aave-v3-rewards/interface.sol
@@ -0,0 +1,15 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+interface AaveIncentivesInterface {
+	function claimRewards(
+		address[] calldata assets,
+		uint256 amount,
+		address to,
+		address reward
+	) external returns (uint256);
+
+	function claimAllRewards(address[] calldata assets, address to)
+		external
+		returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
+}
diff --git a/contracts/base/connectors/aave/aave-v3-rewards/main.sol b/contracts/base/connectors/aave/aave-v3-rewards/main.sol
new file mode 100644
index 00000000..5a6263b5
--- /dev/null
+++ b/contracts/base/connectors/aave/aave-v3-rewards/main.sol
@@ -0,0 +1,78 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+/**
+ * @title Aave v3 Rewards.
+ * @dev Claim Aave v3 rewards.
+ */
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+import { Stores } from "../../../common/stores.sol";
+import { Helpers } from "./helpers.sol";
+import { Events } from "./events.sol";
+
+abstract contract IncentivesResolver is Helpers, Events {
+	/**
+	 * @dev Claim Pending Rewards.
+	 * @notice Claim Pending Rewards from Aave v3 incentives contract.
+	 * @param assets The list of assets supplied and borrowed.
+	 * @param amt The amount of reward to claim. (uint(-1) for max)
+	 * @param reward The address of reward token to claim.
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of rewards claimed.
+	 */
+	function claim(
+		address[] calldata assets,
+		uint256 amt,
+		address reward,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		require(assets.length > 0, "invalid-assets");
+
+		_amt = incentives.claimRewards(assets, _amt, address(this), reward);
+
+		TokenInterface weth = TokenInterface(wethAddr);
+		uint256 wethAmount = weth.balanceOf(address(this));
+		convertWethToEth(wethAmount > 0, weth, wethAmount);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogClaimed(address[],uint256,uint256,uint256)";
+		_eventParam = abi.encode(assets, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Claim All Pending Rewards.
+	 * @notice Claim All Pending Rewards from Aave v3 incentives contract.
+	 * @param assets The list of assets supplied and borrowed.
+	 */
+	function claimAll(address[] calldata assets)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		require(assets.length > 0, "invalid-assets");
+		uint256[] memory _amts = new uint256[](assets.length);
+		address[] memory _rewards = new address[](assets.length);
+
+		(_rewards, _amts) = incentives.claimAllRewards(assets, address(this));
+
+		TokenInterface weth = TokenInterface(wethAddr);
+		uint256 wethAmount = weth.balanceOf(address(this));
+		convertWethToEth(wethAmount > 0, weth, wethAmount);
+
+		_eventName = "LogAllClaimed(address[],address[],uint256[])";
+		_eventParam = abi.encode(assets, _rewards, _amts);
+	}
+}
+
+contract ConnectV3AaveIncentivesBase is IncentivesResolver {
+	string public constant name = "Aave-V3-Incentives-v1";
+}
diff --git a/contracts/base/connectors/aave/v3-import/events.sol b/contracts/base/connectors/aave/v3-import/events.sol
new file mode 100644
index 00000000..c9aaeebb
--- /dev/null
+++ b/contracts/base/connectors/aave/v3-import/events.sol
@@ -0,0 +1,25 @@
+//SPDX-License-Identifier: MIT
+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
+	);
+	event LogAaveV3ImportWithCollateral(
+		address indexed user,
+		address[] atokens,
+		string[] supplyIds,
+		string[] borrowIds,
+		uint256[] flashLoanFees,
+		uint256[] supplyAmts,
+		uint256[] borrowAmts,
+		bool[] enableCollateral
+	);
+}
diff --git a/contracts/base/connectors/aave/v3-import/helpers.sol b/contracts/base/connectors/aave/v3-import/helpers.sol
new file mode 100644
index 00000000..e9d3600f
--- /dev/null
+++ b/contracts/base/connectors/aave/v3-import/helpers.sol
@@ -0,0 +1,315 @@
+//SPDX-License-Identifier: MIT
+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(0xe20fCBdBfFC4Dd138cE8b2E6FBb6CB49777ad64D);
+
+	/**
+	 * @dev Aave Protocol Data Provider
+	 */
+	AaveDataProviderInterface internal constant aaveData =
+		AaveDataProviderInterface(0x2d8A3C5677189723C4cB8873CfC9C8976FDF38Ac);
+
+	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 _TransferAtokensWithCollateral(
+		uint256 _length,
+		AaveInterface aave,
+		ATokenInterface[] memory atokenContracts,
+		uint256[] memory amts,
+		address[] memory tokens,
+		bool[] memory colEnable,
+		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], colEnable[i]);
+				}
+			}
+		}
+	}
+
+	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/base/connectors/aave/v3-import/interface.sol b/contracts/base/connectors/aave/v3-import/interface.sol
new file mode 100644
index 00000000..384e7369
--- /dev/null
+++ b/contracts/base/connectors/aave/v3-import/interface.sol
@@ -0,0 +1,95 @@
+//SPDX-License-Identifier: MIT
+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/base/connectors/aave/v3-import/main.sol b/contracts/base/connectors/aave/v3-import/main.sol
new file mode 100644
index 00000000..66fea0e3
--- /dev/null
+++ b/contracts/base/connectors/aave/v3-import/main.sol
@@ -0,0 +1,209 @@
+//SPDX-License-Identifier: MIT
+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
+		);
+	}
+
+	function _importAaveWithCollateral(address userAccount, ImportInputData memory inputData, bool[] memory enableCollateral)
+		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");
+		require(enableCollateral.length == inputData.supplyTokens.length, "lengths-not-same");
+
+		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;
+		_TransferAtokensWithCollateral(
+			data._supplyTokens.length,
+			aave,
+			data.aTokens,
+			data.supplyAmts,
+			data._supplyTokens,
+			enableCollateral,
+			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 = "LogAaveV3ImportWithCollateral(address,bool,address[],address[],uint256[],uint256[],uint256[],uint256[],bool[])";
+		_eventParam = abi.encode(
+			userAccount,
+			inputData.convertStable,
+			inputData.supplyTokens,
+			inputData.borrowTokens,
+			inputData.flashLoanFees,
+			data.supplyAmts,
+			data.stableBorrowAmts,
+			data.variableBorrowAmts,
+			enableCollateral
+		);
+	}
+
+	/**
+	 * @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);
+	}
+
+	/**
+	 * @dev Import aave V3 position (with collateral).
+	 * @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
+	 * @param enableCollateral The boolean array to enable selected collaterals in the imported position
+	 */
+	function importAaveWithCollateral(address userAccount, ImportInputData memory inputData, bool[] memory enableCollateral)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		(_eventName, _eventParam) = _importAaveWithCollateral(userAccount, inputData, enableCollateral);
+	}
+}
+
+contract ConnectV2AaveV3ImportBase is AaveV3ImportResolver {
+	string public constant name = "Aave-v3-import-v1.1";
+}
diff --git a/contracts/base/connectors/aave/v3/events.sol b/contracts/base/connectors/aave/v3/events.sol
new file mode 100644
index 00000000..e60aaa12
--- /dev/null
+++ b/contracts/base/connectors/aave/v3/events.sol
@@ -0,0 +1,64 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+contract Events {
+	event LogDeposit(
+		address indexed token,
+		uint256 tokenAmt,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogWithdraw(
+		address indexed token,
+		uint256 tokenAmt,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogBorrow(
+		address indexed token,
+		uint256 tokenAmt,
+		uint256 indexed rateMode,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogPayback(
+		address indexed token,
+		uint256 tokenAmt,
+		uint256 indexed rateMode,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogEnableCollateral(address[] tokens);
+	event LogSwapRateMode(address indexed token, uint256 rateMode);
+	event LogSetUserEMode(uint8 categoryId);
+	event LogDelegateBorrow(
+		address token,
+		uint256 amount,
+		uint256 rateMode,
+		address delegateTo,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogDepositWithoutCollateral(
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogBorrowOnBehalfOf(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		address onBehalfOf,
+		uint256 getId,
+		uint256 setId
+	);
+	event LogPaybackOnBehalfOf(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		address onBehalfOf,
+		uint256 getId,
+		uint256 setId
+	);
+}
diff --git a/contracts/base/connectors/aave/v3/helpers.sol b/contracts/base/connectors/aave/v3/helpers.sol
new file mode 100644
index 00000000..68e9a472
--- /dev/null
+++ b/contracts/base/connectors/aave/v3/helpers.sol
@@ -0,0 +1,99 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+import { DSMath } from "../../../common/math.sol";
+import { Basic } from "../../../common/basic.sol";
+import { AavePoolProviderInterface, AaveDataProviderInterface } from "./interface.sol";
+
+abstract contract Helpers is DSMath, Basic {
+	/**
+	 * @dev Aave Pool Provider
+	 */
+	AavePoolProviderInterface internal constant aaveProvider =
+		AavePoolProviderInterface(0xe20fCBdBfFC4Dd138cE8b2E6FBb6CB49777ad64D);
+
+	/**
+	 * @dev Aave Pool Data Provider
+	 */
+	AaveDataProviderInterface internal constant aaveData =
+		AaveDataProviderInterface(0x2d8A3C5677189723C4cB8873CfC9C8976FDF38Ac);
+
+	/**
+	 * @dev Aave Referral Code
+	 */
+	uint16 internal constant referralCode = 3228;
+
+	/**
+	 * @dev Checks if collateral is enabled for an asset
+	 * @param token token address of the asset.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 */
+
+	function getIsColl(address token) internal view returns (bool isCol) {
+		(, , , , , , , , isCol) = aaveData.getUserReserveData(
+			token,
+			address(this)
+		);
+	}
+
+	/**
+	 * @dev Get total debt balance & fee for an asset
+	 * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param rateMode Borrow rate mode (Stable = 1, Variable = 2)
+	 */
+	function getPaybackBalance(address token, uint256 rateMode)
+		internal
+		view
+		returns (uint256)
+	{
+		(, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData
+			.getUserReserveData(token, address(this));
+		return rateMode == 1 ? stableDebt : variableDebt;
+	}
+
+	/**
+	 * @dev Get OnBehalfOf user's total debt balance & fee for an asset
+	 * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param rateMode Borrow rate mode (Stable = 1, Variable = 2)
+	 */
+	function getOnBehalfOfPaybackBalance(address token, uint256 rateMode, address onBehalfOf)
+		internal
+		view
+		returns (uint256)
+	{
+		(, uint256 stableDebt, uint256 variableDebt, , , , , , ) = aaveData
+			.getUserReserveData(token, onBehalfOf);
+		return rateMode == 1 ? stableDebt : variableDebt;
+	}
+
+	/**
+	 * @dev Get total collateral balance for an asset
+	 * @param token token address of the collateral.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 */
+	function getCollateralBalance(address token)
+		internal
+		view
+		returns (uint256 bal)
+	{
+		(bal, , , , , , , , ) = aaveData.getUserReserveData(
+			token,
+			address(this)
+		);
+	}
+
+	/**
+	 * @dev Get debt token address for an asset
+	 * @param token token address of the asset
+	 * @param rateMode Debt type: stable-1, variable-2
+	 */
+	function getDTokenAddr(address token, uint256 rateMode)
+		internal
+		view
+		returns(address dToken)
+	{
+		if (rateMode == 1) {
+			(, dToken, ) = aaveData.getReserveTokensAddresses(token);
+		} else {
+			(, , dToken) = aaveData.getReserveTokensAddresses(token);
+		}
+	}
+}
diff --git a/contracts/base/connectors/aave/v3/interface.sol b/contracts/base/connectors/aave/v3/interface.sol
new file mode 100644
index 00000000..6de08261
--- /dev/null
+++ b/contracts/base/connectors/aave/v3/interface.sol
@@ -0,0 +1,96 @@
+//SPDX-License-Identifier: MIT
+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 returns (uint256);
+
+	function borrow(
+		address asset,
+		uint256 amount,
+		uint256 interestRateMode,
+		uint16 referralCode,
+		address onBehalfOf
+	) external;
+
+	function repay(
+		address asset,
+		uint256 amount,
+		uint256 interestRateMode,
+		address onBehalfOf
+	) external returns (uint256);
+
+	function repayWithATokens(
+		address asset,
+		uint256 amount,
+		uint256 interestRateMode
+	) external returns (uint256);
+
+	function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
+		external;
+
+	function swapBorrowRateMode(address asset, uint256 interestRateMode)
+		external;
+
+	function setUserEMode(uint8 categoryId) external;
+}
+
+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
+		);
+
+	function getReserveEModeCategory(address asset)
+		external
+		view
+		returns (uint256);
+}
+
+interface AaveAddressProviderRegistryInterface {
+	function getAddressesProvidersList()
+		external
+		view
+		returns (address[] memory);
+}
+
+interface ATokenInterface {
+	function balanceOf(address _user) external view returns (uint256);
+}
+
+interface DTokenInterface {
+	function approveDelegation(address delegatee, uint256 amount) external;
+}
diff --git a/contracts/base/connectors/aave/v3/main.sol b/contracts/base/connectors/aave/v3/main.sol
new file mode 100644
index 00000000..7c3aa530
--- /dev/null
+++ b/contracts/base/connectors/aave/v3/main.sol
@@ -0,0 +1,494 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+/**
+ * @title Aave v3.
+ * @dev Lending & Borrowing.
+ */
+
+import { TokenInterface } from "../../../common/interfaces.sol";
+import { Stores } from "../../../common/stores.sol";
+import { Helpers } from "./helpers.sol";
+import { Events } from "./events.sol";
+import { AaveInterface, DTokenInterface } from "./interface.sol";
+
+abstract contract AaveResolver is Events, Helpers {
+	/**
+	 * @dev Deposit ETH/ERC20_Token.
+	 * @notice Deposit a token to Aave v3 for lending / collaterization.
+	 * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens deposited.
+	 */
+	function deposit(
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		if (isEth) {
+			_amt = _amt == uint256(-1) ? address(this).balance : _amt;
+			convertEthToWeth(isEth, tokenContract, _amt);
+		} else {
+			_amt = _amt == uint256(-1)
+				? tokenContract.balanceOf(address(this))
+				: _amt;
+		}
+
+		approve(tokenContract, address(aave), _amt);
+
+		aave.supply(_token, _amt, address(this), referralCode);
+
+		if (!getIsColl(_token)) {
+			aave.setUserUseReserveAsCollateral(_token, true);
+		}
+
+		setUint(setId, _amt);
+
+		_eventName = "LogDeposit(address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Deposit ETH/ERC20_Token without collateral
+	 * @notice Deposit a token to Aave v3 without enabling it as collateral.
+	 * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens deposited.
+	 */
+	function depositWithoutCollateral(
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		if (isEth) {
+			_amt = _amt == uint256(-1) ? address(this).balance : _amt;
+			convertEthToWeth(isEth, tokenContract, _amt);
+		} else {
+			_amt = _amt == uint256(-1)
+				? tokenContract.balanceOf(address(this))
+				: _amt;
+		}
+
+		approve(tokenContract, address(aave), _amt);
+
+		aave.supply(_token, _amt, address(this), referralCode);
+
+		if (getCollateralBalance(_token) > 0 && getIsColl(_token)) {
+			aave.setUserUseReserveAsCollateral(_token, false);
+		}
+
+		setUint(setId, _amt);
+
+		_eventName = "LogDepositWithoutCollateral(address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Withdraw ETH/ERC20_Token.
+	 * @notice Withdraw deposited token from Aave v3
+	 * @param token The address of the token to withdraw.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens withdrawn.
+	 */
+	function withdraw(
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		uint256 initialBal = tokenContract.balanceOf(address(this));
+		aave.withdraw(_token, _amt, address(this));
+		uint256 finalBal = tokenContract.balanceOf(address(this));
+
+		_amt = sub(finalBal, initialBal);
+
+		convertWethToEth(isEth, tokenContract, _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogWithdraw(address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Borrow ETH/ERC20_Token.
+	 * @notice Borrow a token using Aave v3
+	 * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to borrow.
+	 * @param rateMode The type of debt. (For Stable: 1, Variable: 2)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens borrowed.
+	 */
+	function borrow(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		aave.borrow(_token, _amt, rateMode, referralCode, address(this));
+		convertWethToEth(isEth, TokenInterface(_token), _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogBorrow(address,uint256,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, rateMode, getId, setId);
+	}
+
+	/**
+	 * @dev Borrow ETH/ERC20_Token on behalf of a user.
+	 * @notice Borrow a token using Aave v3 on behalf of a user
+	 * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to borrow.
+	 * @param rateMode The type of debt. (For Stable: 1, Variable: 2)
+	 * @param onBehalfOf The user who will incur the debt
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens borrowed.
+	 */
+	function borrowOnBehalfOf(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		address onBehalfOf,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		aave.borrow(_token, _amt, rateMode, referralCode, onBehalfOf);
+		convertWethToEth(isEth, TokenInterface(_token), _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogBorrowOnBehalfOf(address,uint256,uint256,address,uint256,uint256)";
+		_eventParam = abi.encode(
+			token,
+			_amt,
+			rateMode,
+			onBehalfOf,
+			getId,
+			setId
+		);
+	}
+
+	/**
+	 * @dev Payback borrowed ETH/ERC20_Token.
+	 * @notice Payback debt owed.
+	 * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to payback. (For max: `uint256(-1)`)
+	 * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens paid back.
+	 */
+	function payback(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		_amt = _amt == uint256(-1) ? getPaybackBalance(_token, rateMode) : _amt;
+
+		if (isEth) convertEthToWeth(isEth, tokenContract, _amt);
+
+		approve(tokenContract, address(aave), _amt);
+
+		aave.repay(_token, _amt, rateMode, address(this));
+
+		setUint(setId, _amt);
+
+		_eventName = "LogPayback(address,uint256,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, rateMode, getId, setId);
+	}
+
+	/**
+	 * @dev Payback borrowed ETH/ERC20_Token using aTokens.
+	 * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the equivalent debt tokens.
+	 * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to payback. (For max: `uint256(-1)`)
+	 * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens paid back.
+	 */
+	function paybackWithATokens(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		_amt = _amt == uint256(-1) ? getPaybackBalance(_token, rateMode) : _amt;
+
+		if (isEth) convertEthToWeth(isEth, tokenContract, _amt);
+
+		approve(tokenContract, address(aave), _amt);
+
+		aave.repayWithATokens(_token, _amt, rateMode);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogPayback(address,uint256,uint256,uint256,uint256)";
+		_eventParam = abi.encode(token, _amt, rateMode, getId, setId);
+	}
+
+	/**
+	 * @dev Payback borrowed ETH/ERC20_Token on behalf of a user.
+	 * @notice Payback debt owed on behalf os a user.
+	 * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to payback. (For max: `uint256(-1)`)
+	 * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2)
+	 * @param onBehalfOf Address of user who's debt to repay.
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens paid back.
+	 */
+	function paybackOnBehalfOf(
+		address token,
+		uint256 amt,
+		uint256 rateMode,
+		address onBehalfOf,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		_amt = _amt == uint256(-1)
+			? getOnBehalfOfPaybackBalance(_token, rateMode, onBehalfOf)
+			: _amt;
+
+		if (isEth) convertEthToWeth(isEth, tokenContract, _amt);
+
+		approve(tokenContract, address(aave), _amt);
+
+		aave.repay(_token, _amt, rateMode, onBehalfOf);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogPaybackOnBehalfOf(address,uint256,uint256,address,uint256,uint256)";
+		_eventParam = abi.encode(
+			token,
+			_amt,
+			rateMode,
+			onBehalfOf,
+			getId,
+			setId
+		);
+	}
+
+	/**
+	 * @dev Enable collateral
+	 * @notice Enable an array of tokens as collateral
+	 * @param tokens Array of tokens to enable collateral
+	 */
+	function enableCollateral(address[] calldata tokens)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _length = tokens.length;
+		require(_length > 0, "0-tokens-not-allowed");
+
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		for (uint256 i = 0; i < _length; i++) {
+			bool isEth = tokens[i] == ethAddr;
+			address _token = isEth ? wethAddr : tokens[i];
+
+			if (getCollateralBalance(_token) > 0 && !getIsColl(_token)) {
+				aave.setUserUseReserveAsCollateral(_token, true);
+			}
+		}
+
+		_eventName = "LogEnableCollateral(address[])";
+		_eventParam = abi.encode(tokens);
+	}
+
+	/**
+	 * @dev Swap borrow rate mode
+	 * @notice Swaps user borrow rate mode between variable and stable
+	 * @param token The address of the token to swap borrow rate.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param rateMode Current rate mode. (Stable = 1, Variable = 2)
+	 */
+	function swapBorrowRateMode(address token, uint256 rateMode)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		if (getPaybackBalance(_token, rateMode) > 0) {
+			aave.swapBorrowRateMode(_token, rateMode);
+		}
+
+		_eventName = "LogSwapRateMode(address,uint256)";
+		_eventParam = abi.encode(token, rateMode);
+	}
+
+	/**
+	 * @dev Set user e-mode
+	 * @notice Updates the user's e-mode category
+	 * @param categoryId The category Id of the e-mode user want to set
+	 */
+	function setUserEMode(uint8 categoryId)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		AaveInterface aave = AaveInterface(aaveProvider.getPool());
+
+		aave.setUserEMode(categoryId);
+
+		_eventName = "LogSetUserEMode(uint8)";
+		_eventParam = abi.encode(categoryId);
+	}
+
+	/**
+	 * @dev Approve Delegation
+	 * @notice Gives approval to delegate debt tokens
+	 * @param token The address of token
+	 * @param amount The amount
+	 * @param rateMode The type of debt
+	 * @param delegateTo The address to whom the user is delegating
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens delegated.
+	 */
+	function delegateBorrow(
+		address token,
+		uint256 amount,
+		uint256 rateMode,
+		address delegateTo,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		require(rateMode == 1 || rateMode == 2, "Invalid debt type");
+		uint256 _amt = getUint(getId, amount);
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		address _dToken = getDTokenAddr(_token, rateMode);
+		DTokenInterface(_dToken).approveDelegation(delegateTo, _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogDelegateBorrow(address,uint256,uint256,address,uint256,uint256)";
+		_eventParam = abi.encode(
+			token,
+			_amt,
+			rateMode,
+			delegateTo,
+			getId,
+			setId
+		);
+	}
+}
+
+contract ConnectV2AaveV3Base is AaveResolver {
+	string public constant name = "AaveV3-v1.0";
+}