Skip to content

Commit

Permalink
Merge pull request #23 from aave/gitlab-merge
Browse files Browse the repository at this point in the history
Bring GitHub up to date with GitLab
  • Loading branch information
eboadom authored Feb 5, 2021
2 parents de6437b + 32ddc01 commit 2708551
Show file tree
Hide file tree
Showing 71 changed files with 3,594 additions and 3,970 deletions.
52 changes: 51 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
stages:
- checks
- prepare
- publish

variables:
IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}

lint:
stage: checks
tags:
- aave-build-runner
before_script:
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml build
script:
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run prettier:check
after_script:
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down

test:
stage: checks
Expand All @@ -12,7 +29,9 @@ test:
after_script:
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down

only:
- master
- merge_requests
deploy-mainnet-fork:
tags:
- aave-build-runner
Expand All @@ -24,6 +43,9 @@ deploy-mainnet-fork:
after_script:
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml run contracts-env npm run ci:clean
- docker-compose -p ${CI_JOB_ID} -f docker-compose.test.yml down
only:
- master
- merge_requests

certora-test:
stage: checks
Expand All @@ -40,3 +62,31 @@ certora-test:
- certoraRun specs/harness/StableDebtTokenHarness.sol:StableDebtTokenHarness --solc_args "['--optimize']" --verify StableDebtTokenHarness:specs/StableDebtToken.spec --settings -assumeUnwindCond,-b=4 --cache StableDebtToken --cloud
- certoraRun specs/harness/UserConfigurationHarness.sol --verify UserConfigurationHarness:specs/UserConfiguration.spec --solc_args "['--optimize']" --settings -useBitVectorTheory --cache UserConfiguration --cloud
- 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
only:
- master
- merge_requests

prepare:
stage: prepare
tags:
- docker-builder
script:
- docker build -t ${IMAGE} .
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
- docker push ${IMAGE}
only:
- master

publish:
image: ${IMAGE}
tags:
- docker
stage: publish
script:
- npm ci
- echo //registry.npmjs.org/:_authToken=${NPM_V2_PACKAGES_TOKEN} > .npmrc
- npm run compile
- ${VERSION}
- npm publish --access public
only:
- master
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,37 @@ A more detailed and technical description of the protocol can be found in this r

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.

## Getting Started

You can install `@aave/protocol-v2` as an NPM package in your Hardhat, Buidler or Truffle project to import the contracts and interfaces:

`npm install @aave/protocol-v2`

Import at Solidity files:

```
import {ILendingPool} from "@aave/protocol-v2/contracts/interfaces/ILendingPool.sol";
contract Misc {
function deposit(address pool, address token, address user, uint256 amount) {
ILendingPool(pool).deposit(token, amount, user, '0');
{...}
}
}
```

The JSON artifacts with the ABI and Bytecode are also included into the bundled NPM package at `artifacts/` directory.

Import JSON file via Node JS `require`:

```
const LendingPoolV2Artifact = require('@aave/protocol-v2/artifacts/contracts/protocol/lendingpool/LendingPool.sol/LendingPool.json');
// Log the ABI into console
console.log(LendingPoolV2Artifact.abi)
```

## Setup

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`.
Expand Down
16 changes: 9 additions & 7 deletions contracts/adapters/BaseUniswapAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {IBaseUniswapAdapter} from './interfaces/IBaseUniswapAdapter.sol';
abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapter, Ownable {
using SafeMath for uint256;
using PercentageMath for uint256;

using SafeERC20 for IERC20;

// Max slippage percent allowed
Expand Down Expand Up @@ -349,15 +348,16 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt

if (reserveIn == reserveOut) {
uint256 reserveDecimals = _getDecimals(reserveIn);
address[] memory _reserveIn = new address[](1);
_reserveIn[0] = reserveIn;
address[] memory path = new address[](1);
path[0] = reserveIn;

return
AmountCalc(
finalAmountIn,
finalAmountIn.mul(10**18).div(amountIn),
_calcUsdValue(reserveIn, amountIn, reserveDecimals),
_calcUsdValue(reserveIn, finalAmountIn, reserveDecimals),
_reserveIn
path
);
}

Expand Down Expand Up @@ -386,6 +386,7 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
}

uint256 bestAmountOut;

try UNISWAP_ROUTER.getAmountsOut(finalAmountIn, simplePath) returns (
uint256[] memory resultAmounts
) {
Expand Down Expand Up @@ -439,15 +440,16 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
// Add flash loan fee
uint256 amountIn = amountOut.add(amountOut.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000));
uint256 reserveDecimals = _getDecimals(reserveIn);
address[] memory _reserveIn = new address[](1);
_reserveIn[0] = reserveIn;
address[] memory path = new address[](1);
path[0] = reserveIn;

return
AmountCalc(
amountIn,
amountOut.mul(10**18).div(amountIn),
_calcUsdValue(reserveIn, amountIn, reserveDecimals),
_calcUsdValue(reserveIn, amountOut, reserveDecimals),
_reserveIn
path
);
}

Expand Down
184 changes: 184 additions & 0 deletions contracts/adapters/FlashLiquidationAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
import {Helpers} from '../protocol/libraries/helpers/Helpers.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {IAToken} from '../interfaces/IAToken.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';

/**
* @title UniswapLiquiditySwapAdapter
* @notice Uniswap V2 Adapter to swap liquidity.
* @author Aave
**/
contract FlashLiquidationAdapter is BaseUniswapAdapter {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;

struct LiquidationParams {
address collateralAsset;
address borrowedAsset;
address user;
uint256 debtToCover;
bool useEthPath;
}

struct LiquidationCallLocalVars {
uint256 initFlashBorrowedBalance;
uint256 diffFlashBorrowedBalance;
uint256 initCollateralBalance;
uint256 diffCollateralBalance;
uint256 flashLoanDebt;
uint256 soldAmount;
uint256 remainingTokens;
uint256 borrowedAssetLeftovers;
}

constructor(
ILendingPoolAddressesProvider addressesProvider,
IUniswapV2Router02 uniswapRouter,
address wethAddress
) public BaseUniswapAdapter(addressesProvider, uniswapRouter, wethAddress) {}

/**
* @dev Liquidate a non-healthy position collateral-wise, with a Health Factor below 1, using Flash Loan and Uniswap to repay flash loan premium.
* - The caller (liquidator) with a flash loan covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk minus the flash loan premium.
* @param assets Address of asset to be swapped
* @param amounts Amount of the asset to be swapped
* @param premiums Fee of the flash loan
* @param initiator Address of the caller
* @param params Additional variadic field to include extra params. Expected parameters:
* address collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
* address borrowedAsset The asset that must be covered
* address user The user address with a Health Factor below 1
* uint256 debtToCover The amount of debt to cover
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
*/
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');

LiquidationParams memory decodedParams = _decodeParams(params);

require(assets.length == 1 && assets[0] == decodedParams.borrowedAsset, 'INCONSISTENT_PARAMS');

_liquidateAndSwap(
decodedParams.collateralAsset,
decodedParams.borrowedAsset,
decodedParams.user,
decodedParams.debtToCover,
decodedParams.useEthPath,
amounts[0],
premiums[0],
initiator
);

return true;
}

/**
* @dev
* @param collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
* @param borrowedAsset The asset that must be covered
* @param user The user address with a Health Factor below 1
* @param debtToCover The amount of debt to coverage, can be max(-1) to liquidate all possible debt
* @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
* @param flashBorrowedAmount Amount of asset requested at the flash loan to liquidate the user position
* @param premium Fee of the requested flash loan
* @param initiator Address of the caller
*/
function _liquidateAndSwap(
address collateralAsset,
address borrowedAsset,
address user,
uint256 debtToCover,
bool useEthPath,
uint256 flashBorrowedAmount,
uint256 premium,
address initiator
) internal {
LiquidationCallLocalVars memory vars;
vars.initCollateralBalance = IERC20(collateralAsset).balanceOf(address(this));
if (collateralAsset != borrowedAsset) {
vars.initFlashBorrowedBalance = IERC20(borrowedAsset).balanceOf(address(this));

// Track leftover balance to rescue funds in case of external transfers into this contract
vars.borrowedAssetLeftovers = vars.initFlashBorrowedBalance.sub(flashBorrowedAmount);
}
vars.flashLoanDebt = flashBorrowedAmount.add(premium);

// Approve LendingPool to use debt token for liquidation
IERC20(borrowedAsset).approve(address(LENDING_POOL), debtToCover);

// Liquidate the user position and release the underlying collateral
LENDING_POOL.liquidationCall(collateralAsset, borrowedAsset, user, debtToCover, false);

// Discover the liquidated tokens
uint256 collateralBalanceAfter = IERC20(collateralAsset).balanceOf(address(this));

// Track only collateral released, not current asset balance of the contract
vars.diffCollateralBalance = collateralBalanceAfter.sub(vars.initCollateralBalance);

if (collateralAsset != borrowedAsset) {
// Discover flash loan balance after the liquidation
uint256 flashBorrowedAssetAfter = IERC20(borrowedAsset).balanceOf(address(this));

// Use only flash loan borrowed assets, not current asset balance of the contract
vars.diffFlashBorrowedBalance = flashBorrowedAssetAfter.sub(vars.borrowedAssetLeftovers);

// Swap released collateral into the debt asset, to repay the flash loan
vars.soldAmount = _swapTokensForExactTokens(
collateralAsset,
borrowedAsset,
vars.diffCollateralBalance,
vars.flashLoanDebt.sub(vars.diffFlashBorrowedBalance),
useEthPath
);
vars.remainingTokens = vars.diffCollateralBalance.sub(vars.soldAmount);
} else {
vars.remainingTokens = vars.diffCollateralBalance.sub(premium);
}

// Allow repay of flash loan
IERC20(borrowedAsset).approve(address(LENDING_POOL), vars.flashLoanDebt);

// Transfer remaining tokens to initiator
if (vars.remainingTokens > 0) {
IERC20(collateralAsset).transfer(initiator, vars.remainingTokens);
}
}

/**
* @dev Decodes the information encoded in the flash loan params
* @param params Additional variadic field to include extra params. Expected parameters:
* address collateralAsset The collateral asset to claim
* address borrowedAsset The asset that must be covered and will be exchanged to pay the flash loan premium
* address user The user address with a Health Factor below 1
* uint256 debtToCover The amount of debt to cover
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
* @return LiquidationParams struct containing decoded params
*/
function _decodeParams(bytes memory params) internal pure returns (LiquidationParams memory) {
(
address collateralAsset,
address borrowedAsset,
address user,
uint256 debtToCover,
bool useEthPath
) = abi.decode(params, (address, address, address, uint256, bool));

return LiquidationParams(collateralAsset, borrowedAsset, user, debtToCover, useEthPath);
}
}
1 change: 1 addition & 0 deletions contracts/adapters/UniswapRepayAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
* uint8 v V param for the permit signature
* bytes32 r R param for the permit signature
* bytes32 s S param for the permit signature
* bool useEthPath use WETH path route
* @return RepayParams struct containing decoded params
*/
function _decodeParams(bytes memory params) internal pure returns (RepayParams memory) {
Expand Down
4 changes: 2 additions & 2 deletions contracts/dependencies/openzeppelin/contracts/Context.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ pragma solidity 0.6.12;
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal virtual view returns (address payable) {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}

function _msgData() internal virtual view returns (bytes memory) {
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
Expand Down
Loading

0 comments on commit 2708551

Please sign in to comment.