Merge pull request from Richa-iitr/aave-v3-import-permit

Aave-v3-import with permit | Avalanche, Polygon, Arbitrum
This commit is contained in:
Thrilok kumar 2022-04-12 17:14:58 +05:30 committed by GitHub
commit 51946a8922
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2839 additions and 3 deletions

View File

@ -0,0 +1,15 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
contract Events {
event LogAaveV3ImportWithPermit(
address indexed user,
address[] atokens,
string[] supplyIds,
string[] borrowIds,
uint256[] flashLoanFees,
uint256[] supplyAmts,
uint256[] borrowAmts
);
}

View File

@ -0,0 +1,316 @@
//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(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;
}
struct SignedPermits {
uint8[] v;
bytes32[] r;
bytes32[] s;
uint256[] expiry;
}
}
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 _PermitATokens(
address userAccount,
ATokenInterface[] memory aTokenContracts,
address[] memory tokens,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s,
uint256[] memory expiry
) internal {
for (uint256 i = 0; i < tokens.length; i++) {
aTokenContracts[i].permit(
userAccount,
address(this),
uint256(-1),
expiry[i],
v[i],
r[i],
s[i]
);
}
}
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));
}
}

View File

@ -0,0 +1,105 @@
//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 permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
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);
}

View File

@ -0,0 +1,132 @@
//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 AaveV3ImportPermitResolver is AaveHelpers {
function _importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
) 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
);
//permit this address to transfer aTokens
_PermitATokens(
userAccount,
data.aTokens,
data._supplyTokens,
permitData.v,
permitData.r,
permitData.s,
permitData.expiry
);
// 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 = "LogAaveV3ImportWithPermit(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
* @param permitData The struct containing signed permit data like v,r,s,expiry
*/
function importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(
userAccount,
inputData,
permitData
);
}
}
contract ConnectV2AaveV3ImportPermitArbitrum is AaveV3ImportPermitResolver {
string public constant name = "Aave-v3-import-permit-v1";
}

View File

@ -0,0 +1,15 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
contract Events {
event LogAaveV3ImportWithPermit(
address indexed user,
address[] atokens,
string[] supplyIds,
string[] borrowIds,
uint256[] flashLoanFees,
uint256[] supplyAmts,
uint256[] borrowAmts
);
}

View File

@ -0,0 +1,318 @@
//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 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;
}
struct SignedPermits {
uint8[] v;
bytes32[] r;
bytes32[] s;
uint256[] expiry;
}
}
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] == 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.variableBorrowAmtsWithFee[i] = data.variableBorrowAmts[
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 _PermitATokens(
address userAccount,
ATokenInterface[] memory aTokenContracts,
address[] memory tokens,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s,
uint256[] memory expiry
) internal {
for (uint256 i = 0; i < tokens.length; i++) {
aTokenContracts[i].permit(
userAccount,
address(this),
uint256(-1),
expiry[i],
v[i],
r[i],
s[i]
);
}
}
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));
}
}

View File

@ -0,0 +1,105 @@
//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 permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
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);
}

View File

@ -0,0 +1,132 @@
//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 AaveV3ImportPermitResolver is AaveHelpers {
function _importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
) 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
);
//permit this address to transfer aTokens
_PermitATokens(
userAccount,
data.aTokens,
data._supplyTokens,
permitData.v,
permitData.r,
permitData.s,
permitData.expiry
);
// 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 = "LogAaveV3ImportWithPermit(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
* @param permitData The struct containing signed permit data like v,r,s,expiry
*/
function importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(
userAccount,
inputData,
permitData
);
}
}
contract ConnectV2AaveV3ImportPermitAvalanche is AaveV3ImportPermitResolver {
string public constant name = "Aave-v3-import-permit-v1";
}

View File

@ -0,0 +1,15 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
contract Events {
event LogAaveV3ImportWithPermit(
address indexed user,
address[] atokens,
string[] supplyIds,
string[] borrowIds,
uint256[] flashLoanFees,
uint256[] supplyAmts,
uint256[] borrowAmts
);
}

View File

@ -0,0 +1,316 @@
//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(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;
}
struct SignedPermits {
uint8[] v;
bytes32[] r;
bytes32[] s;
uint256[] expiry;
}
}
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] == 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 _PermitATokens(
address userAccount,
ATokenInterface[] memory aTokenContracts,
address[] memory tokens,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s,
uint256[] memory expiry
) internal {
for (uint256 i = 0; i < tokens.length; i++) {
aTokenContracts[i].permit(
userAccount,
address(this),
uint256(-1),
expiry[i],
v[i],
r[i],
s[i]
);
}
}
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));
}
}

View File

@ -0,0 +1,105 @@
//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 permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
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);
}

View File

@ -0,0 +1,133 @@
//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 AaveV3ImportPermitResolver is AaveHelpers {
function _importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
) 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
);
//permit this address to transfer aTokens
_PermitATokens(
userAccount,
data.aTokens,
data._supplyTokens,
permitData.v,
permitData.r,
permitData.s,
permitData.expiry
);
// 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 = "LogAaveV3ImportWithPermit(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
* @param permitData The struct containing signed permit data like v,r,s,expiry
*/
function importAave(
address userAccount,
ImportInputData memory inputData,
SignedPermits memory permitData
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(
userAccount,
inputData,
permitData
);
}
}
contract ConnectV2AaveV3ImportPermitPolygon is AaveV3ImportPermitResolver {
string public constant name = "Aave-v3-import-permit-v1";
}

View File

@ -4,6 +4,7 @@ import { impersonateAccounts } from "./impersonate";
import { tokenMapping as mainnetMapping } from "./mainnet/tokens";
import { tokenMapping as polygonMapping } from "./polygon/tokens";
import { tokenMapping as avalancheMapping } from "./avalanche/tokens";
import { tokenMapping as optimismMapping } from "./optimism/tokens";
const mineTx = async (tx: any) => {
await (await tx).wait();
@ -12,7 +13,8 @@ const mineTx = async (tx: any) => {
const tokenMapping: Record<string, Record<string, any>> = {
mainnet: mainnetMapping,
polygon: polygonMapping,
avalanche: avalancheMapping
avalanche: avalancheMapping,
optimism: optimismMapping
};
export async function addLiquidity(tokenName: string, address: any, amt: any) {

View File

@ -3,6 +3,7 @@ import { ethers } from "hardhat";
import { addresses as addressesPolygon } from "./polygon/addresses";
import { addresses as addressesArbitrum } from "./arbitrum/addresses";
import { addresses as addressesAvalanche } from "./avalanche/addresses";
import { addresses as addressesOptimism } from "./optimism/addresses";
import { addresses } from "./mainnet/addresses";
import { abis } from "../constant/abis";
import { abi } from "../../deployements/mainnet/Implementation_m1.sol/InstaImplementationM1.json";
@ -11,6 +12,7 @@ function getAddress(network: string | undefined) {
if (network === "polygon") return addressesPolygon.core.instaIndex;
else if (network === "arbitrum") return addressesArbitrum.core.instaIndex;
else if (network === "avalanche") return addressesAvalanche.core.instaIndex;
else if (network === "optimism") return addressesOptimism.core.instaIndex;
else return addresses.core.instaIndex;
}

View File

@ -3,6 +3,7 @@ import { addresses } from "./mainnet/addresses";
import { abis } from "../constant/abis";
import { addresses as addressesArbitrum } from "./arbitrum/addresses";
import { addresses as addressesAvalanche } from "./avalanche/addresses";
import { addresses as addressesOptimism } from "./optimism/addresses";
import hre from "hardhat";
import type { Signer, Contract } from "ethers";
@ -22,6 +23,7 @@ function getAddress(network: string | undefined) {
if (network === "polygon") return addressesPolygon;
else if (network === "arbitrum") return addressesArbitrum;
else if (network === "avalanche") return addressesAvalanche;
else if (network === "optimism") return addressesOptimism;
else return addresses;
}

View File

@ -3,12 +3,14 @@ import { addresses } from "./mainnet/addresses";
import { addresses as addressesPolygon } from "./polygon/addresses";
import { addresses as addressesArbitrum } from "./arbitrum/addresses";
import { addresses as addressesAvalanche } from "./avalanche/addresses";
import { addresses as addressesOptimism } from "./optimism/addresses";
import { abis } from "../constant/abis";
function getAddress(network: string | undefined) {
if (network === "polygon") return addressesPolygon.core.instaIndex;
else if (network === "arbitrum") return addressesArbitrum.core.instaIndex;
else if (network === "avalanche") return addressesAvalanche.core.instaIndex;
else if (network === "optimism") return addressesOptimism.core.instaIndex;
else return addresses.core.instaIndex;
}

View File

@ -6,7 +6,7 @@ import { execScript } from "./command";
let start: number, end: number;
async function testRunner() {
const chain = ["avalanche", "mainnet", "polygon", "arbitrum"];
const chain = ["avalanche", "mainnet", "polygon", "arbitrum", "optimism"];
start = Date.now();
for (let ch of chain) {

View File

@ -0,0 +1,10 @@
export const addresses: Record<string, any> = {
connectors: {
basic: "0xe5398f279175962E56fE4c5E0b62dc7208EF36c6",
auth: "0xd1aff9f2acf800c876c409100d6f39aea93fc3d9",
},
core: {
connectorsV2: "0x127d8cD0E2b2E0366D522DeA53A787bfE9002C14",
instaIndex: "0x6CE3e607C808b4f4C26B7F6aDAeB619e49CAbb25",
},
};

View File

@ -0,0 +1,87 @@
import { Provider } from "@ethersproject/abstract-provider";
import { Signer } from "@ethersproject/abstract-signer";
import { ethers } from "hardhat";
const mineTx = async (tx: any) => {
await (await tx).wait();
};
export const tokens = {
eth: {
type: "token",
symbol: "ETH",
name: "Eth",
address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
decimals: 18,
},
dai: {
type: "token",
symbol: "DAI",
name: "DAI Stable",
address: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
decimals: 18,
},
usdc: {
type: "token",
symbol: "USDC",
name: "USD Coin",
address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
decimals: 6,
},
};
export const tokenMapping: Record<string, any> = {
usdc: {
impersonateSigner: "0x31efc4aeaa7c39e54a33fdc3c46ee2bd70ae0a09",
address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
abi: [
"function mint(address _to, uint256 _amount) external returns (bool);",
],
process: async function (owner: Signer | Provider, to: any, amt: any) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.mint(to, amt));
},
},
dai: {
impersonateSigner: "0x31efc4aeaa7c39e54a33fdc3c46ee2bd70ae0a09",
address: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
abi: ["function transfer(address to, uint value)"],
process: async function (owner: Signer | Provider, to: any, amt: any) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.transfer(to, amt));
},
},
usdt: {
impersonateSigner: "0x31efc4aeaa7c39e54a33fdc3c46ee2bd70ae0a09",
address: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58",
abi: [
"function issue(uint amount)",
"function transfer(address to, uint value)",
],
process: async function (owner: Signer | Provider, address: any, amt: any) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.issue(amt));
await mineTx(contract.transfer(address, amt));
},
},
wbtc: {
impersonateSigner: "0x3aa76aa74bdfa09d68d9ebeb462c5f40d727283f",
address: "0x68f180fcCe6836688e9084f035309E29Bf0A2095",
abi: ["function mint(address _to, uint256 _amount) public returns (bool)"],
process: async function (owner: Signer | Provider, address: any, amt: any) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.mint(address, amt));
},
},
// inst: {
// impersonateSigner: "0xf1f22f25f748f79263d44735198e023b72806ab1",
// address: "0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb",
// abi: ["function transfer(address to, uint value)"],
// process: async function (owner: Signer | Provider, address: any, amt: any) {
// const contract = new ethers.Contract(this.address, this.abi, owner);
// await mineTx(contract.transfer(address, amt));
// },
// },
};

View File

@ -12,7 +12,7 @@ async function testRunner() {
name: "chain",
message: "What chain do you want to run tests on?",
type: "list",
choices: ["mainnet", "polygon", "avalanche", "arbitrum"],
choices: ["mainnet", "polygon", "avalanche", "arbitrum", "optimism"],
},
]);
const testsPath = join(__dirname, "../../test", chain);

View File

@ -0,0 +1,303 @@
import { expect, should } from "chai";
import hre, { ethers, waffle } from "hardhat";
import type { Signer, Contract } from "ethers";
import { ecsign, ecrecover, pubToAddress } from "ethereumjs-util";
import { keccak256 } from "@ethersproject/keccak256";
import { defaultAbiCoder } from "@ethersproject/abi";
import { BigNumber } from "bignumber.js";
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
import { addresses } from "../../../scripts/tests/arbitrum/addresses";
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
import { abis } from "../../../scripts/constant/abis";
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
import { parseEther, parseUnits } from "ethers/lib/utils";
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
import encodeFlashcastData from "../../../scripts/tests/encodeFlashcastData";
import { ConnectV2AaveV3ImportPermitArbitrum__factory, IERC20__factory } from "../../../typechain";
const ABI = [
"function DOMAIN_SEPARATOR() public view returns (bytes32)",
"function balanceOf(address account) public view returns (uint256)",
"function nonces(address owner) public view returns (uint256)"
];
const aDaiAddress = "0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE";
const aaveAddress = "0x794a61358D6845594F94dc1DB02A252b5b4814aD";
let account = "0xc5ed2333f8a2c351fca35e5ebadb2a82f5d254c3";
const DAI = "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1";
const USDC = "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8";
const mnemonic = "test test test test test test test test test test test junk";
const connectorName = "AAVE-V3-IMPORT-PERMIT-X";
let signer: any, wallet0: any;
const aaveAbi = [
{
inputs: [
{ internalType: "address", name: "asset", type: "address" },
{ internalType: "uint256", name: "amount", type: "uint256" },
{ internalType: "uint256", name: "interestRateMode", type: "uint256" },
{ internalType: "uint16", name: "referralCode", type: "uint16" },
{ internalType: "address", name: "onBehalfOf", type: "address" }
],
name: "borrow",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "address", name: "asset", type: "address" },
{ internalType: "uint256", name: "amount", type: "uint256" },
{ internalType: "address", name: "onBehalfOf", type: "address" },
{ internalType: "uint16", name: "referralCode", type: "uint16" }
],
name: "supply",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}
];
const erc20Abi = [
{
constant: false,
inputs: [
{
name: "_spender",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "approve",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
},
{
constant: true,
inputs: [],
name: "totalSupply",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
{
constant: true,
inputs: [
{
name: "_owner",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
name: "balance",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
{
constant: false,
inputs: [
{
name: "_to",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "transfer",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
}
];
const token = new ethers.Contract(DAI, erc20Abi);
const aDai = new ethers.Contract(aDaiAddress, ABI);
const usdcToken = new ethers.Contract(USDC, erc20Abi);
const aave = new ethers.Contract(aaveAddress, aaveAbi);
describe("Import Aave v3 Position for Arbitrum", function () {
let dsaWallet0: any;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: any;
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
//@ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 9333600
}
}
]
});
masterSigner = await getMasterSigner();
[wallet0] = await ethers.getSigners();
await hre.network.provider.send("hardhat_setBalance", [account, ethers.utils.parseEther("10").toHexString()]);
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [account]
});
signer = await ethers.getSigner(account);
await token.connect(signer).transfer(wallet0.address, ethers.utils.parseEther("10"));
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2AaveV3ImportPermitArbitrum__factory,
signer: masterSigner,
connectors: instaConnectorsV2
});
});
describe("check user AAVE position", async () => {
it("Should create Aave v3 position of DAI(collateral) and USDC(debt)", async () => {
// approve DAI to aavePool
await token.connect(wallet0).approve(aaveAddress, parseEther("10"));
//deposit DAI in aave
await aave.connect(wallet0).supply(DAI, parseEther("10"), wallet.address, 3228);
console.log("Supplied DAI on aave");
//borrow USDC from aave
await aave.connect(wallet0).borrow(USDC, parseUnits("3", 6), 2, 3228, wallet.address);
console.log("Borrowed USDC from aave");
});
it("Should check position of user", async () => {
expect(await aDai.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(10).multipliedBy(1e18).toString()
);
expect(await usdcToken.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(3).multipliedBy(1e6).toString()
);
});
});
describe("Deployment", async () => {
it("Should set correct name", async () => {
expect(await connector.name()).to.eq("Aave-v3-import-permit-v1");
});
});
describe("DSA wallet setup", async () => {
it("Should build DSA v2", async () => {
dsaWallet0 = await buildDSAv2(wallet.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("5")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("5"));
});
});
describe("Aave position migration", async () => {
it("Should migrate Aave position", async () => {
const DOMAIN_SEPARATOR = await aDai.connect(wallet0).DOMAIN_SEPARATOR();
const PERMIT_TYPEHASH = "0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9";
let nonce = (await aDai.connect(wallet0).nonces(wallet.address)).toNumber();
//Approving max amount
const amount = ethers.constants.MaxUint256;
const expiry = Date.now() + 20 * 60;
const digest = keccak256(
ethers.utils.solidityPack(
["bytes1", "bytes1", "bytes32", "bytes32"],
[
"0x19",
"0x01",
DOMAIN_SEPARATOR,
keccak256(
defaultAbiCoder.encode(
["bytes32", "address", "address", "uint256", "uint256", "uint256"],
[PERMIT_TYPEHASH, wallet.address, dsaWallet0.address, amount, nonce, expiry]
)
)
]
)
);
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), "hex"), Buffer.from(wallet.privateKey.slice(2), "hex"));
const amount0 = new BigNumber(await usdcToken.connect(wallet0).balanceOf(wallet.address));
const amountB = new BigNumber(amount0.toString()).multipliedBy(5).dividedBy(1e4);
const amountWithFee = amount0.plus(amountB);
const flashSpells = [
{
connector: "AAVE-V3-IMPORT-PERMIT-X",
method: "importAave",
args: [
wallet.address,
[[DAI], [USDC], false, [amountB.toFixed(0)]],
[[v], [ethers.utils.hexlify(r)], [ethers.utils.hexlify(s)], [expiry]]
]
},
{
connector: "INSTAPOOL-C",
method: "flashPayback",
args: [USDC, amountWithFee.toFixed(0), 0, 0]
}
];
const spells = [
{
connector: "INSTAPOOL-C",
method: "flashBorrowAndCast",
args: [USDC, amount0.toString(), 5, encodeFlashcastData(flashSpells), "0x"]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet.address);
const receipt = await tx.wait();
});
it("Should check DSA AAVE position", async () => {
expect(await aDai.connect(wallet0).balanceOf(dsaWallet0.address)).to.be.gte(
new BigNumber(10).multipliedBy(1e18).toString()
);
});
});
});

View File

@ -0,0 +1,353 @@
import { expect, should } from "chai";
import hre, { ethers, waffle } from "hardhat";
import type { Signer, Contract } from "ethers";
import { ecsign, ecrecover, pubToAddress } from "ethereumjs-util";
import { keccak256 } from "@ethersproject/keccak256";
import { defaultAbiCoder } from "@ethersproject/abi";
import { BigNumber } from "bignumber.js";
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
import { addresses } from "../../../scripts/tests/avalanche/addresses";
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
import { abis } from "../../../scripts/constant/abis";
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
import { parseEther, parseUnits } from "ethers/lib/utils";
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
import encodeFlashcastData from "../../../scripts/tests/encodeFlashcastData";
import { ConnectV2AaveV3ImportPermitAvalanche__factory, IERC20__factory } from "../../../typechain";
const ABI = [
"function DOMAIN_SEPARATOR() public view returns (bytes32)",
"function balanceOf(address account) public view returns (uint256)",
"function nonces(address owner) public view returns (uint256)"
];
const aDaiAddress = "0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE";
const aaveAddress = "0x794a61358d6845594f94dc1db02a252b5b4814ad";
// const account = "0xf04adbf75cdfc5ed26eea4bbbb991db002036bdd";
let account = "0x95eEA1Bdd19A8C40E9575048Dd0d6577D11a84e5";
const DAI = "0xd586E7F844cEa2F87f50152665BCbc2C279D8d70";
const ETH = "0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB";
const mnemonic = "test test test test test test test test test test test junk";
const connectorName = "AAVE-V3-IMPORT-PERMIT-X";
let signer: any, wallet0: any;
const aaveAbi =[
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "uint256",
name: "interestRateMode",
type: "uint256"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
}
],
name: "borrow",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
}
],
name: "deposit",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
}
],
name: "supply",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}
];
const erc20Abi = [
{
constant: false,
inputs: [
{
name: "_spender",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "approve",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
},
{
constant: true,
inputs: [
{
name: "_owner",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
name: "balance",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
{
constant: false,
inputs: [
{
name: "_to",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "transfer",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
}
];
const token = new ethers.Contract(DAI, erc20Abi);
const aDai = new ethers.Contract(aDaiAddress, ABI);
const ethToken = new ethers.Contract(ETH, erc20Abi);
const aave = new ethers.Contract(aaveAddress, aaveAbi);
describe("Import Aave v3 Position for Avalanche", function () {
let dsaWallet0: any;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: any;
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
//@ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 13024200
}
}
]
});
masterSigner = await getMasterSigner();
[wallet0] = await ethers.getSigners();
await hre.network.provider.send("hardhat_setBalance", [account, ethers.utils.parseEther("10").toHexString()]);
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [account]
});
signer = await ethers.getSigner(account);
await token.connect(signer).transfer(wallet0.address, ethers.utils.parseEther("8"));
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2AaveV3ImportPermitAvalanche__factory,
signer: masterSigner,
connectors: instaConnectorsV2
});
});
describe("check user AAVE position", async () => {
it("Should create Aave v3 position of DAI(collateral) and ETH(debt)", async () => {
// approve DAI to aavePool
await token.connect(wallet0).approve(aaveAddress, parseEther("8"));
//deposit DAI in aave
await aave.connect(wallet0).supply(DAI, parseEther("8"), wallet.address, 3228);
console.log("Supplied DAI on aave");
//borrow ETH from aave
await aave.connect(wallet0).borrow(ETH, parseUnits("3", 6), 2, 3228, wallet.address);
console.log("Borrowed ETH from aave");
});
it("Should check position of user", async () => {
expect(await aDai.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(8).multipliedBy(1e18).toString()
);
expect(await ethToken.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(3).multipliedBy(1e6).toString()
);
});
});
describe("Deployment", async () => {
it("Should set correct name", async () => {
expect(await connector.name()).to.eq("Aave-v3-import-permit-v1");
});
});
describe("DSA wallet setup", async () => {
it("Should build DSA v2", async () => {
dsaWallet0 = await buildDSAv2(wallet.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("3")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("3"));
});
});
describe("Aave position migration", async () => {
it("Should migrate Aave position", async () => {
const DOMAIN_SEPARATOR = await aDai.connect(wallet0).DOMAIN_SEPARATOR();
const PERMIT_TYPEHASH = "0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9";
let nonce = (await aDai.connect(wallet0).nonces(wallet.address)).toNumber();
//Approving max amount
const amount = ethers.constants.MaxUint256;
const expiry = Date.now() + 20 * 60;
const digest = keccak256(
ethers.utils.solidityPack(
["bytes1", "bytes1", "bytes32", "bytes32"],
[
"0x19",
"0x01",
DOMAIN_SEPARATOR,
keccak256(
defaultAbiCoder.encode(
["bytes32", "address", "address", "uint256", "uint256", "uint256"],
[PERMIT_TYPEHASH, wallet.address, dsaWallet0.address, amount, nonce, expiry]
)
)
]
)
);
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), "hex"), Buffer.from(wallet.privateKey.slice(2), "hex"));
const amount0 = new BigNumber(await ethToken.connect(wallet0).balanceOf(wallet.address));
const amountB = new BigNumber(amount0.toString()).multipliedBy(9).dividedBy(1e4);
const amountWithFee = amount0.plus(amountB);
const flashSpells = [
{
connector: "AAVE-V3-IMPORT-PERMIT-X",
method: "importAave",
args: [
wallet.address,
[[DAI], [ETH], false, [amountB.toFixed(0)]],
[[v], [ethers.utils.hexlify(r)], [ethers.utils.hexlify(s)], [expiry]]
]
},
{
connector: "INSTAPOOL-C",
method: "flashPayback",
args: [ETH, amountWithFee.toFixed(0), 0, 0]
}
];
const spells = [
{
connector: "INSTAPOOL-C",
method: "flashBorrowAndCast",
args: [ETH, amount0.toString(), 1, encodeFlashcastData(flashSpells), "0x"]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet.address);
const receipt = await tx.wait();
});
it("Should check DSA AAVE position", async () => {
expect(await aDai.connect(wallet0).balanceOf(dsaWallet0.address)).to.be.gte(
new BigNumber(3).multipliedBy(1e18).toString()
);
});
});
});

View File

@ -0,0 +1,368 @@
import { expect, should } from "chai";
import hre, { ethers, waffle } from "hardhat";
import type { Signer, Contract } from "ethers";
import { ecsign, ecrecover, pubToAddress } from "ethereumjs-util";
import { keccak256 } from "@ethersproject/keccak256";
import { toUtf8Bytes } from "@ethersproject/strings";
import { defaultAbiCoder } from "@ethersproject/abi";
import { BigNumber } from "bignumber.js";
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
import { addresses } from "../../../scripts/tests/polygon/addresses";
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
import { abis } from "../../../scripts/constant/abis";
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
import { parseEther, parseUnits } from "ethers/lib/utils";
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
import encodeFlashcastData from "../../../scripts/tests/encodeFlashcastData";
import { ConnectV2AaveV3ImportPermitPolygon__factory, IERC20__factory } from "../../../typechain";
const ABI = [
"function DOMAIN_SEPARATOR() public view returns (bytes32)",
"function balanceOf(address account) public view returns (uint256)",
"function nonces(address owner) public view returns (uint256)"
];
const aDaiAddress = "0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE";
const aaveAddress = "0x794a61358D6845594F94dc1DB02A252b5b4814aD";
const account = "0xf04adbf75cdfc5ed26eea4bbbb991db002036bdd";
const DAI = "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063";
const USDC = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174";
const mnemonic = "test test test test test test test test test test test junk";
const connectorName = "AAVE-V3-IMPORT-PERMIT-X";
let signer: any, wallet0: any;
const aaveAbi = [
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "uint256",
name: "interestRateMode",
type: "uint256"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
}
],
name: "borrow",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
}
],
name: "deposit",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "asset",
type: "address"
},
{
internalType: "uint256",
name: "amount",
type: "uint256"
},
{
internalType: "address",
name: "onBehalfOf",
type: "address"
},
{
internalType: "uint16",
name: "referralCode",
type: "uint16"
}
],
name: "supply",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}
];
const erc20Abi = [
{
constant: false,
inputs: [
{
name: "_spender",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "approve",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
},
{
constant: true,
inputs: [],
name: "totalSupply",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
{
constant: true,
inputs: [
{
name: "_owner",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
name: "balance",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
{
constant: false,
inputs: [
{
name: "_to",
type: "address"
},
{
name: "_value",
type: "uint256"
}
],
name: "transfer",
outputs: [
{
name: "",
type: "bool"
}
],
payable: false,
stateMutability: "nonpayable",
type: "function"
}
];
const token = new ethers.Contract(DAI, erc20Abi);
const aDai = new ethers.Contract(aDaiAddress, ABI);
const usdcToken = new ethers.Contract(USDC, erc20Abi);
const aave = new ethers.Contract(aaveAddress, aaveAbi);
describe("Import Aave v3 Position", function () {
let dsaWallet0: any;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: any;
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
//@ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 26652016
}
}
]
});
masterSigner = await getMasterSigner();
[wallet0] = await ethers.getSigners();
await hre.network.provider.send("hardhat_setBalance", [account, ethers.utils.parseEther("10").toHexString()]);
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [account]
});
signer = await ethers.getSigner(account);
await token.connect(signer).transfer(wallet0.address, ethers.utils.parseEther("8"));
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2AaveV3ImportPermitPolygon__factory,
signer: masterSigner,
connectors: instaConnectorsV2
});
});
describe("check user AAVE position", async () => {
it("Should create Aave v3 position of DAI(collateral) and USDC(debt)", async () => {
// approve DAI to aavePool
await token.connect(wallet0).approve(aaveAddress, parseEther("8"));
//deposit DAI in aave
await aave.connect(wallet0).supply(DAI, parseEther("8"), wallet.address, 3228);
console.log("Supplied DAI on aave");
//borrow USDC from aave
await aave.connect(wallet0).borrow(USDC, parseUnits("5", 6), 2, 3228, wallet.address);
console.log("Borrowed USDC from aave");
});
it("Should check position of user", async () => {
expect(await aDai.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(8).multipliedBy(1e18).toString()
);
expect(await usdcToken.connect(wallet0).balanceOf(wallet.address)).to.be.gte(
new BigNumber(5).multipliedBy(1e6).toString()
);
});
});
describe("Deployment", async () => {
it("Should set correct name", async () => {
expect(await connector.name()).to.eq("Aave-v3-import-permit-v1");
});
});
describe("DSA wallet setup", async () => {
it("Should build DSA v2", async () => {
dsaWallet0 = await buildDSAv2(wallet.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("5")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("5"));
});
});
describe("Aave position migration", async () => {
it("Should migrate Aave position", async () => {
const DOMAIN_SEPARATOR = await aDai.connect(wallet0).DOMAIN_SEPARATOR();
const PERMIT_TYPEHASH = "0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9";
let nonce = (await aDai.connect(wallet0).nonces(wallet.address)).toNumber();
//Approving max amount
const amount = ethers.constants.MaxUint256;
const expiry = Date.now() + 20 * 60;
const digest = keccak256(
ethers.utils.solidityPack(
["bytes1", "bytes1", "bytes32", "bytes32"],
[
"0x19",
"0x01",
DOMAIN_SEPARATOR,
keccak256(
defaultAbiCoder.encode(
["bytes32", "address", "address", "uint256", "uint256", "uint256"],
[PERMIT_TYPEHASH, wallet.address, dsaWallet0.address, amount, nonce, expiry]
)
)
]
)
);
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), "hex"), Buffer.from(wallet.privateKey.slice(2), "hex"));
const amount0 = new BigNumber(await usdcToken.connect(wallet0).balanceOf(wallet.address));
const amountB = new BigNumber(amount0.toString()).multipliedBy(5).dividedBy(1e4);
const amountWithFee = amount0.plus(amountB);
const flashSpells = [
{
connector: "AAVE-V3-IMPORT-PERMIT-X",
method: "importAave",
args: [
wallet.address,
[[DAI], [USDC], false, [amountB.toFixed(0)]],
[[ethers.utils.hexlify(v)], [ethers.utils.hexlify(r)], [ethers.utils.hexlify(s)], [expiry]]
]
},
{
connector: "INSTAPOOL-C",
method: "flashPayback",
args: [USDC, amountWithFee.toFixed(0), 0, 0]
}
];
const spells = [
{
connector: "INSTAPOOL-C",
method: "flashBorrowAndCast",
args: [USDC, amount0.toString(), 5, encodeFlashcastData(flashSpells), "0x"]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet.address);
const receipt = await tx.wait();
});
it("Should check DSA AAVE position", async () => {
expect(await aDai.connect(wallet0).balanceOf(dsaWallet0.address)).to.be.gte(
new BigNumber(8).multipliedBy(1e18).toString()
);
});
});
});