Merge branch 'aave-v2-to-v3-import' of https://github.com/Instadapp/dsa-connectors into aave-v3-addresses-update

This commit is contained in:
pradyuman-verma 2022-03-24 01:21:10 +05:30
commit ea78b1ccb4
No known key found for this signature in database
GPG Key ID: E36FD6BC8923221F
483 changed files with 13324 additions and 15819 deletions

View File

@ -2,4 +2,10 @@ ETHERSCAN_API_KEY=""
PRIVATE_KEY=""
TENDERLY_PROJECT=""
TENDERLY_USERNAME=""
ALCHEMY_ID=""
ALCHEMY_ID=""
MAIN_ETHSCAN_KEY=
OPT_ETHSCAN_KEY=
POLY_ETHSCAN_KEY=
ARB_ETHSCAN_KEY=
AVAX_ETHSCAN_KEY=
FTM_ETHSCAN_KEY=

View File

@ -6,7 +6,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
permissions:
permissions:
contents: write
strategy:
matrix:
@ -32,12 +32,9 @@ jobs:
- name: Run status checks
id: status_check
run: |
mkdir -p pr
# Run status checks, Remove ANSI colors from the text
output=$(node ./status-checks | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g')
# Escape newlines so _all_ the output is included in the set-output
output="${output//'%'/'%25'}"
output="${output//$'\n'/'%0A'}"
output="${output//$'\r'/'%0D'}"
output=$(npx ts-node ./status-checks/index.ts | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g')
cat <<< "$output" > "./pr/status-check-output"
echo ${{ github.event.number }} > ./pr/number
- uses: actions/upload-artifact@v2

3
.gitignore vendored
View File

@ -63,4 +63,5 @@ build/contracts
# buidler
artifacts
cache
typechain
typechain

View File

@ -47,8 +47,27 @@ Run all the tests:
```sh
$ npm run test
```
(Striclty use this envirnment to test, or otherwise make suitable changes in config file before testing).
### Deploy
To deploy a connector using interactive CLI
```sh
$ npm run deploy:runner
```
(To deploy script manually use `scripts/deployment/deployManually.ts` script)
### checks
To check that code is compatible with github actions
```sh
$ npm run check
```
## How to add a new connector
You can create a new PR to add a new connector. To get the PR merged, certain requirements needs to be met which will be explained here.
@ -57,39 +76,39 @@ You can create a new PR to add a new connector. To get the PR merged, certain re
Common files for all connectors are in `contracts/common` directory.
* `math.sol` has methods for mathematical operations (`DSMath`)
* `interfaces.sol` contains the common interfaces
* `TokenInterface` for ERC-20 interface including WETH
* `stores.sol` contains the global constants as well as methods `getId` & `setId` (`Stores`)
* `basic.sol` inherits `DSMath` & `Stores` contracts. This contains few details explained below
* Wrapping & unwrapping ETH (`convertEthToWeth` & `convertWethToEth`)
* Getting token & ETH balance of DSA
- `math.sol` has methods for mathematical operations (`DSMath`)
- `interfaces.sol` contains the common interfaces
- `TokenInterface` for ERC-20 interface including WETH
- `stores.sol` contains the global constants as well as methods `getId` & `setId` (`Stores`)
- `basic.sol` inherits `DSMath` & `Stores` contracts. This contains few details explained below
- Wrapping & unwrapping ETH (`convertEthToWeth` & `convertWethToEth`)
- Getting token & ETH balance of DSA
Connectors are under `contracts/connectors` directory, and should be formatted as follows:
* Connector events should be in a separate contract: `events.sol`
* Interfaces should be defined in a seperate file: `interface.sol`
* If the connector has helper methods & constants (including interface instances), this should be defined in a separate file: `helpers.sol`
* `Helpers` contract should inherit `Basic` contract from common directory
* If the connector doesn't have any helper methods, the main contract should inherit `Basic` contract
* The main logic of the contract should be under `main.sol`, and the contract should inherit `Helpers` (if exists, otherwise `Basic`) & `Events`
- Connector events should be in a separate contract: `events.sol`
- Interfaces should be defined in a seperate file: `interface.sol`
- If the connector has helper methods & constants (including interface instances), this should be defined in a separate file: `helpers.sol`
- `Helpers` contract should inherit `Basic` contract from common directory
- If the connector doesn't have any helper methods, the main contract should inherit `Basic` contract
- The main logic of the contract should be under `main.sol`, and the contract should inherit `Helpers` (if exists, otherwise `Basic`) & `Events`
Few things to consider while writing the connector:
* Connector should have a public constant string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1`
* Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound`
* User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables:
* `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)`
* `_eventParam` of `bytes` type: This will be the abi encoded event parameters
* The contracts should not have `selfdestruct()`
* The contracts should not have `delegatecall()`
* Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere
* Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20)
* Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc
* Only `approve()` (declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell.
* User interacting functions should have natspec comments(@dev, @notice, @param).
* Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell
* Use `setUint()` (declared in `Stores`) for setting value to save for the future spell
- Connector should have a public constant string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1`
- Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound`
- User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables:
- `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)`
- `_eventParam` of `bytes` type: This will be the abi encoded event parameters
- The contracts should not have `selfdestruct()`
- The contracts should not have `delegatecall()`
- Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere
- Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20)
- Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc
- Only `approve()` (declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell.
- User interacting functions should have natspec comments(@dev, @notice, @param).
- Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell
- Use `setUint()` (declared in `Stores`) for setting value to save for the future spell
### Support

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "./interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
interface TokenInterface {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { MemoryInterface, InstaMapping } from "./interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -0,0 +1,15 @@
//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
);
}

View File

@ -0,0 +1,287 @@
//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;
}
}
contract AaveHelpers is Helper {
function getBorrowAmount(address _token, address userAccount)
internal
view
returns (uint256 stableBorrow, uint256 variableBorrow)
{
(
,
address stableDebtTokenAddress,
address variableDebtTokenAddress
) = aaveData.getReserveTokensAddresses(_token);
stableBorrow = ATokenInterface(stableDebtTokenAddress).balanceOf(
userAccount
);
variableBorrow = ATokenInterface(variableDebtTokenAddress).balanceOf(
userAccount
);
}
function getBorrowAmounts(
address userAccount,
AaveInterface aave,
ImportInputData memory inputData,
ImportData memory data
) internal returns (ImportData memory) {
if (inputData.borrowTokens.length > 0) {
data._borrowTokens = new address[](inputData.borrowTokens.length);
data.variableBorrowAmts = new uint256[](
inputData.borrowTokens.length
);
data.variableBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
data.stableBorrowAmts = new uint256[](
inputData.borrowTokens.length
);
data.stableBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length);
data.totalBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
for (uint256 i = 0; i < inputData.borrowTokens.length; i++) {
for (uint256 j = i; j < inputData.borrowTokens.length; j++) {
if (j != i) {
require(
inputData.borrowTokens[i] !=
inputData.borrowTokens[j],
"token-repeated"
);
}
}
}
for (uint256 i = 0; i < inputData.borrowTokens.length; i++) {
address _token = inputData.borrowTokens[i] == ethAddr
? wethAddr
: inputData.borrowTokens[i];
data._borrowTokens[i] = _token;
(
data.stableBorrowAmts[i],
data.variableBorrowAmts[i]
) = getBorrowAmount(_token, userAccount);
if (data.variableBorrowAmts[i] != 0) {
data.variableBorrowAmtsWithFee[i] = add(
data.variableBorrowAmts[i],
inputData.flashLoanFees[i]
);
data.stableBorrowAmtsWithFee[i] = data.stableBorrowAmts[i];
} else {
data.stableBorrowAmtsWithFee[i] = add(
data.stableBorrowAmts[i],
inputData.flashLoanFees[i]
);
}
data.totalBorrowAmts[i] = add(
data.stableBorrowAmts[i],
data.variableBorrowAmts[i]
);
data.totalBorrowAmtsWithFee[i] = add(
data.stableBorrowAmtsWithFee[i],
data.variableBorrowAmtsWithFee[i]
);
if (data.totalBorrowAmts[i] > 0) {
uint256 _amt = data.totalBorrowAmts[i];
TokenInterface(_token).approve(address(aave), _amt);
}
}
}
return data;
}
function getSupplyAmounts(
address userAccount,
ImportInputData memory inputData,
ImportData memory data
) internal view returns (ImportData memory) {
data.supplyAmts = new uint256[](inputData.supplyTokens.length);
data._supplyTokens = new address[](inputData.supplyTokens.length);
data.aTokens = new ATokenInterface[](inputData.supplyTokens.length);
for (uint256 i = 0; i < inputData.supplyTokens.length; i++) {
for (uint256 j = i; j < inputData.supplyTokens.length; j++) {
if (j != i) {
require(
inputData.supplyTokens[i] != inputData.supplyTokens[j],
"token-repeated"
);
}
}
}
for (uint256 i = 0; i < inputData.supplyTokens.length; i++) {
address _token = inputData.supplyTokens[i] == ethAddr
? wethAddr
: inputData.supplyTokens[i];
(address _aToken, , ) = aaveData.getReserveTokensAddresses(_token);
data._supplyTokens[i] = _token;
data.aTokens[i] = ATokenInterface(_aToken);
data.supplyAmts[i] = data.aTokens[i].balanceOf(userAccount);
}
return data;
}
function _paybackBehalfOne(
AaveInterface aave,
address token,
uint256 amt,
uint256 rateMode,
address user
) private {
aave.repay(token, amt, rateMode, user);
}
function _PaybackStable(
uint256 _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOne(aave, tokens[i], amts[i], 1, user);
}
}
}
function _PaybackVariable(
uint256 _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOne(aave, tokens[i], amts[i], 2, user);
}
}
}
function _TransferAtokens(
uint256 _length,
AaveInterface aave,
ATokenInterface[] memory atokenContracts,
uint256[] memory amts,
address[] memory tokens,
address userAccount
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
uint256 _amt = amts[i];
require(
atokenContracts[i].transferFrom(
userAccount,
address(this),
_amt
),
"allowance?"
);
if (!getIsColl(tokens[i], address(this))) {
aave.setUserUseReserveAsCollateral(tokens[i], true);
}
}
}
}
function _BorrowVariable(
uint256 _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_borrowOne(aave, tokens[i], amts[i], 2);
}
}
}
function _BorrowStable(
uint256 _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_borrowOne(aave, tokens[i], amts[i], 1);
}
}
}
function _borrowOne(
AaveInterface aave,
address token,
uint256 amt,
uint256 rateMode
) private {
aave.borrow(token, amt, rateMode, referalCode, address(this));
}
}

View File

@ -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);
}

View File

@ -0,0 +1,111 @@
//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
);
}
/**
* @dev Import aave V3 position .
* @notice Import EOA's aave V3 position to DSA's aave v3 position
* @param userAccount The address of the EOA from which aave position will be imported
* @param inputData The struct containing all the neccessary input data
*/
function importAave(address userAccount, ImportInputData memory inputData)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(userAccount, inputData);
}
}
contract ConnectV2AaveV3ImportArbitrum is AaveV3ImportResolver {
string public constant name = "Aave-v3-import-v1";
}

View File

@ -0,0 +1,34 @@
//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);
}

View File

@ -0,0 +1,67 @@
//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(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); // Arbitrum address - PoolAddressesProvider
/**
* @dev Aave Pool Data Provider
*/
AaveDataProviderInterface internal constant aaveData =
AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); //Arbitrum address - PoolDataProvider
/**
* @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 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)
);
}
}

View File

@ -0,0 +1,92 @@
//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);
}

View File

@ -0,0 +1,297 @@
//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 } from "./interface.sol";
abstract contract AaveResolver is Events, Helpers {
/**
* @dev Deposit ETH/ERC20_Token.
* @notice Deposit a token to Aave v2 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 Withdraw ETH/ERC20_Token.
* @notice Withdraw deposited token from Aave v2
* @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 v2
* @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 borrow 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 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 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++) {
address token = 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 Desired borrow 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());
uint256 currentRateMode = rateMode == 1 ? 2 : 1;
if (getPaybackBalance(token, currentRateMode) > 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
returns (string memory _eventName, bytes memory _eventParam)
{
AaveInterface aave = AaveInterface(aaveProvider.getPool());
aave.setUserEMode(categoryId);
_eventName = "LogSetUserEMode(uint8)";
_eventParam = abi.encode(categoryId);
}
}
contract ConnectV2AaveV3Arbitrum is AaveResolver {
string public constant name = "AaveV3-v1.0";
}

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -0,0 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {
event LogSwap(
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,81 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";
import { DSMath } from "../../../common/math.sol";
import { Basic } from "../../../common/basic.sol";
import { SwapData } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev UniswapV3 Swap Router Address
*/
address internal constant V3_SWAP_ROUTER_ADDRESS =
0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
/**
* @dev UniswapV3 swapHelper
* @param swapData - Struct defined in interfaces.sol
*/
function _swapHelper(SwapData memory swapData)
internal
returns (uint256 buyAmt)
{
(uint256 _buyDec, uint256 _sellDec) = getTokensDec(
swapData.buyToken,
swapData.sellToken
);
uint256 _sellAmt18 = convertTo18(_sellDec, swapData._sellAmt);
uint256 _slippageAmt = convert18ToDec(
_buyDec,
wmul(swapData.unitAmt, _sellAmt18)
);
uint256 initalBal = getTokenBal(swapData.buyToken);
// solium-disable-next-line security/no-call-value
(bool success, ) = V3_SWAP_ROUTER_ADDRESS.call(swapData.callData);
if (!success) revert("uniswapV3-swap-failed");
uint256 finalBal = getTokenBal(swapData.buyToken);
buyAmt = sub(finalBal, initalBal);
require(_slippageAmt <= buyAmt, "Too much slippage");
}
/**
* @dev Gets the swapping data from auto router sdk
* @param swapData Struct with multiple swap data defined in interfaces.sol
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function _swap(SwapData memory swapData, uint256 setId)
internal
returns (SwapData memory)
{
bool isEthSellToken = address(swapData.sellToken) == ethAddr;
bool isEthBuyToken = address(swapData.buyToken) == ethAddr;
swapData.sellToken = isEthSellToken
? TokenInterface(wethAddr)
: swapData.sellToken;
swapData.buyToken = isEthBuyToken
? TokenInterface(wethAddr)
: swapData.buyToken;
convertEthToWeth(isEthSellToken, swapData.sellToken, swapData._sellAmt);
approve(
TokenInterface(swapData.sellToken),
V3_SWAP_ROUTER_ADDRESS,
swapData._sellAmt
);
swapData._buyAmt = _swapHelper(swapData);
convertWethToEth(isEthBuyToken, swapData.buyToken, swapData._buyAmt);
setUint(setId, swapData._buyAmt);
return swapData;
}
}

View File

@ -0,0 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";
struct SwapData {
TokenInterface sellToken;
TokenInterface buyToken;
uint256 _sellAmt;
uint256 _buyAmt;
uint256 unitAmt;
bytes callData;
}

View File

@ -0,0 +1,65 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title UniswapV3_autoRouter.
* @dev DEX.
*/
// import files from common directory
import { TokenInterface, MemoryInterface } from "../../../common/interfaces.sol";
import { Stores } from "../../../common/stores.sol";
import { SwapData } from "./interface.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract AutoRouter is Helpers, Events {
/**
* @dev Sell ETH/ERC20_Token using uniswap v3 auto router.
* @notice Swap tokens from getting an optimized trade routes
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAmt The amount of the token to sell.
* @param unitAmt The amount of buyAmt/sellAmt with slippage.
* @param callData Data from Uniswap V3 auto router SDK.
* @param setId ID stores the amount of token brought.
*/
function sell(
address buyAddr,
address sellAddr,
uint256 sellAmt,
uint256 unitAmt,
bytes calldata callData,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
SwapData memory swapData = SwapData({
buyToken: TokenInterface(buyAddr),
sellToken: TokenInterface(sellAddr),
unitAmt: unitAmt,
callData: callData,
_sellAmt: sellAmt,
_buyAmt: 0
});
swapData = _swap(swapData, setId);
_eventName = "LogSwap(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
buyAddr,
sellAddr,
swapData._buyAmt,
swapData._sellAmt,
0,
setId
);
}
}
contract ConnectV2UniswapV3AutoRouterArbitrum is AutoRouter {
string public name = "UniswapV3-Auto-Router-v1";
}

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma abicoder v2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "./interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
interface TokenInterface {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { MemoryInterface } from "./interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import {TokenInterface} from "../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import {TokenInterface} from "../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { DSMath } from "../../../common/math.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
interface AaveIncentivesInterface {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

View File

@ -0,0 +1,18 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {
event LogAaveImportV2ToV3(
address indexed user,
bool doImport,
bool convertStable,
address[] supplyTokensV2,
address[] supplyTokensV3,
address[] borrowTokensV2,
address[] borrowTokensV3,
uint256[] flashLoanFees,
uint256[] supplyAmts,
uint256[] stableBorrowAmts,
uint256[] variableBorrowAmts
);
}

View File

@ -0,0 +1,361 @@
//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 "./events.sol";
import "./interfaces.sol";
abstract contract Helper is DSMath, Basic {
/**
* @dev Aave referal code
*/
uint16 internal constant referalCode = 3228;
/**
* @dev AaveV2 Lending Pool Provider
*/
AaveV2LendingPoolProviderInterface internal constant aaveV2Provider =
AaveV2LendingPoolProviderInterface(
0xb6A86025F0FE1862B372cb0ca18CE3EDe02A318f // v2 address: LendingPoolAddressProvider avax
);
/**
* @dev AaveV3 Lending Pool Provider
*/
AaveV3PoolProviderInterface internal constant aaveV3Provider =
AaveV3PoolProviderInterface(
0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb // v3 - PoolAddressesProvider Avalanche
);
/**
* @dev Aave Protocol Data Provider
*/
AaveV2DataProviderInterface internal constant aaveV2Data =
AaveV2DataProviderInterface(0x65285E9dfab318f57051ab2b139ccCf232945451); // aave v2 - avax
function getIsColl(address token, address user)
internal
view
returns (bool isCol)
{
(, , , , , , , , isCol) = aaveV2Data.getUserReserveData(token, user);
}
struct ImportData {
address[] _supplyTokens;
address[] _supplyTokensV3;
address[] _borrowTokens;
address[] _borrowTokensV3;
ATokenV2Interface[] 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 _AaveHelper is Helper {
/*
** Convert Avalanche Bridge tokens to Offical tokens. Like USDC.e to USDC
*/
function convertABTokens(address _token) internal pure returns (address) {
if (_token == 0xc7198437980c041c805A1EDcbA50c1Ce5db95118) {
// USDT.e => USDT
return 0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7;
} else if (_token == 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664) {
// USDC.e => USDC
return 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E;
} else {
return _token;
}
}
function getBorrowAmountV2(address _token, address userAccount)
internal
view
returns (uint256 stableBorrow, uint256 variableBorrow)
{
(
,
address stableDebtTokenAddress,
address variableDebtTokenAddress
) = aaveV2Data.getReserveTokensAddresses(_token);
stableBorrow = ATokenV2Interface(stableDebtTokenAddress).balanceOf(
userAccount
);
variableBorrow = ATokenV2Interface(variableDebtTokenAddress).balanceOf(
userAccount
);
}
function getBorrowAmountsV2(
address userAccount,
AaveV2Interface aaveV2,
ImportInputData memory inputData,
ImportData memory data
) internal returns (ImportData memory) {
if (inputData.borrowTokens.length > 0) {
data._borrowTokens = new address[](inputData.borrowTokens.length);
data._borrowTokensV3 = new address[](inputData.borrowTokens.length);
data.variableBorrowAmts = new uint256[](
inputData.borrowTokens.length
);
data.stableBorrowAmts = new uint256[](
inputData.borrowTokens.length
);
data.variableBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
data.stableBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
data.totalBorrowAmtsWithFee = new uint256[](
inputData.borrowTokens.length
);
data.totalBorrowAmts = new uint256[](inputData.borrowTokens.length);
for (uint256 i = 0; i < inputData.borrowTokens.length; i++) {
for (uint256 j = i; j < inputData.borrowTokens.length; j++) {
if (j != i) {
require(
inputData.borrowTokens[i] !=
inputData.borrowTokens[j],
"token-repeated"
);
}
}
}
for (uint256 i = 0; i < inputData.borrowTokens.length; i++) {
address _token = inputData.borrowTokens[i] == avaxAddr
? wavaxAddr
: inputData.borrowTokens[i];
data._borrowTokens[i] = _token;
data._borrowTokensV3[i] = convertABTokens(_token);
(
data.stableBorrowAmts[i],
data.variableBorrowAmts[i]
) = getBorrowAmountV2(_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(aaveV2), _amt);
}
}
}
return data;
}
function getSupplyAmountsV2(
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._supplyTokensV3 = new address[](inputData.supplyTokens.length);
data.aTokens = new ATokenV2Interface[](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, , ) = aaveV2Data.getReserveTokensAddresses(
_token
);
data._supplyTokens[i] = _token;
data._supplyTokensV3[i] = convertABTokens(_token);
data.aTokens[i] = ATokenV2Interface(_aToken);
data.supplyAmts[i] = data.aTokens[i].balanceOf(userAccount);
}
return data;
}
function _paybackBehalfOneV2(
AaveV2Interface aaveV2,
address token,
uint256 amt,
uint256 rateMode,
address user
) private {
aaveV2.repay(token, amt, rateMode, user);
}
function _PaybackStableV2(
uint256 _length,
AaveV2Interface aaveV2,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOneV2(aaveV2, tokens[i], amts[i], 1, user);
}
}
}
function _PaybackVariableV2(
uint256 _length,
AaveV2Interface aaveV2,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOneV2(aaveV2, tokens[i], amts[i], 2, user);
}
}
}
function _TransferAtokensV2(
uint256 _length,
AaveV2Interface aaveV2,
ATokenV2Interface[] 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))) {
aaveV2.setUserUseReserveAsCollateral(tokens[i], true);
}
}
}
}
function _WithdrawTokensFromV2(
uint256 _length,
AaveV2Interface aaveV2,
uint256[] memory amts,
address[] memory tokens
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
uint256 _amt = amts[i];
address _token = tokens[i];
aaveV2.withdraw(_token, _amt, address(this));
}
}
}
function _depositTokensV3(
uint256 _length,
AaveV3Interface aaveV3,
uint256[] memory amts,
address[] memory tokens
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
uint256 _amt = amts[i];
address _token = tokens[i];
TokenInterface tokenContract = TokenInterface(_token);
require(
tokenContract.balanceOf(address(this)) >= _amt,
"Insufficient funds to deposit in v3"
);
approve(tokenContract, address(aaveV3), _amt);
aaveV3.supply(_token, _amt, address(this), referalCode);
if (!getIsColl(_token, address(this))) {
aaveV3.setUserUseReserveAsCollateral(_token, true);
}
}
}
}
function _BorrowVariableV3(
uint256 _length,
AaveV3Interface aaveV3,
address[] memory tokens,
uint256[] memory amts
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_borrowOneV3(aaveV3, tokens[i], amts[i], 2);
}
}
}
function _BorrowStableV3(
uint256 _length,
AaveV3Interface aaveV3,
address[] memory tokens,
uint256[] memory amts
) internal {
for (uint256 i = 0; i < _length; i++) {
if (amts[i] > 0) {
_borrowOneV3(aaveV3, tokens[i], amts[i], 1);
}
}
}
function _borrowOneV3(
AaveV3Interface aaveV3,
address token,
uint256 amt,
uint256 rateMode
) private {
aaveV3.borrow(token, amt, rateMode, referalCode, address(this));
}
}

View File

@ -0,0 +1,151 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// aave v2
interface AaveV2Interface {
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 getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
interface AaveV2LendingPoolProviderInterface {
function getLendingPool() external view returns (address);
}
// Aave Protocol Data Provider
interface AaveV2DataProviderInterface {
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 getReserveConfigurationData(address asset)
// external
// view
// returns (
// uint256 decimals,
// uint256 ltv,
// uint256 liquidationThreshold,
// uint256 liquidationBonus,
// uint256 reserveFactor,
// bool usageAsCollateralEnabled,
// bool borrowingEnabled,
// bool stableBorrowRateEnabled,
// bool isActive,
// bool isFrozen
// );
function getReserveTokensAddresses(address asset)
external
view
returns (
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress
);
}
interface ATokenV2Interface {
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);
}
// aave v3
interface AaveV3Interface {
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 setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
external;
function swapBorrowRateMode(address asset, uint256 interestRateMode)
external;
}
interface AaveV3PoolProviderInterface {
function getPool() external view returns (address);
}

View File

@ -0,0 +1,157 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { TokenInterface, AccountInterface } from "../../../common/interfaces.sol";
import "./interfaces.sol";
import "./helpers.sol";
import "./events.sol";
/**
* @title Aave v2 to v3 import connector .
* @dev migrate aave V2 position to aave v3 position
*/
contract _AaveV2ToV3MigrationResolver is _AaveHelper {
function _importAave(
address userAccount,
ImportInputData memory inputData,
bool doImport
) internal returns (string memory _eventName, bytes memory _eventParam) {
if (doImport) {
// check only when we are importing from user's address
require(
AccountInterface(address(this)).isAuth(userAccount),
"user-account-not-auth"
);
}
require(inputData.supplyTokens.length > 0, "0-length-not-allowed");
ImportData memory data;
AaveV2Interface aaveV2 = AaveV2Interface(
aaveV2Provider.getLendingPool()
);
AaveV3Interface aaveV3 = AaveV3Interface(aaveV3Provider.getPool());
data = getBorrowAmountsV2(userAccount, aaveV2, inputData, data);
data = getSupplyAmountsV2(userAccount, inputData, data);
// payback borrowed amount;
_PaybackStableV2(
data._borrowTokens.length,
aaveV2,
data._borrowTokens,
data.stableBorrowAmts,
userAccount
);
_PaybackVariableV2(
data._borrowTokens.length,
aaveV2,
data._borrowTokens,
data.variableBorrowAmts,
userAccount
);
if (doImport) {
// transfer atokens to this address;
_TransferAtokensV2(
data._supplyTokens.length,
aaveV2,
data.aTokens,
data.supplyAmts,
data._supplyTokens,
userAccount
);
}
// withdraw v2 supplied tokens
_WithdrawTokensFromV2(
data._supplyTokens.length,
aaveV2,
data.supplyAmts,
data._supplyTokens
);
// deposit tokens in v3
_depositTokensV3(
data._supplyTokensV3.length,
aaveV3,
data.supplyAmts,
data._supplyTokensV3
);
// borrow assets in aave v3 after migrating position
if (data.convertStable) {
_BorrowVariableV3(
data._borrowTokensV3.length,
aaveV3,
data._borrowTokensV3,
data.totalBorrowAmtsWithFee
);
} else {
_BorrowStableV3(
data._borrowTokensV3.length,
aaveV3,
data._borrowTokensV3,
data.stableBorrowAmtsWithFee
);
_BorrowVariableV3(
data._borrowTokensV3.length,
aaveV3,
data._borrowTokensV3,
data.variableBorrowAmtsWithFee
);
}
_eventName = "LogAaveImportV2ToV3(address,bool,bool,address[],address[],address[],address[],uint256[],uint256[],uint256[],uint256[])";
_eventParam = abi.encode(
userAccount,
doImport,
inputData.convertStable,
inputData.supplyTokens,
data._supplyTokensV3,
inputData.borrowTokens,
data._borrowTokensV3,
inputData.flashLoanFees,
data.supplyAmts,
data.stableBorrowAmts,
data.variableBorrowAmts
);
}
/**
* @dev Import aave position .
* @notice Import EOA's aave V2 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 importAaveV2ToV3(
address userAccount,
ImportInputData memory inputData
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(userAccount, inputData, true);
}
/**
* @dev Migrate aave position .
* @notice Migrate DSA's aave V2 position to DSA's aave v3 position
* @param inputData The struct containing all the neccessary input data
*/
function migrateAaveV2ToV3(ImportInputData memory inputData)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(
address(this),
inputData,
false
);
}
}
contract ConnectV2AaveV2ToV3MigrationAvalanche is _AaveV2ToV3MigrationResolver {
string public constant name = "Aave-Import-v2-to-v3";
}

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { DSMath } from "../../../common/math.sol";

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
interface AaveInterface {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -0,0 +1,15 @@
//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
);
}

View File

@ -0,0 +1,289 @@
//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;
}
}
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 _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,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);
}

View File

@ -0,0 +1,111 @@
//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
);
}
/**
* @dev Import aave V3 position .
* @notice Import EOA's aave V3 position to DSA's aave v3 position
* @param userAccount The address of the EOA from which aave position will be imported
* @param inputData The struct containing all the neccessary input data
*/
function importAave(address userAccount, ImportInputData memory inputData)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
(_eventName, _eventParam) = _importAave(userAccount, inputData);
}
}
contract ConnectV2AaveV3ImportAvalanche is AaveV3ImportResolver {
string public constant name = "Aave-v3-import-v1";
}

View File

@ -0,0 +1,34 @@
//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);
}

View File

@ -0,0 +1,67 @@
//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(0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb); // Avalanche address - PoolAddressesProvider
/**
* @dev Aave Pool Data Provider
*/
AaveDataProviderInterface internal constant aaveData =
AaveDataProviderInterface(0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654); // Avalanche address - PoolDataProvider
/**
* @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 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)
);
}
}

View File

@ -0,0 +1,92 @@
//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);
}

View File

@ -0,0 +1,297 @@
//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 } from "./interface.sol";
abstract contract AaveResolver is Events, Helpers {
/**
* @dev Deposit avax/ERC20_Token.
* @notice Deposit a token to Aave v3 for lending / collaterization.
* @param token The address of the token to deposit.(For avax: 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 isAVAX = token == avaxAddr;
address _token = isAVAX ? wavaxAddr : token;
TokenInterface tokenContract = TokenInterface(_token);
if (isAVAX) {
_amt = _amt == uint256(-1) ? address(this).balance : _amt;
convertAvaxToWavax(isAVAX, 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 Withdraw avax/ERC20_Token.
* @notice Withdraw deposited token from Aave v3
* @param token The address of the token to withdraw.(For avax: 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 isAVAX = token == avaxAddr;
address _token = isAVAX ? wavaxAddr : 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);
convertWavaxToAvax(isAVAX, tokenContract, _amt);
setUint(setId, _amt);
_eventName = "LogWithdraw(address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, getId, setId);
}
/**
* @dev Borrow avax/ERC20_Token.
* @notice Borrow a token using Aave v3
* @param token The address of the token to borrow.(For avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt The amount of the token to borrow.
* @param rateMode The type of borrow 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 isAVAX = token == avaxAddr;
address _token = isAVAX ? wavaxAddr : token;
aave.borrow(_token, _amt, rateMode, referralCode, address(this));
convertWavaxToAvax(isAVAX, TokenInterface(_token), _amt);
setUint(setId, _amt);
_eventName = "LogBorrow(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, rateMode, getId, setId);
}
/**
* @dev Payback borrowed avax/ERC20_Token.
* @notice Payback debt owed.
* @param token The address of the token to payback.(For avax: 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 isAVAX = token == avaxAddr;
address _token = isAVAX ? wavaxAddr : token;
TokenInterface tokenContract = TokenInterface(_token);
_amt = _amt == uint256(-1) ? getPaybackBalance(_token, rateMode) : _amt;
if (isAVAX) convertAvaxToWavax(isAVAX, 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 avax/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 avax: 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 isAVAX = token == avaxAddr;
address _token = isAVAX ? wavaxAddr : token;
TokenInterface tokenContract = TokenInterface(_token);
_amt = _amt == uint256(-1) ? getPaybackBalance(_token, rateMode) : _amt;
if (isAVAX) convertAvaxToWavax(isAVAX, 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 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++) {
address token = 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 avax: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param rateMode Desired borrow 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());
uint256 currentRateMode = rateMode == 1 ? 2 : 1;
if (getPaybackBalance(token, currentRateMode) > 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
returns (string memory _eventName, bytes memory _eventParam)
{
AaveInterface aave = AaveInterface(aaveProvider.getPool());
aave.setUserEMode(categoryId);
_eventName = "LogSetUserEMode(uint8)";
_eventParam = abi.encode(categoryId);
}
}
contract ConnectV2AaveV3Avalanche is AaveResolver {
string public constant name = "AaveV3-v1.0";
}

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
interface ComptrollerInterface {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Events {

View File

@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import { DSMath } from "../../../common/math.sol";

Some files were not shown because too many files have changed in this diff Show More