Skip to content

Commit 6c0bbad

Browse files
authored
Merge branch 'master' into feat/add-compile-prior-tests
2 parents 0f7a68a + 644350c commit 6c0bbad

File tree

216 files changed

+29972
-12911
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

216 files changed

+29972
-12911
lines changed

.github/workflows/node.js.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [14.x]
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
- name: Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v2
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
- uses: actions/cache@v2
24+
with:
25+
path: ~/.npm
26+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
27+
restore-keys: |
28+
${{ runner.os }}-node-
29+
- name: Install dependencies
30+
run: npm ci
31+
- name: Test
32+
run: npm run ci:test
33+
# - name: Coverage
34+
# run: npm run coverage
35+
# - uses: codecov/codecov-action@v1
36+
# with:
37+
# fail_ci_if_error: true

.gitlab-ci.yml

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
stages:
22
- checks
3+
- prepare
4+
- publish
5+
6+
variables:
7+
IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
8+
9+
lint:
10+
stage: checks
11+
tags:
12+
- aave-build-runner
13+
before_script:
14+
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml build
15+
script:
16+
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run prettier:check
17+
after_script:
18+
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
19+
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down
320

421
test:
522
stage: checks
@@ -12,7 +29,9 @@ test:
1229
after_script:
1330
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
1431
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down
15-
32+
only:
33+
- master
34+
- merge_requests
1635
deploy-mainnet-fork:
1736
tags:
1837
- aave-build-runner
@@ -24,6 +43,9 @@ deploy-mainnet-fork:
2443
after_script:
2544
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
2645
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down
46+
only:
47+
- master
48+
- merge_requests
2749

2850
certora-test:
2951
stage: checks
@@ -40,3 +62,31 @@ certora-test:
4062
- certoraRun specs/harness/StableDebtTokenHarness.sol:StableDebtTokenHarness --solc_args "['--optimize']" --verify StableDebtTokenHarness:specs/StableDebtToken.spec --settings -assumeUnwindCond,-b=4 --cache StableDebtToken --cloud
4163
- certoraRun specs/harness/UserConfigurationHarness.sol --verify UserConfigurationHarness:specs/UserConfiguration.spec --solc_args "['--optimize']" --settings -useBitVectorTheory --cache UserConfiguration --cloud
4264
- certoraRun contracts/protocol/tokenization/VariableDebtToken.sol:VariableDebtToken specs/harness/LendingPoolHarnessForVariableDebtToken.sol --solc_args "['--optimize']" --link VariableDebtToken:POOL=LendingPoolHarnessForVariableDebtToken --verify VariableDebtToken:specs/VariableDebtToken.spec --settings -assumeUnwindCond,-useNonLinearArithmetic,-b=4 --cache VariableDebtToken --cloud
65+
only:
66+
- master
67+
- merge_requests
68+
69+
prepare:
70+
stage: prepare
71+
tags:
72+
- docker-builder
73+
script:
74+
- docker build -t ${IMAGE} .
75+
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
76+
- docker push ${IMAGE}
77+
only:
78+
- master
79+
80+
publish:
81+
image: ${IMAGE}
82+
tags:
83+
- docker
84+
stage: publish
85+
script:
86+
- npm ci
87+
- echo //registry.npmjs.org/:_authToken=${NPM_V2_PACKAGES_TOKEN} > .npmrc
88+
- npm run compile
89+
- ${VERSION}
90+
- npm publish --access public
91+
only:
92+
- master

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
2+
[![Build pass](https://github.com/AAVE/protocol-v2/actions/workflows/node.js.yml/badge.svg)](https://github.com/aave/protocol-v2/actions/workflows/node.js.yml)
13
```
24
.///. .///. //. .// `/////////////-
35
`++:++` .++:++` :++` `++: `++:......---.`
@@ -40,6 +42,37 @@ A more detailed and technical description of the protocol can be found in this r
4042

4143
You can join at the [Discord](http://aave.com/discord) channel or at the [Governance Forum](https://governance.aave.com/) for asking questions about the protocol or talk about Aave with other peers.
4244

45+
## Getting Started
46+
47+
You can install `@aave/protocol-v2` as an NPM package in your Hardhat, Buidler or Truffle project to import the contracts and interfaces:
48+
49+
`npm install @aave/protocol-v2`
50+
51+
Import at Solidity files:
52+
53+
```
54+
import {ILendingPool} from "@aave/protocol-v2/contracts/interfaces/ILendingPool.sol";
55+
56+
contract Misc {
57+
58+
function deposit(address pool, address token, address user, uint256 amount) public {
59+
ILendingPool(pool).deposit(token, amount, user, 0);
60+
{...}
61+
}
62+
}
63+
```
64+
65+
The JSON artifacts with the ABI and Bytecode are also included into the bundled NPM package at `artifacts/` directory.
66+
67+
Import JSON file via Node JS `require`:
68+
69+
```
70+
const LendingPoolV2Artifact = require('@aave/protocol-v2/artifacts/contracts/protocol/lendingpool/LendingPool.sol/LendingPool.json');
71+
72+
// Log the ABI into console
73+
console.log(LendingPoolV2Artifact.abi)
74+
```
75+
4376
## Setup
4477

4578
The repository uses Docker Compose to manage sensitive keys and load the configuration. Prior any action like test or deploy, you must run `docker-compose up` to start the `contracts-env` container, and then connect to the container console via `docker-compose exec contracts-env bash`.

aave-v2-whitepaper.pdf

-1 Bytes
Binary file not shown.

contracts/adapters/BaseUniswapAdapter.sol

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {IBaseUniswapAdapter} from './interfaces/IBaseUniswapAdapter.sol';
2424
abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapter, Ownable {
2525
using SafeMath for uint256;
2626
using PercentageMath for uint256;
27-
2827
using SafeERC20 for IERC20;
2928

3029
// Max slippage percent allowed
@@ -349,13 +348,16 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
349348

350349
if (reserveIn == reserveOut) {
351350
uint256 reserveDecimals = _getDecimals(reserveIn);
351+
address[] memory path = new address[](1);
352+
path[0] = reserveIn;
353+
352354
return
353355
AmountCalc(
354356
finalAmountIn,
355357
finalAmountIn.mul(10**18).div(amountIn),
356358
_calcUsdValue(reserveIn, amountIn, reserveDecimals),
357359
_calcUsdValue(reserveIn, finalAmountIn, reserveDecimals),
358-
[reserveIn]
360+
path
359361
);
360362
}
361363

@@ -437,13 +439,16 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
437439
// Add flash loan fee
438440
uint256 amountIn = amountOut.add(amountOut.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000));
439441
uint256 reserveDecimals = _getDecimals(reserveIn);
442+
address[] memory path = new address[](1);
443+
path[0] = reserveIn;
444+
440445
return
441446
AmountCalc(
442447
amountIn,
443448
amountOut.mul(10**18).div(amountIn),
444449
_calcUsdValue(reserveIn, amountIn, reserveDecimals),
445450
_calcUsdValue(reserveIn, amountOut, reserveDecimals),
446-
[reserveIn]
451+
path
447452
);
448453
}
449454

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// SPDX-License-Identifier: agpl-3.0
2+
pragma solidity 0.6.12;
3+
pragma experimental ABIEncoderV2;
4+
5+
import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
6+
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
7+
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
8+
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
9+
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
10+
import {Helpers} from '../protocol/libraries/helpers/Helpers.sol';
11+
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
12+
import {IAToken} from '../interfaces/IAToken.sol';
13+
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
14+
15+
/**
16+
* @title UniswapLiquiditySwapAdapter
17+
* @notice Uniswap V2 Adapter to swap liquidity.
18+
* @author Aave
19+
**/
20+
contract FlashLiquidationAdapter is BaseUniswapAdapter {
21+
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
22+
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
23+
24+
struct LiquidationParams {
25+
address collateralAsset;
26+
address borrowedAsset;
27+
address user;
28+
uint256 debtToCover;
29+
bool useEthPath;
30+
}
31+
32+
struct LiquidationCallLocalVars {
33+
uint256 initFlashBorrowedBalance;
34+
uint256 diffFlashBorrowedBalance;
35+
uint256 initCollateralBalance;
36+
uint256 diffCollateralBalance;
37+
uint256 flashLoanDebt;
38+
uint256 soldAmount;
39+
uint256 remainingTokens;
40+
uint256 borrowedAssetLeftovers;
41+
}
42+
43+
constructor(
44+
ILendingPoolAddressesProvider addressesProvider,
45+
IUniswapV2Router02 uniswapRouter,
46+
address wethAddress
47+
) public BaseUniswapAdapter(addressesProvider, uniswapRouter, wethAddress) {}
48+
49+
/**
50+
* @dev Liquidate a non-healthy position collateral-wise, with a Health Factor below 1, using Flash Loan and Uniswap to repay flash loan premium.
51+
* - The caller (liquidator) with a flash loan covers `debtToCover` amount of debt of the user getting liquidated, and receives
52+
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk minus the flash loan premium.
53+
* @param assets Address of asset to be swapped
54+
* @param amounts Amount of the asset to be swapped
55+
* @param premiums Fee of the flash loan
56+
* @param initiator Address of the caller
57+
* @param params Additional variadic field to include extra params. Expected parameters:
58+
* address collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
59+
* address borrowedAsset The asset that must be covered
60+
* address user The user address with a Health Factor below 1
61+
* uint256 debtToCover The amount of debt to cover
62+
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
63+
*/
64+
function executeOperation(
65+
address[] calldata assets,
66+
uint256[] calldata amounts,
67+
uint256[] calldata premiums,
68+
address initiator,
69+
bytes calldata params
70+
) external override returns (bool) {
71+
require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');
72+
73+
LiquidationParams memory decodedParams = _decodeParams(params);
74+
75+
require(assets.length == 1 && assets[0] == decodedParams.borrowedAsset, 'INCONSISTENT_PARAMS');
76+
77+
_liquidateAndSwap(
78+
decodedParams.collateralAsset,
79+
decodedParams.borrowedAsset,
80+
decodedParams.user,
81+
decodedParams.debtToCover,
82+
decodedParams.useEthPath,
83+
amounts[0],
84+
premiums[0],
85+
initiator
86+
);
87+
88+
return true;
89+
}
90+
91+
/**
92+
* @dev
93+
* @param collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
94+
* @param borrowedAsset The asset that must be covered
95+
* @param user The user address with a Health Factor below 1
96+
* @param debtToCover The amount of debt to coverage, can be max(-1) to liquidate all possible debt
97+
* @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
98+
* @param flashBorrowedAmount Amount of asset requested at the flash loan to liquidate the user position
99+
* @param premium Fee of the requested flash loan
100+
* @param initiator Address of the caller
101+
*/
102+
function _liquidateAndSwap(
103+
address collateralAsset,
104+
address borrowedAsset,
105+
address user,
106+
uint256 debtToCover,
107+
bool useEthPath,
108+
uint256 flashBorrowedAmount,
109+
uint256 premium,
110+
address initiator
111+
) internal {
112+
LiquidationCallLocalVars memory vars;
113+
vars.initCollateralBalance = IERC20(collateralAsset).balanceOf(address(this));
114+
if (collateralAsset != borrowedAsset) {
115+
vars.initFlashBorrowedBalance = IERC20(borrowedAsset).balanceOf(address(this));
116+
117+
// Track leftover balance to rescue funds in case of external transfers into this contract
118+
vars.borrowedAssetLeftovers = vars.initFlashBorrowedBalance.sub(flashBorrowedAmount);
119+
}
120+
vars.flashLoanDebt = flashBorrowedAmount.add(premium);
121+
122+
// Approve LendingPool to use debt token for liquidation
123+
IERC20(borrowedAsset).approve(address(LENDING_POOL), debtToCover);
124+
125+
// Liquidate the user position and release the underlying collateral
126+
LENDING_POOL.liquidationCall(collateralAsset, borrowedAsset, user, debtToCover, false);
127+
128+
// Discover the liquidated tokens
129+
uint256 collateralBalanceAfter = IERC20(collateralAsset).balanceOf(address(this));
130+
131+
// Track only collateral released, not current asset balance of the contract
132+
vars.diffCollateralBalance = collateralBalanceAfter.sub(vars.initCollateralBalance);
133+
134+
if (collateralAsset != borrowedAsset) {
135+
// Discover flash loan balance after the liquidation
136+
uint256 flashBorrowedAssetAfter = IERC20(borrowedAsset).balanceOf(address(this));
137+
138+
// Use only flash loan borrowed assets, not current asset balance of the contract
139+
vars.diffFlashBorrowedBalance = flashBorrowedAssetAfter.sub(vars.borrowedAssetLeftovers);
140+
141+
// Swap released collateral into the debt asset, to repay the flash loan
142+
vars.soldAmount = _swapTokensForExactTokens(
143+
collateralAsset,
144+
borrowedAsset,
145+
vars.diffCollateralBalance,
146+
vars.flashLoanDebt.sub(vars.diffFlashBorrowedBalance),
147+
useEthPath
148+
);
149+
vars.remainingTokens = vars.diffCollateralBalance.sub(vars.soldAmount);
150+
} else {
151+
vars.remainingTokens = vars.diffCollateralBalance.sub(premium);
152+
}
153+
154+
// Allow repay of flash loan
155+
IERC20(borrowedAsset).approve(address(LENDING_POOL), vars.flashLoanDebt);
156+
157+
// Transfer remaining tokens to initiator
158+
if (vars.remainingTokens > 0) {
159+
IERC20(collateralAsset).transfer(initiator, vars.remainingTokens);
160+
}
161+
}
162+
163+
/**
164+
* @dev Decodes the information encoded in the flash loan params
165+
* @param params Additional variadic field to include extra params. Expected parameters:
166+
* address collateralAsset The collateral asset to claim
167+
* address borrowedAsset The asset that must be covered and will be exchanged to pay the flash loan premium
168+
* address user The user address with a Health Factor below 1
169+
* uint256 debtToCover The amount of debt to cover
170+
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
171+
* @return LiquidationParams struct containing decoded params
172+
*/
173+
function _decodeParams(bytes memory params) internal pure returns (LiquidationParams memory) {
174+
(
175+
address collateralAsset,
176+
address borrowedAsset,
177+
address user,
178+
uint256 debtToCover,
179+
bool useEthPath
180+
) = abi.decode(params, (address, address, address, uint256, bool));
181+
182+
return LiquidationParams(collateralAsset, borrowedAsset, user, debtToCover, useEthPath);
183+
}
184+
}

contracts/adapters/UniswapRepayAdapter.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
234234
* uint8 v V param for the permit signature
235235
* bytes32 r R param for the permit signature
236236
* bytes32 s S param for the permit signature
237+
* bool useEthPath use WETH path route
237238
* @return RepayParams struct containing decoded params
238239
*/
239240
function _decodeParams(bytes memory params) internal pure returns (RepayParams memory) {

0 commit comments

Comments
 (0)