mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Pulled contracts for light deployment
This commit is contained in:
parent
5146efbaec
commit
b4d72bfc37
534
contracts/adapters/BaseUniswapAdapter.sol
Normal file
534
contracts/adapters/BaseUniswapAdapter.sol
Normal file
|
@ -0,0 +1,534 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
|
||||
import {SafeMath} from '../dependencies/openzeppelin/contracts/SafeMath.sol';
|
||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
||||
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
|
||||
import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol';
|
||||
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
||||
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
|
||||
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
|
||||
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
||||
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
||||
import {FlashLoanReceiverBase} from '../flashloan/base/FlashLoanReceiverBase.sol';
|
||||
import {IBaseUniswapAdapter} from './interfaces/IBaseUniswapAdapter.sol';
|
||||
|
||||
/**
|
||||
* @title BaseUniswapAdapter
|
||||
* @notice Implements the logic for performing assets swaps in Uniswap V2
|
||||
* @author Aave
|
||||
**/
|
||||
abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapter, Ownable {
|
||||
using SafeMath for uint256;
|
||||
using PercentageMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
// Max slippage percent allowed
|
||||
uint256 public constant override MAX_SLIPPAGE_PERCENT = 3000; // 30%
|
||||
// FLash Loan fee set in lending pool
|
||||
uint256 public constant override FLASHLOAN_PREMIUM_TOTAL = 9;
|
||||
// USD oracle asset address
|
||||
address public constant override USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
|
||||
|
||||
address public immutable override WETH_ADDRESS;
|
||||
IPriceOracleGetter public immutable override ORACLE;
|
||||
IUniswapV2Router02 public immutable override UNISWAP_ROUTER;
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter,
|
||||
address wethAddress
|
||||
) public FlashLoanReceiverBase(addressesProvider) {
|
||||
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
||||
UNISWAP_ROUTER = uniswapRouter;
|
||||
WETH_ADDRESS = wethAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Given an input asset amount, returns the maximum output amount of the other asset and the prices
|
||||
* @param amountIn Amount of reserveIn
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @return uint256 Amount out of the reserveOut
|
||||
* @return uint256 The price of out amount denominated in the reserveIn currency (18 decimals)
|
||||
* @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
*/
|
||||
function getAmountsOut(
|
||||
uint256 amountIn,
|
||||
address reserveIn,
|
||||
address reserveOut
|
||||
)
|
||||
external
|
||||
view
|
||||
override
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
address[] memory
|
||||
)
|
||||
{
|
||||
AmountCalc memory results = _getAmountsOutData(reserveIn, reserveOut, amountIn);
|
||||
|
||||
return (
|
||||
results.calculatedAmount,
|
||||
results.relativePrice,
|
||||
results.amountInUsd,
|
||||
results.amountOutUsd,
|
||||
results.path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the minimum input asset amount required to buy the given output asset amount and the prices
|
||||
* @param amountOut Amount of reserveOut
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @return uint256 Amount in of the reserveIn
|
||||
* @return uint256 The price of in amount denominated in the reserveOut currency (18 decimals)
|
||||
* @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
*/
|
||||
function getAmountsIn(
|
||||
uint256 amountOut,
|
||||
address reserveIn,
|
||||
address reserveOut
|
||||
)
|
||||
external
|
||||
view
|
||||
override
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
address[] memory
|
||||
)
|
||||
{
|
||||
AmountCalc memory results = _getAmountsInData(reserveIn, reserveOut, amountOut);
|
||||
|
||||
return (
|
||||
results.calculatedAmount,
|
||||
results.relativePrice,
|
||||
results.amountInUsd,
|
||||
results.amountOutUsd,
|
||||
results.path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps an exact `amountToSwap` of an asset to another
|
||||
* @param assetToSwapFrom Origin asset
|
||||
* @param assetToSwapTo Destination asset
|
||||
* @param amountToSwap Exact amount of `assetToSwapFrom` to be swapped
|
||||
* @param minAmountOut the min amount of `assetToSwapTo` to be received from the swap
|
||||
* @return the amount received from the swap
|
||||
*/
|
||||
function _swapExactTokensForTokens(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo,
|
||||
uint256 amountToSwap,
|
||||
uint256 minAmountOut,
|
||||
bool useEthPath
|
||||
) internal returns (uint256) {
|
||||
uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
|
||||
|
||||
uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
|
||||
uint256 toAssetPrice = _getPrice(assetToSwapTo);
|
||||
|
||||
uint256 expectedMinAmountOut =
|
||||
amountToSwap
|
||||
.mul(fromAssetPrice.mul(10**toAssetDecimals))
|
||||
.div(toAssetPrice.mul(10**fromAssetDecimals))
|
||||
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(MAX_SLIPPAGE_PERCENT));
|
||||
|
||||
require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage');
|
||||
|
||||
// Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
|
||||
IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), 0);
|
||||
IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), amountToSwap);
|
||||
|
||||
address[] memory path;
|
||||
if (useEthPath) {
|
||||
path = new address[](3);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = WETH_ADDRESS;
|
||||
path[2] = assetToSwapTo;
|
||||
} else {
|
||||
path = new address[](2);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = assetToSwapTo;
|
||||
}
|
||||
uint256[] memory amounts =
|
||||
UNISWAP_ROUTER.swapExactTokensForTokens(
|
||||
amountToSwap,
|
||||
minAmountOut,
|
||||
path,
|
||||
address(this),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[amounts.length - 1]);
|
||||
|
||||
return amounts[amounts.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Receive an exact amount `amountToReceive` of `assetToSwapTo` tokens for as few `assetToSwapFrom` tokens as
|
||||
* possible.
|
||||
* @param assetToSwapFrom Origin asset
|
||||
* @param assetToSwapTo Destination asset
|
||||
* @param maxAmountToSwap Max amount of `assetToSwapFrom` allowed to be swapped
|
||||
* @param amountToReceive Exact amount of `assetToSwapTo` to receive
|
||||
* @return the amount swapped
|
||||
*/
|
||||
function _swapTokensForExactTokens(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo,
|
||||
uint256 maxAmountToSwap,
|
||||
uint256 amountToReceive,
|
||||
bool useEthPath
|
||||
) internal returns (uint256) {
|
||||
uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
|
||||
|
||||
uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
|
||||
uint256 toAssetPrice = _getPrice(assetToSwapTo);
|
||||
|
||||
uint256 expectedMaxAmountToSwap =
|
||||
amountToReceive
|
||||
.mul(toAssetPrice.mul(10**fromAssetDecimals))
|
||||
.div(fromAssetPrice.mul(10**toAssetDecimals))
|
||||
.percentMul(PercentageMath.PERCENTAGE_FACTOR.add(MAX_SLIPPAGE_PERCENT));
|
||||
|
||||
require(maxAmountToSwap < expectedMaxAmountToSwap, 'maxAmountToSwap exceed max slippage');
|
||||
|
||||
// Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
|
||||
IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), 0);
|
||||
IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), maxAmountToSwap);
|
||||
|
||||
address[] memory path;
|
||||
if (useEthPath) {
|
||||
path = new address[](3);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = WETH_ADDRESS;
|
||||
path[2] = assetToSwapTo;
|
||||
} else {
|
||||
path = new address[](2);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = assetToSwapTo;
|
||||
}
|
||||
|
||||
uint256[] memory amounts =
|
||||
UNISWAP_ROUTER.swapTokensForExactTokens(
|
||||
amountToReceive,
|
||||
maxAmountToSwap,
|
||||
path,
|
||||
address(this),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[amounts.length - 1]);
|
||||
|
||||
return amounts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the price of the asset from the oracle denominated in eth
|
||||
* @param asset address
|
||||
* @return eth price for the asset
|
||||
*/
|
||||
function _getPrice(address asset) internal view returns (uint256) {
|
||||
return ORACLE.getAssetPrice(asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the decimals of an asset
|
||||
* @return number of decimals of the asset
|
||||
*/
|
||||
function _getDecimals(address asset) internal view returns (uint256) {
|
||||
return IERC20Detailed(asset).decimals();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the aToken associated to the asset
|
||||
* @return address of the aToken
|
||||
*/
|
||||
function _getReserveData(address asset) internal view returns (DataTypes.ReserveData memory) {
|
||||
return LENDING_POOL.getReserveData(asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pull the ATokens from the user
|
||||
* @param reserve address of the asset
|
||||
* @param reserveAToken address of the aToken of the reserve
|
||||
* @param user address
|
||||
* @param amount of tokens to be transferred to the contract
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function _pullAToken(
|
||||
address reserve,
|
||||
address reserveAToken,
|
||||
address user,
|
||||
uint256 amount,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
if (_usePermit(permitSignature)) {
|
||||
IERC20WithPermit(reserveAToken).permit(
|
||||
user,
|
||||
address(this),
|
||||
permitSignature.amount,
|
||||
permitSignature.deadline,
|
||||
permitSignature.v,
|
||||
permitSignature.r,
|
||||
permitSignature.s
|
||||
);
|
||||
}
|
||||
|
||||
// transfer from user to adapter
|
||||
IERC20(reserveAToken).safeTransferFrom(user, address(this), amount);
|
||||
|
||||
// withdraw reserve
|
||||
LENDING_POOL.withdraw(reserve, amount, address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells if the permit method should be called by inspecting if there is a valid signature.
|
||||
* If signature params are set to 0, then permit won't be called.
|
||||
* @param signature struct containing the permit signature
|
||||
* @return whether or not permit should be called
|
||||
*/
|
||||
function _usePermit(PermitSignature memory signature) internal pure returns (bool) {
|
||||
return
|
||||
!(uint256(signature.deadline) == uint256(signature.v) && uint256(signature.deadline) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the value denominated in USD
|
||||
* @param reserve Address of the reserve
|
||||
* @param amount Amount of the reserve
|
||||
* @param decimals Decimals of the reserve
|
||||
* @return whether or not permit should be called
|
||||
*/
|
||||
function _calcUsdValue(
|
||||
address reserve,
|
||||
uint256 amount,
|
||||
uint256 decimals
|
||||
) internal view returns (uint256) {
|
||||
uint256 ethUsdPrice = _getPrice(USD_ADDRESS);
|
||||
uint256 reservePrice = _getPrice(reserve);
|
||||
|
||||
return amount.mul(reservePrice).div(10**decimals).mul(ethUsdPrice).div(10**18);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Given an input asset amount, returns the maximum output amount of the other asset
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @param amountIn Amount of reserveIn
|
||||
* @return Struct containing the following information:
|
||||
* uint256 Amount out of the reserveOut
|
||||
* uint256 The price of out amount denominated in the reserveIn currency (18 decimals)
|
||||
* uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
*/
|
||||
function _getAmountsOutData(
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountIn
|
||||
) internal view returns (AmountCalc memory) {
|
||||
// Subtract flash loan fee
|
||||
uint256 finalAmountIn = amountIn.sub(amountIn.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000));
|
||||
|
||||
address[] memory simplePath = new address[](2);
|
||||
simplePath[0] = reserveIn;
|
||||
simplePath[1] = reserveOut;
|
||||
|
||||
uint256[] memory amountsWithoutWeth;
|
||||
uint256[] memory amountsWithWeth;
|
||||
|
||||
address[] memory pathWithWeth = new address[](3);
|
||||
if (reserveIn != WETH_ADDRESS && reserveOut != WETH_ADDRESS) {
|
||||
pathWithWeth[0] = reserveIn;
|
||||
pathWithWeth[1] = WETH_ADDRESS;
|
||||
pathWithWeth[2] = reserveOut;
|
||||
|
||||
try UNISWAP_ROUTER.getAmountsOut(finalAmountIn, pathWithWeth) returns (
|
||||
uint256[] memory resultsWithWeth
|
||||
) {
|
||||
amountsWithWeth = resultsWithWeth;
|
||||
} catch {
|
||||
amountsWithWeth = new uint256[](3);
|
||||
}
|
||||
} else {
|
||||
amountsWithWeth = new uint256[](3);
|
||||
}
|
||||
|
||||
uint256 bestAmountOut;
|
||||
try UNISWAP_ROUTER.getAmountsOut(finalAmountIn, simplePath) returns (
|
||||
uint256[] memory resultAmounts
|
||||
) {
|
||||
amountsWithoutWeth = resultAmounts;
|
||||
|
||||
bestAmountOut = (amountsWithWeth[2] > amountsWithoutWeth[1])
|
||||
? amountsWithWeth[2]
|
||||
: amountsWithoutWeth[1];
|
||||
} catch {
|
||||
amountsWithoutWeth = new uint256[](2);
|
||||
bestAmountOut = amountsWithWeth[2];
|
||||
}
|
||||
|
||||
uint256 reserveInDecimals = _getDecimals(reserveIn);
|
||||
uint256 reserveOutDecimals = _getDecimals(reserveOut);
|
||||
|
||||
uint256 outPerInPrice =
|
||||
finalAmountIn.mul(10**18).mul(10**reserveOutDecimals).div(
|
||||
bestAmountOut.mul(10**reserveInDecimals)
|
||||
);
|
||||
|
||||
return
|
||||
AmountCalc(
|
||||
bestAmountOut,
|
||||
outPerInPrice,
|
||||
_calcUsdValue(reserveIn, amountIn, reserveInDecimals),
|
||||
_calcUsdValue(reserveOut, bestAmountOut, reserveOutDecimals),
|
||||
(bestAmountOut == 0) ? new address[](2) : (bestAmountOut == amountsWithoutWeth[1])
|
||||
? simplePath
|
||||
: pathWithWeth
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the minimum input asset amount required to buy the given output asset amount
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @param amountOut Amount of reserveOut
|
||||
* @return Struct containing the following information:
|
||||
* uint256 Amount in of the reserveIn
|
||||
* uint256 The price of in amount denominated in the reserveOut currency (18 decimals)
|
||||
* uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
*/
|
||||
function _getAmountsInData(
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountOut
|
||||
) internal view returns (AmountCalc memory) {
|
||||
(uint256[] memory amounts, address[] memory path) =
|
||||
_getAmountsInAndPath(reserveIn, reserveOut, amountOut);
|
||||
|
||||
// Add flash loan fee
|
||||
uint256 finalAmountIn = amounts[0].add(amounts[0].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000));
|
||||
|
||||
uint256 reserveInDecimals = _getDecimals(reserveIn);
|
||||
uint256 reserveOutDecimals = _getDecimals(reserveOut);
|
||||
|
||||
uint256 inPerOutPrice =
|
||||
amountOut.mul(10**18).mul(10**reserveInDecimals).div(
|
||||
finalAmountIn.mul(10**reserveOutDecimals)
|
||||
);
|
||||
|
||||
return
|
||||
AmountCalc(
|
||||
finalAmountIn,
|
||||
inPerOutPrice,
|
||||
_calcUsdValue(reserveIn, finalAmountIn, reserveInDecimals),
|
||||
_calcUsdValue(reserveOut, amountOut, reserveOutDecimals),
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the input asset amount required to buy the given output asset amount
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @param amountOut Amount of reserveOut
|
||||
* @return uint256[] amounts Array containing the amountIn and amountOut for a swap
|
||||
*/
|
||||
function _getAmountsInAndPath(
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountOut
|
||||
) internal view returns (uint256[] memory, address[] memory) {
|
||||
address[] memory simplePath = new address[](2);
|
||||
simplePath[0] = reserveIn;
|
||||
simplePath[1] = reserveOut;
|
||||
|
||||
uint256[] memory amountsWithoutWeth;
|
||||
uint256[] memory amountsWithWeth;
|
||||
address[] memory pathWithWeth = new address[](3);
|
||||
|
||||
if (reserveIn != WETH_ADDRESS && reserveOut != WETH_ADDRESS) {
|
||||
pathWithWeth[0] = reserveIn;
|
||||
pathWithWeth[1] = WETH_ADDRESS;
|
||||
pathWithWeth[2] = reserveOut;
|
||||
|
||||
try UNISWAP_ROUTER.getAmountsIn(amountOut, pathWithWeth) returns (
|
||||
uint256[] memory resultsWithWeth
|
||||
) {
|
||||
amountsWithWeth = resultsWithWeth;
|
||||
} catch {
|
||||
amountsWithWeth = new uint256[](3);
|
||||
}
|
||||
} else {
|
||||
amountsWithWeth = new uint256[](3);
|
||||
}
|
||||
|
||||
try UNISWAP_ROUTER.getAmountsIn(amountOut, simplePath) returns (
|
||||
uint256[] memory resultAmounts
|
||||
) {
|
||||
amountsWithoutWeth = resultAmounts;
|
||||
|
||||
return
|
||||
(amountsWithWeth[0] < amountsWithoutWeth[0] && amountsWithWeth[0] != 0)
|
||||
? (amountsWithWeth, pathWithWeth)
|
||||
: (amountsWithoutWeth, simplePath);
|
||||
} catch {
|
||||
return (amountsWithWeth, pathWithWeth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the input asset amount required to buy the given output asset amount
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @param amountOut Amount of reserveOut
|
||||
* @return uint256[] amounts Array containing the amountIn and amountOut for a swap
|
||||
*/
|
||||
function _getAmountsIn(
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountOut,
|
||||
bool useEthPath
|
||||
) internal view returns (uint256[] memory) {
|
||||
address[] memory path;
|
||||
|
||||
if (useEthPath) {
|
||||
path = new address[](3);
|
||||
path[0] = reserveIn;
|
||||
path[1] = WETH_ADDRESS;
|
||||
path[2] = reserveOut;
|
||||
} else {
|
||||
path = new address[](2);
|
||||
path[0] = reserveIn;
|
||||
path[1] = reserveOut;
|
||||
}
|
||||
|
||||
return UNISWAP_ROUTER.getAmountsIn(amountOut, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emergency rescue for token stucked on this contract, as failsafe mechanism
|
||||
* - Funds should never remain in this contract more time than during transactions
|
||||
* - Only callable by the owner
|
||||
**/
|
||||
function rescueTokens(IERC20 token) external onlyOwner {
|
||||
token.transfer(owner(), token.balanceOf(address(this)));
|
||||
}
|
||||
}
|
280
contracts/adapters/UniswapLiquiditySwapAdapter.sol
Normal file
280
contracts/adapters/UniswapLiquiditySwapAdapter.sol
Normal file
|
@ -0,0 +1,280 @@
|
|||
// 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';
|
||||
|
||||
/**
|
||||
* @title UniswapLiquiditySwapAdapter
|
||||
* @notice Uniswap V2 Adapter to swap liquidity.
|
||||
* @author Aave
|
||||
**/
|
||||
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
|
||||
struct PermitParams {
|
||||
uint256[] amount;
|
||||
uint256[] deadline;
|
||||
uint8[] v;
|
||||
bytes32[] r;
|
||||
bytes32[] s;
|
||||
}
|
||||
|
||||
struct SwapParams {
|
||||
address[] assetToSwapToList;
|
||||
uint256[] minAmountsToReceive;
|
||||
bool[] swapAllBalance;
|
||||
PermitParams permitParams;
|
||||
bool[] useEthPath;
|
||||
}
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter,
|
||||
address wethAddress
|
||||
) public BaseUniswapAdapter(addressesProvider, uniswapRouter, wethAddress) {}
|
||||
|
||||
/**
|
||||
* @dev Swaps the received reserve amount from the flash loan into the asset specified in the params.
|
||||
* The received funds from the swap are then deposited into the protocol on behalf of the user.
|
||||
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and
|
||||
* repay the flash loan.
|
||||
* @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 user
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
|
||||
* uint256[] minAmountsToReceive List of min amounts to be received from the swap
|
||||
* bool[] swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* uint256[] permitAmount List of amounts for the permit signature
|
||||
* uint256[] deadline List of deadlines for the permit signature
|
||||
* uint8[] v List of v param for the permit signature
|
||||
* bytes32[] r List of r param for the permit signature
|
||||
* bytes32[] s List of s param for the permit signature
|
||||
*/
|
||||
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');
|
||||
|
||||
SwapParams memory decodedParams = _decodeParams(params);
|
||||
|
||||
require(
|
||||
assets.length == decodedParams.assetToSwapToList.length &&
|
||||
assets.length == decodedParams.minAmountsToReceive.length &&
|
||||
assets.length == decodedParams.swapAllBalance.length &&
|
||||
assets.length == decodedParams.permitParams.amount.length &&
|
||||
assets.length == decodedParams.permitParams.deadline.length &&
|
||||
assets.length == decodedParams.permitParams.v.length &&
|
||||
assets.length == decodedParams.permitParams.r.length &&
|
||||
assets.length == decodedParams.permitParams.s.length &&
|
||||
assets.length == decodedParams.useEthPath.length,
|
||||
'INCONSISTENT_PARAMS'
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
_swapLiquidity(
|
||||
assets[i],
|
||||
decodedParams.assetToSwapToList[i],
|
||||
amounts[i],
|
||||
premiums[i],
|
||||
initiator,
|
||||
decodedParams.minAmountsToReceive[i],
|
||||
decodedParams.swapAllBalance[i],
|
||||
PermitSignature(
|
||||
decodedParams.permitParams.amount[i],
|
||||
decodedParams.permitParams.deadline[i],
|
||||
decodedParams.permitParams.v[i],
|
||||
decodedParams.permitParams.r[i],
|
||||
decodedParams.permitParams.s[i]
|
||||
),
|
||||
decodedParams.useEthPath[i]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SwapAndDepositLocalVars {
|
||||
uint256 i;
|
||||
uint256 aTokenInitiatorBalance;
|
||||
uint256 amountToSwap;
|
||||
uint256 receivedAmount;
|
||||
address aToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps an amount of an asset to another and deposits the new asset amount on behalf of the user without using
|
||||
* a flash loan. This method can be used when the temporary transfer of the collateral asset to this contract
|
||||
* does not affect the user position.
|
||||
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and
|
||||
* perform the swap.
|
||||
* @param assetToSwapFromList List of addresses of the underlying asset to be swap from
|
||||
* @param assetToSwapToList List of addresses of the underlying asset to be swap to and deposited
|
||||
* @param amountToSwapList List of amounts to be swapped. If the amount exceeds the balance, the total balance is used for the swap
|
||||
* @param minAmountsToReceive List of min amounts to be received from the swap
|
||||
* @param permitParams List of struct containing the permit signatures
|
||||
* uint256 permitAmount Amount for the permit signature
|
||||
* uint256 deadline Deadline for the permit signature
|
||||
* uint8 v param for the permit signature
|
||||
* bytes32 r param for the permit signature
|
||||
* bytes32 s param for the permit signature
|
||||
* @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
|
||||
*/
|
||||
function swapAndDeposit(
|
||||
address[] calldata assetToSwapFromList,
|
||||
address[] calldata assetToSwapToList,
|
||||
uint256[] calldata amountToSwapList,
|
||||
uint256[] calldata minAmountsToReceive,
|
||||
PermitSignature[] calldata permitParams,
|
||||
bool[] calldata useEthPath
|
||||
) external {
|
||||
require(
|
||||
assetToSwapFromList.length == assetToSwapToList.length &&
|
||||
assetToSwapFromList.length == amountToSwapList.length &&
|
||||
assetToSwapFromList.length == minAmountsToReceive.length &&
|
||||
assetToSwapFromList.length == permitParams.length,
|
||||
'INCONSISTENT_PARAMS'
|
||||
);
|
||||
|
||||
SwapAndDepositLocalVars memory vars;
|
||||
|
||||
for (vars.i = 0; vars.i < assetToSwapFromList.length; vars.i++) {
|
||||
vars.aToken = _getReserveData(assetToSwapFromList[vars.i]).aTokenAddress;
|
||||
|
||||
vars.aTokenInitiatorBalance = IERC20(vars.aToken).balanceOf(msg.sender);
|
||||
vars.amountToSwap = amountToSwapList[vars.i] > vars.aTokenInitiatorBalance
|
||||
? vars.aTokenInitiatorBalance
|
||||
: amountToSwapList[vars.i];
|
||||
|
||||
_pullAToken(
|
||||
assetToSwapFromList[vars.i],
|
||||
vars.aToken,
|
||||
msg.sender,
|
||||
vars.amountToSwap,
|
||||
permitParams[vars.i]
|
||||
);
|
||||
|
||||
vars.receivedAmount = _swapExactTokensForTokens(
|
||||
assetToSwapFromList[vars.i],
|
||||
assetToSwapToList[vars.i],
|
||||
vars.amountToSwap,
|
||||
minAmountsToReceive[vars.i],
|
||||
useEthPath[vars.i]
|
||||
);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapToList[vars.i]).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(assetToSwapToList[vars.i]).safeApprove(address(LENDING_POOL), vars.receivedAmount);
|
||||
LENDING_POOL.deposit(assetToSwapToList[vars.i], vars.receivedAmount, msg.sender, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps an `amountToSwap` of an asset to another and deposits the funds on behalf of the initiator.
|
||||
* @param assetFrom Address of the underlying asset to be swap from
|
||||
* @param assetTo Address of the underlying asset to be swap to and deposited
|
||||
* @param amount Amount from flash loan
|
||||
* @param premium Premium of the flash loan
|
||||
* @param minAmountToReceive Min amount to be received from the swap
|
||||
* @param swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* @param permitSignature List of struct containing the permit signature
|
||||
* @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
|
||||
*/
|
||||
|
||||
struct SwapLiquidityLocalVars {
|
||||
address aToken;
|
||||
uint256 aTokenInitiatorBalance;
|
||||
uint256 amountToSwap;
|
||||
uint256 receivedAmount;
|
||||
uint256 flashLoanDebt;
|
||||
uint256 amountToPull;
|
||||
}
|
||||
|
||||
function _swapLiquidity(
|
||||
address assetFrom,
|
||||
address assetTo,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
address initiator,
|
||||
uint256 minAmountToReceive,
|
||||
bool swapAllBalance,
|
||||
PermitSignature memory permitSignature,
|
||||
bool useEthPath
|
||||
) internal {
|
||||
|
||||
SwapLiquidityLocalVars memory vars;
|
||||
|
||||
vars.aToken = _getReserveData(assetFrom).aTokenAddress;
|
||||
|
||||
vars.aTokenInitiatorBalance = IERC20(vars.aToken).balanceOf(initiator);
|
||||
vars.amountToSwap =
|
||||
swapAllBalance && vars.aTokenInitiatorBalance.sub(premium) <= amount
|
||||
? vars.aTokenInitiatorBalance.sub(premium)
|
||||
: amount;
|
||||
|
||||
vars.receivedAmount =
|
||||
_swapExactTokensForTokens(assetFrom, assetTo, vars.amountToSwap, minAmountToReceive, useEthPath);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetTo).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(assetTo).safeApprove(address(LENDING_POOL), vars.receivedAmount);
|
||||
LENDING_POOL.deposit(assetTo, vars.receivedAmount, initiator, 0);
|
||||
|
||||
vars.flashLoanDebt = amount.add(premium);
|
||||
vars.amountToPull = vars.amountToSwap.add(premium);
|
||||
|
||||
_pullAToken(assetFrom, vars.aToken, initiator, vars.amountToPull, permitSignature);
|
||||
|
||||
// Repay flash loan
|
||||
IERC20(assetFrom).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(assetFrom).safeApprove(address(LENDING_POOL), vars.flashLoanDebt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decodes the information encoded in the flash loan params
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
|
||||
* uint256[] minAmountsToReceive List of min amounts to be received from the swap
|
||||
* bool[] swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* uint256[] permitAmount List of amounts for the permit signature
|
||||
* uint256[] deadline List of deadlines for the permit signature
|
||||
* uint8[] v List of v param for the permit signature
|
||||
* bytes32[] r List of r param for the permit signature
|
||||
* bytes32[] s List of s param for the permit signature
|
||||
* bool[] useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
|
||||
* @return SwapParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal pure returns (SwapParams memory) {
|
||||
(
|
||||
address[] memory assetToSwapToList,
|
||||
uint256[] memory minAmountsToReceive,
|
||||
bool[] memory swapAllBalance,
|
||||
uint256[] memory permitAmount,
|
||||
uint256[] memory deadline,
|
||||
uint8[] memory v,
|
||||
bytes32[] memory r,
|
||||
bytes32[] memory s,
|
||||
bool[] memory useEthPath
|
||||
) =
|
||||
abi.decode(
|
||||
params,
|
||||
(address[], uint256[], bool[], uint256[], uint256[], uint8[], bytes32[], bytes32[], bool[])
|
||||
);
|
||||
|
||||
return
|
||||
SwapParams(
|
||||
assetToSwapToList,
|
||||
minAmountsToReceive,
|
||||
swapAllBalance,
|
||||
PermitParams(permitAmount, deadline, v, r, s),
|
||||
useEthPath
|
||||
);
|
||||
}
|
||||
}
|
259
contracts/adapters/UniswapRepayAdapter.sol
Normal file
259
contracts/adapters/UniswapRepayAdapter.sol
Normal file
|
@ -0,0 +1,259 @@
|
|||
// 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';
|
||||
|
||||
/**
|
||||
* @title UniswapRepayAdapter
|
||||
* @notice Uniswap V2 Adapter to perform a repay of a debt with collateral.
|
||||
* @author Aave
|
||||
**/
|
||||
contract UniswapRepayAdapter is BaseUniswapAdapter {
|
||||
struct RepayParams {
|
||||
address collateralAsset;
|
||||
uint256 collateralAmount;
|
||||
uint256 rateMode;
|
||||
PermitSignature permitSignature;
|
||||
bool useEthPath;
|
||||
}
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter,
|
||||
address wethAddress
|
||||
) public BaseUniswapAdapter(addressesProvider, uniswapRouter, wethAddress) {}
|
||||
|
||||
/**
|
||||
* @dev Uses the received funds from the flash loan to repay a debt on the protocol on behalf of the user. Then pulls
|
||||
* the collateral from the user and swaps it to the debt asset to repay the flash loan.
|
||||
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset, swap it
|
||||
* and repay the flash loan.
|
||||
* Supports only one asset on the flash loan.
|
||||
* @param assets Address of debt asset
|
||||
* @param amounts Amount of the debt to be repaid
|
||||
* @param premiums Fee of the flash loan
|
||||
* @param initiator Address of the user
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address collateralAsset Address of the reserve to be swapped
|
||||
* uint256 collateralAmount Amount of reserve to be swapped
|
||||
* uint256 rateMode Rate modes of the debt to be repaid
|
||||
* uint256 permitAmount Amount for the permit signature
|
||||
* uint256 deadline Deadline for the permit signature
|
||||
* uint8 v V param for the permit signature
|
||||
* bytes32 r R param for the permit signature
|
||||
* bytes32 s S param for the permit signature
|
||||
*/
|
||||
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');
|
||||
|
||||
RepayParams memory decodedParams = _decodeParams(params);
|
||||
|
||||
_swapAndRepay(
|
||||
decodedParams.collateralAsset,
|
||||
assets[0],
|
||||
amounts[0],
|
||||
decodedParams.collateralAmount,
|
||||
decodedParams.rateMode,
|
||||
initiator,
|
||||
premiums[0],
|
||||
decodedParams.permitSignature,
|
||||
decodedParams.useEthPath
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps the user collateral for the debt asset and then repay the debt on the protocol on behalf of the user
|
||||
* without using flash loans. This method can be used when the temporary transfer of the collateral asset to this
|
||||
* contract does not affect the user position.
|
||||
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset
|
||||
* @param collateralAsset Address of asset to be swapped
|
||||
* @param debtAsset Address of debt asset
|
||||
* @param collateralAmount Amount of the collateral to be swapped
|
||||
* @param debtRepayAmount Amount of the debt to be repaid
|
||||
* @param debtRateMode Rate mode of the debt to be repaid
|
||||
* @param permitSignature struct containing the permit signature
|
||||
* @param useEthPath struct containing the permit signature
|
||||
|
||||
*/
|
||||
function swapAndRepay(
|
||||
address collateralAsset,
|
||||
address debtAsset,
|
||||
uint256 collateralAmount,
|
||||
uint256 debtRepayAmount,
|
||||
uint256 debtRateMode,
|
||||
PermitSignature calldata permitSignature,
|
||||
bool useEthPath
|
||||
) external {
|
||||
DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
|
||||
DataTypes.ReserveData memory debtReserveData = _getReserveData(debtAsset);
|
||||
|
||||
address debtToken =
|
||||
DataTypes.InterestRateMode(debtRateMode) == DataTypes.InterestRateMode.STABLE
|
||||
? debtReserveData.stableDebtTokenAddress
|
||||
: debtReserveData.variableDebtTokenAddress;
|
||||
|
||||
uint256 currentDebt = IERC20(debtToken).balanceOf(msg.sender);
|
||||
uint256 amountToRepay = debtRepayAmount <= currentDebt ? debtRepayAmount : currentDebt;
|
||||
|
||||
if (collateralAsset != debtAsset) {
|
||||
uint256 maxCollateralToSwap = collateralAmount;
|
||||
if (amountToRepay < debtRepayAmount) {
|
||||
maxCollateralToSwap = maxCollateralToSwap.mul(amountToRepay).div(debtRepayAmount);
|
||||
}
|
||||
|
||||
// Get exact collateral needed for the swap to avoid leftovers
|
||||
uint256[] memory amounts =
|
||||
_getAmountsIn(collateralAsset, debtAsset, amountToRepay, useEthPath);
|
||||
require(amounts[0] <= maxCollateralToSwap, 'slippage too high');
|
||||
|
||||
// Pull aTokens from user
|
||||
_pullAToken(
|
||||
collateralAsset,
|
||||
collateralReserveData.aTokenAddress,
|
||||
msg.sender,
|
||||
amounts[0],
|
||||
permitSignature
|
||||
);
|
||||
|
||||
// Swap collateral for debt asset
|
||||
_swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], amountToRepay, useEthPath);
|
||||
} else {
|
||||
// Pull aTokens from user
|
||||
_pullAToken(
|
||||
collateralAsset,
|
||||
collateralReserveData.aTokenAddress,
|
||||
msg.sender,
|
||||
amountToRepay,
|
||||
permitSignature
|
||||
);
|
||||
}
|
||||
|
||||
// Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), amountToRepay);
|
||||
LENDING_POOL.repay(debtAsset, amountToRepay, debtRateMode, msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan
|
||||
*
|
||||
* @param collateralAsset Address of token to be swapped
|
||||
* @param debtAsset Address of debt token to be received from the swap
|
||||
* @param amount Amount of the debt to be repaid
|
||||
* @param collateralAmount Amount of the reserve to be swapped
|
||||
* @param rateMode Rate mode of the debt to be repaid
|
||||
* @param initiator Address of the user
|
||||
* @param premium Fee of the flash loan
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function _swapAndRepay(
|
||||
address collateralAsset,
|
||||
address debtAsset,
|
||||
uint256 amount,
|
||||
uint256 collateralAmount,
|
||||
uint256 rateMode,
|
||||
address initiator,
|
||||
uint256 premium,
|
||||
PermitSignature memory permitSignature,
|
||||
bool useEthPath
|
||||
) internal {
|
||||
DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
|
||||
|
||||
// Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), amount);
|
||||
uint256 repaidAmount = IERC20(debtAsset).balanceOf(address(this));
|
||||
LENDING_POOL.repay(debtAsset, amount, rateMode, initiator);
|
||||
repaidAmount = repaidAmount.sub(IERC20(debtAsset).balanceOf(address(this)));
|
||||
|
||||
if (collateralAsset != debtAsset) {
|
||||
uint256 maxCollateralToSwap = collateralAmount;
|
||||
if (repaidAmount < amount) {
|
||||
maxCollateralToSwap = maxCollateralToSwap.mul(repaidAmount).div(amount);
|
||||
}
|
||||
|
||||
uint256 neededForFlashLoanDebt = repaidAmount.add(premium);
|
||||
uint256[] memory amounts =
|
||||
_getAmountsIn(collateralAsset, debtAsset, neededForFlashLoanDebt, useEthPath);
|
||||
require(amounts[0] <= maxCollateralToSwap, 'slippage too high');
|
||||
|
||||
// Pull aTokens from user
|
||||
_pullAToken(
|
||||
collateralAsset,
|
||||
collateralReserveData.aTokenAddress,
|
||||
initiator,
|
||||
amounts[0],
|
||||
permitSignature
|
||||
);
|
||||
|
||||
// Swap collateral asset to the debt asset
|
||||
_swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], neededForFlashLoanDebt, useEthPath);
|
||||
} else {
|
||||
// Pull aTokens from user
|
||||
_pullAToken(
|
||||
collateralAsset,
|
||||
collateralReserveData.aTokenAddress,
|
||||
initiator,
|
||||
repaidAmount.add(premium),
|
||||
permitSignature
|
||||
);
|
||||
}
|
||||
|
||||
// Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
|
||||
IERC20(debtAsset).safeApprove(address(LENDING_POOL), amount.add(premium));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decodes debt information encoded in the flash loan params
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address collateralAsset Address of the reserve to be swapped
|
||||
* uint256 collateralAmount Amount of reserve to be swapped
|
||||
* uint256 rateMode Rate modes of the debt to be repaid
|
||||
* uint256 permitAmount Amount for the permit signature
|
||||
* uint256 deadline Deadline for the permit signature
|
||||
* uint8 v V param for the permit signature
|
||||
* bytes32 r R param for the permit signature
|
||||
* bytes32 s S param for the permit signature
|
||||
* @return RepayParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal pure returns (RepayParams memory) {
|
||||
(
|
||||
address collateralAsset,
|
||||
uint256 collateralAmount,
|
||||
uint256 rateMode,
|
||||
uint256 permitAmount,
|
||||
uint256 deadline,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s,
|
||||
bool useEthPath
|
||||
) =
|
||||
abi.decode(
|
||||
params,
|
||||
(address, uint256, uint256, uint256, uint256, uint8, bytes32, bytes32, bool)
|
||||
);
|
||||
|
||||
return
|
||||
RepayParams(
|
||||
collateralAsset,
|
||||
collateralAmount,
|
||||
rateMode,
|
||||
PermitSignature(permitAmount, deadline, v, r, s),
|
||||
useEthPath
|
||||
);
|
||||
}
|
||||
}
|
90
contracts/adapters/interfaces/IBaseUniswapAdapter.sol
Normal file
90
contracts/adapters/interfaces/IBaseUniswapAdapter.sol
Normal file
|
@ -0,0 +1,90 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
|
||||
import {IUniswapV2Router02} from '../../interfaces/IUniswapV2Router02.sol';
|
||||
|
||||
interface IBaseUniswapAdapter {
|
||||
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
|
||||
|
||||
struct PermitSignature {
|
||||
uint256 amount;
|
||||
uint256 deadline;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
}
|
||||
|
||||
struct AmountCalc {
|
||||
uint256 calculatedAmount;
|
||||
uint256 relativePrice;
|
||||
uint256 amountInUsd;
|
||||
uint256 amountOutUsd;
|
||||
address[] path;
|
||||
}
|
||||
|
||||
function WETH_ADDRESS() external returns (address);
|
||||
|
||||
function MAX_SLIPPAGE_PERCENT() external returns (uint256);
|
||||
|
||||
function FLASHLOAN_PREMIUM_TOTAL() external returns (uint256);
|
||||
|
||||
function USD_ADDRESS() external returns (address);
|
||||
|
||||
function ORACLE() external returns (IPriceOracleGetter);
|
||||
|
||||
function UNISWAP_ROUTER() external returns (IUniswapV2Router02);
|
||||
|
||||
/**
|
||||
* @dev Given an input asset amount, returns the maximum output amount of the other asset and the prices
|
||||
* @param amountIn Amount of reserveIn
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @return uint256 Amount out of the reserveOut
|
||||
* @return uint256 The price of out amount denominated in the reserveIn currency (18 decimals)
|
||||
* @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
* @return address[] The exchange path
|
||||
*/
|
||||
function getAmountsOut(
|
||||
uint256 amountIn,
|
||||
address reserveIn,
|
||||
address reserveOut
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
address[] memory
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Returns the minimum input asset amount required to buy the given output asset amount and the prices
|
||||
* @param amountOut Amount of reserveOut
|
||||
* @param reserveIn Address of the asset to be swap from
|
||||
* @param reserveOut Address of the asset to be swap to
|
||||
* @return uint256 Amount in of the reserveIn
|
||||
* @return uint256 The price of in amount denominated in the reserveOut currency (18 decimals)
|
||||
* @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
|
||||
* @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
|
||||
* @return address[] The exchange path
|
||||
*/
|
||||
function getAmountsIn(
|
||||
uint256 amountOut,
|
||||
address reserveIn,
|
||||
address reserveOut
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
uint256,
|
||||
address[] memory
|
||||
);
|
||||
}
|
|
@ -20,6 +20,20 @@ contract ATokensAndRatesHelper is Ownable {
|
|||
address private poolConfigurator;
|
||||
event deployedContracts(address aToken, address strategy);
|
||||
|
||||
struct InitDeploymentInput {
|
||||
address asset;
|
||||
uint256[6] rates;
|
||||
}
|
||||
|
||||
struct ConfigureReserveInput {
|
||||
address asset;
|
||||
uint256 baseLTV;
|
||||
uint256 liquidationThreshold;
|
||||
uint256 liquidationBonus;
|
||||
uint256 reserveFactor;
|
||||
bool stableBorrowingEnabled;
|
||||
}
|
||||
|
||||
constructor(
|
||||
address payable _pool,
|
||||
address _addressesProvider,
|
||||
|
@ -30,93 +44,40 @@ contract ATokensAndRatesHelper is Ownable {
|
|||
poolConfigurator = _poolConfigurator;
|
||||
}
|
||||
|
||||
function initDeployment(
|
||||
address[] calldata assets,
|
||||
string[] calldata symbols,
|
||||
uint256[6][] calldata rates,
|
||||
address treasuryAddress,
|
||||
address incentivesController
|
||||
) external onlyOwner {
|
||||
require(assets.length == symbols.length, 't Arrays not same length');
|
||||
require(rates.length == symbols.length, 'r Arrays not same length');
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
function initDeployment(InitDeploymentInput[] calldata inputParams) external onlyOwner {
|
||||
for (uint256 i = 0; i < inputParams.length; i++) {
|
||||
emit deployedContracts(
|
||||
address(
|
||||
new AToken(
|
||||
LendingPool(pool),
|
||||
assets[i],
|
||||
treasuryAddress,
|
||||
StringLib.concat('Aave interest bearing ', symbols[i]),
|
||||
StringLib.concat('a', symbols[i]),
|
||||
incentivesController
|
||||
)
|
||||
),
|
||||
address(new AToken()),
|
||||
address(
|
||||
new DefaultReserveInterestRateStrategy(
|
||||
LendingPoolAddressesProvider(addressesProvider),
|
||||
rates[i][0],
|
||||
rates[i][1],
|
||||
rates[i][2],
|
||||
rates[i][3],
|
||||
rates[i][4],
|
||||
rates[i][5]
|
||||
inputParams[i].rates[0],
|
||||
inputParams[i].rates[1],
|
||||
inputParams[i].rates[2],
|
||||
inputParams[i].rates[3],
|
||||
inputParams[i].rates[4],
|
||||
inputParams[i].rates[5]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function initReserve(
|
||||
address[] calldata stables,
|
||||
address[] calldata variables,
|
||||
address[] calldata aTokens,
|
||||
address[] calldata strategies,
|
||||
uint8[] calldata reserveDecimals
|
||||
) external onlyOwner {
|
||||
require(variables.length == stables.length);
|
||||
require(aTokens.length == stables.length);
|
||||
require(strategies.length == stables.length);
|
||||
require(reserveDecimals.length == stables.length);
|
||||
|
||||
for (uint256 i = 0; i < stables.length; i++) {
|
||||
LendingPoolConfigurator(poolConfigurator).initReserve(
|
||||
aTokens[i],
|
||||
stables[i],
|
||||
variables[i],
|
||||
reserveDecimals[i],
|
||||
strategies[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function configureReserves(
|
||||
address[] calldata assets,
|
||||
uint256[] calldata baseLTVs,
|
||||
uint256[] calldata liquidationThresholds,
|
||||
uint256[] calldata liquidationBonuses,
|
||||
uint256[] calldata reserveFactors,
|
||||
bool[] calldata stableBorrowingEnabled
|
||||
) external onlyOwner {
|
||||
require(baseLTVs.length == assets.length);
|
||||
require(liquidationThresholds.length == assets.length);
|
||||
require(liquidationBonuses.length == assets.length);
|
||||
require(stableBorrowingEnabled.length == assets.length);
|
||||
require(reserveFactors.length == assets.length);
|
||||
|
||||
function configureReserves(ConfigureReserveInput[] calldata inputParams) external onlyOwner {
|
||||
LendingPoolConfigurator configurator = LendingPoolConfigurator(poolConfigurator);
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
for (uint256 i = 0; i < inputParams.length; i++) {
|
||||
configurator.configureReserveAsCollateral(
|
||||
assets[i],
|
||||
baseLTVs[i],
|
||||
liquidationThresholds[i],
|
||||
liquidationBonuses[i]
|
||||
inputParams[i].asset,
|
||||
inputParams[i].baseLTV,
|
||||
inputParams[i].liquidationThreshold,
|
||||
inputParams[i].liquidationBonus
|
||||
);
|
||||
|
||||
configurator.enableBorrowingOnReserve(
|
||||
assets[i],
|
||||
stableBorrowingEnabled[i]
|
||||
inputParams[i].asset,
|
||||
inputParams[i].stableBorrowingEnabled
|
||||
);
|
||||
configurator.setReserveFactor(assets[i], reserveFactors[i]);
|
||||
configurator.setReserveFactor(inputParams[i].asset, inputParams[i].reserveFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,34 +18,11 @@ contract StableAndVariableTokensHelper is Ownable {
|
|||
addressesProvider = _addressesProvider;
|
||||
}
|
||||
|
||||
function initDeployment(
|
||||
address[] calldata tokens,
|
||||
string[] calldata symbols,
|
||||
address incentivesController
|
||||
) external onlyOwner {
|
||||
function initDeployment(address[] calldata tokens, string[] calldata symbols) external onlyOwner {
|
||||
require(tokens.length == symbols.length, 'Arrays not same length');
|
||||
require(pool != address(0), 'Pool can not be zero address');
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
emit deployedContracts(
|
||||
address(
|
||||
new StableDebtToken(
|
||||
pool,
|
||||
tokens[i],
|
||||
StringLib.concat('Aave stable debt bearing ', symbols[i]),
|
||||
StringLib.concat('stableDebt', symbols[i]),
|
||||
incentivesController
|
||||
)
|
||||
),
|
||||
address(
|
||||
new VariableDebtToken(
|
||||
pool,
|
||||
tokens[i],
|
||||
StringLib.concat('Aave variable debt bearing ', symbols[i]),
|
||||
StringLib.concat('variableDebt', symbols[i]),
|
||||
incentivesController
|
||||
)
|
||||
)
|
||||
);
|
||||
emit deployedContracts(address(new StableDebtToken()), address(new VariableDebtToken()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ pragma solidity 0.6.12;
|
|||
|
||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
|
||||
import {IInitializableAToken} from './IInitializableAToken.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
interface IAToken is IERC20, IScaledBalanceToken {
|
||||
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
|
||||
/**
|
||||
* @dev Emitted after the mint action
|
||||
* @param from The address performing the mint
|
||||
|
@ -85,4 +87,9 @@ interface IAToken is IERC20, IScaledBalanceToken {
|
|||
* @return The amount transferred
|
||||
**/
|
||||
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view returns (IAaveIncentivesController);
|
||||
}
|
||||
|
|
16
contracts/interfaces/IERC20WithPermit.sol
Normal file
16
contracts/interfaces/IERC20WithPermit.sol
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||
|
||||
interface IERC20WithPermit is IERC20 {
|
||||
function permit(
|
||||
address owner,
|
||||
address spender,
|
||||
uint256 value,
|
||||
uint256 deadline,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) external;
|
||||
}
|
32
contracts/interfaces/IInitializableAToken.sol
Normal file
32
contracts/interfaces/IInitializableAToken.sol
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {ILendingPool} from './ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title IInitializableAToken
|
||||
* @notice Interface for the initialize function on AToken
|
||||
* @author Aave
|
||||
**/
|
||||
interface IInitializableAToken {
|
||||
/**
|
||||
* @dev Initializes the aToken
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
|
||||
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
* @param incentivesController The smart contract managing potential incentives distribution
|
||||
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
|
||||
* @param aTokenName The name of the aToken
|
||||
* @param aTokenSymbol The symbol of the aToken
|
||||
*/
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address treasury,
|
||||
address underlyingAsset,
|
||||
IAaveIncentivesController incentivesController,
|
||||
uint8 aTokenDecimals,
|
||||
string calldata aTokenName,
|
||||
string calldata aTokenSymbol
|
||||
) external;
|
||||
}
|
30
contracts/interfaces/IInitializableDebtToken.sol
Normal file
30
contracts/interfaces/IInitializableDebtToken.sol
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {ILendingPool} from './ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title IInitializableDebtToken
|
||||
* @notice Interface for the initialize function common between debt tokens
|
||||
* @author Aave
|
||||
**/
|
||||
interface IInitializableDebtToken {
|
||||
/**
|
||||
* @dev Initializes the debt token.
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
* @param incentivesController The smart contract managing potential incentives distribution
|
||||
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
|
||||
* @param debtTokenName The name of the token
|
||||
* @param debtTokenSymbol The symbol of the token
|
||||
*/
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address underlyingAsset,
|
||||
IAaveIncentivesController incentivesController,
|
||||
uint8 debtTokenDecimals,
|
||||
string memory debtTokenName,
|
||||
string memory debtTokenSymbol
|
||||
) external;
|
||||
}
|
176
contracts/interfaces/ILendingPoolConfigurator.sol
Normal file
176
contracts/interfaces/ILendingPoolConfigurator.sol
Normal file
|
@ -0,0 +1,176 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface ILendingPoolConfigurator {
|
||||
struct InitReserveInput {
|
||||
address aTokenImpl;
|
||||
address stableDebtTokenImpl;
|
||||
address variableDebtTokenImpl;
|
||||
uint8 underlyingAssetDecimals;
|
||||
address interestRateStrategyAddress;
|
||||
address underlyingAsset;
|
||||
address treasury;
|
||||
address incentivesController;
|
||||
string underlyingAssetName;
|
||||
string aTokenName;
|
||||
string aTokenSymbol;
|
||||
string variableDebtTokenName;
|
||||
string variableDebtTokenSymbol;
|
||||
string stableDebtTokenName;
|
||||
string stableDebtTokenSymbol;
|
||||
}
|
||||
|
||||
struct UpdateATokenInput {
|
||||
address asset;
|
||||
address treasury;
|
||||
address incentivesController;
|
||||
string name;
|
||||
string symbol;
|
||||
address implementation;
|
||||
}
|
||||
|
||||
struct UpdateDebtTokenInput {
|
||||
address asset;
|
||||
address incentivesController;
|
||||
string name;
|
||||
string symbol;
|
||||
address implementation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is initialized.
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param aToken The address of the associated aToken contract
|
||||
* @param stableDebtToken The address of the associated stable rate debt token
|
||||
* @param variableDebtToken The address of the associated variable rate debt token
|
||||
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
|
||||
**/
|
||||
event ReserveInitialized(
|
||||
address indexed asset,
|
||||
address indexed aToken,
|
||||
address stableDebtToken,
|
||||
address variableDebtToken,
|
||||
address interestRateStrategyAddress
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when borrowing is enabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise
|
||||
**/
|
||||
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
|
||||
|
||||
/**
|
||||
* @dev Emitted when borrowing is disabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event BorrowingDisabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param ltv The loan to value of the asset when used as collateral
|
||||
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
|
||||
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
|
||||
**/
|
||||
event CollateralConfigurationChanged(
|
||||
address indexed asset,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when stable rate borrowing is enabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event StableRateEnabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when stable rate borrowing is disabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event StableRateDisabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is activated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveActivated(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is deactivated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveDeactivated(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is frozen
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveFrozen(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is unfrozen
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveUnfrozen(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve factor is updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param factor The new reserve factor
|
||||
**/
|
||||
event ReserveFactorChanged(address indexed asset, uint256 factor);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the reserve decimals are updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param decimals The new decimals
|
||||
**/
|
||||
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve interest strategy contract is updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param strategy The new address of the interest strategy contract
|
||||
**/
|
||||
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
|
||||
|
||||
/**
|
||||
* @dev Emitted when an aToken implementation is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The aToken proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event ATokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation of a stable debt token is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The stable debt token proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event StableDebtTokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation of a variable debt token is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The variable debt token proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event VariableDebtTokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {IInitializableDebtToken} from './IInitializableDebtToken.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title IStableDebtToken
|
||||
* @notice Defines the interface for the stable debt token
|
||||
|
@ -8,7 +11,7 @@ pragma solidity 0.6.12;
|
|||
* @author Aave
|
||||
**/
|
||||
|
||||
interface IStableDebtToken {
|
||||
interface IStableDebtToken is IInitializableDebtToken {
|
||||
/**
|
||||
* @dev Emitted when new stable debt is minted
|
||||
* @param user The address of the user who triggered the minting
|
||||
|
@ -122,4 +125,9 @@ interface IStableDebtToken {
|
|||
* @return The debt balance of the user since the last burn/mint action
|
||||
**/
|
||||
function principalBalanceOf(address user) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view returns (IAaveIncentivesController);
|
||||
}
|
||||
|
|
24
contracts/interfaces/IUniswapV2Router02.sol
Normal file
24
contracts/interfaces/IUniswapV2Router02.sol
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
interface IUniswapV2Router02 {
|
||||
function swapExactTokensForTokens(
|
||||
uint256 amountIn,
|
||||
uint256 amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint256 deadline
|
||||
) external returns (uint256[] memory amounts);
|
||||
|
||||
function swapTokensForExactTokens(
|
||||
uint amountOut,
|
||||
uint amountInMax,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint256[] memory amounts);
|
||||
|
||||
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
|
||||
|
||||
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
|
||||
}
|
|
@ -2,13 +2,15 @@
|
|||
pragma solidity 0.6.12;
|
||||
|
||||
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
|
||||
import {IInitializableDebtToken} from './IInitializableDebtToken.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title IVariableDebtToken
|
||||
* @author Aave
|
||||
* @notice Defines the basic interface for a variable debt token.
|
||||
**/
|
||||
interface IVariableDebtToken is IScaledBalanceToken {
|
||||
interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken {
|
||||
/**
|
||||
* @dev Emitted after the mint action
|
||||
* @param from The address performing the mint
|
||||
|
@ -52,4 +54,9 @@ interface IVariableDebtToken is IScaledBalanceToken {
|
|||
uint256 amount,
|
||||
uint256 index
|
||||
) external;
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view returns (IAaveIncentivesController);
|
||||
}
|
||||
|
|
106
contracts/mocks/swap/MockUniswapV2Router02.sol
Normal file
106
contracts/mocks/swap/MockUniswapV2Router02.sol
Normal file
|
@ -0,0 +1,106 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {IUniswapV2Router02} from '../../interfaces/IUniswapV2Router02.sol';
|
||||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
||||
import {MintableERC20} from '../tokens/MintableERC20.sol';
|
||||
|
||||
contract MockUniswapV2Router02 is IUniswapV2Router02 {
|
||||
mapping(address => uint256) internal _amountToReturn;
|
||||
mapping(address => uint256) internal _amountToSwap;
|
||||
mapping(address => mapping(address => mapping(uint256 => uint256))) internal _amountsIn;
|
||||
mapping(address => mapping(address => mapping(uint256 => uint256))) internal _amountsOut;
|
||||
uint256 internal defaultMockValue;
|
||||
|
||||
function setAmountToReturn(address reserve, uint256 amount) public {
|
||||
_amountToReturn[reserve] = amount;
|
||||
}
|
||||
|
||||
function setAmountToSwap(address reserve, uint256 amount) public {
|
||||
_amountToSwap[reserve] = amount;
|
||||
}
|
||||
|
||||
function swapExactTokensForTokens(
|
||||
uint256 amountIn,
|
||||
uint256, /* amountOutMin */
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint256 /* deadline */
|
||||
) external override returns (uint256[] memory amounts) {
|
||||
IERC20(path[0]).transferFrom(msg.sender, address(this), amountIn);
|
||||
|
||||
MintableERC20(path[1]).mint(_amountToReturn[path[0]]);
|
||||
IERC20(path[1]).transfer(to, _amountToReturn[path[0]]);
|
||||
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
amounts[1] = _amountToReturn[path[0]];
|
||||
}
|
||||
|
||||
function swapTokensForExactTokens(
|
||||
uint256 amountOut,
|
||||
uint256, /* amountInMax */
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint256 /* deadline */
|
||||
) external override returns (uint256[] memory amounts) {
|
||||
IERC20(path[0]).transferFrom(msg.sender, address(this), _amountToSwap[path[0]]);
|
||||
|
||||
MintableERC20(path[1]).mint(amountOut);
|
||||
IERC20(path[1]).transfer(to, amountOut);
|
||||
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[0] = _amountToSwap[path[0]];
|
||||
amounts[1] = amountOut;
|
||||
}
|
||||
|
||||
function setAmountOut(
|
||||
uint256 amountIn,
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountOut
|
||||
) public {
|
||||
_amountsOut[reserveIn][reserveOut][amountIn] = amountOut;
|
||||
}
|
||||
|
||||
function setAmountIn(
|
||||
uint256 amountOut,
|
||||
address reserveIn,
|
||||
address reserveOut,
|
||||
uint256 amountIn
|
||||
) public {
|
||||
_amountsIn[reserveIn][reserveOut][amountOut] = amountIn;
|
||||
}
|
||||
|
||||
function setDefaultMockValue(uint256 value) public {
|
||||
defaultMockValue = value;
|
||||
}
|
||||
|
||||
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
||||
external
|
||||
view
|
||||
override
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
uint256[] memory amounts = new uint256[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
amounts[1] = _amountsOut[path[0]][path[1]][amountIn] > 0
|
||||
? _amountsOut[path[0]][path[1]][amountIn]
|
||||
: defaultMockValue;
|
||||
return amounts;
|
||||
}
|
||||
|
||||
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
||||
external
|
||||
view
|
||||
override
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
uint256[] memory amounts = new uint256[](path.length);
|
||||
amounts[0] = _amountsIn[path[0]][path[1]][amountOut] > 0
|
||||
? _amountsIn[path[0]][path[1]][amountOut]
|
||||
: defaultMockValue;
|
||||
amounts[1] = amountOut;
|
||||
return amounts;
|
||||
}
|
||||
}
|
|
@ -2,39 +2,11 @@
|
|||
pragma solidity 0.6.12;
|
||||
|
||||
import {AToken} from '../../protocol/tokenization/AToken.sol';
|
||||
import {LendingPool} from '../../protocol/lendingpool/LendingPool.sol';
|
||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
|
||||
contract MockAToken is AToken {
|
||||
constructor(
|
||||
LendingPool pool,
|
||||
address underlyingAssetAddress,
|
||||
address reserveTreasury,
|
||||
string memory tokenName,
|
||||
string memory tokenSymbol,
|
||||
address incentivesController
|
||||
)
|
||||
public
|
||||
AToken(
|
||||
pool,
|
||||
underlyingAssetAddress,
|
||||
reserveTreasury,
|
||||
tokenName,
|
||||
tokenSymbol,
|
||||
incentivesController
|
||||
)
|
||||
{}
|
||||
|
||||
function getRevision() internal pure override returns (uint256) {
|
||||
return 0x2;
|
||||
}
|
||||
|
||||
function initialize(
|
||||
uint8 _underlyingAssetDecimals,
|
||||
string calldata _tokenName,
|
||||
string calldata _tokenSymbol
|
||||
) external virtual override initializer {
|
||||
_setName(_tokenName);
|
||||
_setSymbol(_tokenSymbol);
|
||||
_setDecimals(_underlyingAssetDecimals);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,6 @@ pragma solidity 0.6.12;
|
|||
import {StableDebtToken} from '../../protocol/tokenization/StableDebtToken.sol';
|
||||
|
||||
contract MockStableDebtToken is StableDebtToken {
|
||||
constructor(
|
||||
address _pool,
|
||||
address _underlyingAssetAddress,
|
||||
string memory _tokenName,
|
||||
string memory _tokenSymbol,
|
||||
address incentivesController
|
||||
)
|
||||
public
|
||||
StableDebtToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController)
|
||||
{}
|
||||
|
||||
function getRevision() internal pure override returns (uint256) {
|
||||
return 0x2;
|
||||
}
|
||||
|
|
|
@ -4,23 +4,6 @@ pragma solidity 0.6.12;
|
|||
import {VariableDebtToken} from '../../protocol/tokenization/VariableDebtToken.sol';
|
||||
|
||||
contract MockVariableDebtToken is VariableDebtToken {
|
||||
constructor(
|
||||
address _pool,
|
||||
address _underlyingAssetAddress,
|
||||
string memory _tokenName,
|
||||
string memory _tokenSymbol,
|
||||
address incentivesController
|
||||
)
|
||||
public
|
||||
VariableDebtToken(
|
||||
_pool,
|
||||
_underlyingAssetAddress,
|
||||
_tokenName,
|
||||
_tokenSymbol,
|
||||
incentivesController
|
||||
)
|
||||
{}
|
||||
|
||||
function getRevision() internal pure override returns (uint256) {
|
||||
return 0x2;
|
||||
}
|
||||
|
|
|
@ -49,10 +49,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
using PercentageMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
//main configuration parameters
|
||||
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 2500;
|
||||
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
|
||||
uint256 public constant MAX_NUMBER_RESERVES = 128;
|
||||
uint256 public constant LENDINGPOOL_REVISION = 0x2;
|
||||
|
||||
modifier whenNotPaused() {
|
||||
|
@ -86,9 +82,20 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
* - Caching the address of the LendingPoolAddressesProvider in order to reduce gas consumption
|
||||
* on subsequent operations
|
||||
* @param provider The address of the LendingPoolAddressesProvider
|
||||
* @param maxStableRateBorrowSizePercent The percentage of available liquidity that can be borrowed at once at stable rate
|
||||
* @param flashLoanPremiumTotal The fee on flash loans
|
||||
* @param maxNumberOfReserves Maximum number of reserves supported to be listed in this LendingPool
|
||||
**/
|
||||
function initialize(ILendingPoolAddressesProvider provider) public initializer {
|
||||
function initialize(
|
||||
ILendingPoolAddressesProvider provider,
|
||||
uint256 maxStableRateBorrowSizePercent,
|
||||
uint256 flashLoanPremiumTotal,
|
||||
uint256 maxNumberOfReserves
|
||||
) public initializer {
|
||||
_addressesProvider = provider;
|
||||
_maxStableRateBorrowSizePercent = maxStableRateBorrowSizePercent;
|
||||
_flashLoanPremiumTotal = flashLoanPremiumTotal;
|
||||
_maxNumberOfReserves = maxNumberOfReserves;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,7 +151,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
address asset,
|
||||
uint256 amount,
|
||||
address to
|
||||
) external override whenNotPaused returns (uint256) {
|
||||
) external override whenNotPaused returns (uint256) {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
@ -499,7 +506,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
for (vars.i = 0; vars.i < assets.length; vars.i++) {
|
||||
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
|
||||
|
||||
premiums[vars.i] = amounts[vars.i].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000);
|
||||
premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000);
|
||||
|
||||
IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]);
|
||||
}
|
||||
|
@ -703,6 +710,27 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
return _addressesProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the percentage of available liquidity that can be borrowed at once at stable rate
|
||||
*/
|
||||
function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() public view returns (uint256) {
|
||||
return _maxStableRateBorrowSizePercent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the fee on flash loans
|
||||
*/
|
||||
function FLASHLOAN_PREMIUM_TOTAL() public view returns (uint256) {
|
||||
return _flashLoanPremiumTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the maximum number of reserves supported to be listed in this LendingPool
|
||||
*/
|
||||
function MAX_NUMBER_RESERVES() public view returns (uint256) {
|
||||
return _maxNumberOfReserves;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validates and finalizes an aToken transfer
|
||||
* - Only callable by the overlying aToken of the `asset`
|
||||
|
@ -847,7 +875,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
vars.amount,
|
||||
amountInETH,
|
||||
vars.interestRateMode,
|
||||
MAX_STABLE_RATE_BORROW_SIZE_PERCENT,
|
||||
_maxStableRateBorrowSizePercent,
|
||||
_reserves,
|
||||
userConfig,
|
||||
_reservesList,
|
||||
|
@ -909,7 +937,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
function _addReserveToList(address asset) internal {
|
||||
uint256 reservesCount = _reservesCount;
|
||||
|
||||
require(reservesCount < MAX_NUMBER_RESERVES, Errors.LP_NO_MORE_RESERVES_ALLOWED);
|
||||
require(reservesCount < _maxNumberOfReserves, Errors.LP_NO_MORE_RESERVES_ALLOWED);
|
||||
|
||||
bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset;
|
||||
|
||||
|
|
|
@ -10,11 +10,14 @@ import {
|
|||
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
|
||||
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
|
||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||
import {ITokenConfiguration} from '../../interfaces/ITokenConfiguration.sol';
|
||||
import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
||||
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
|
||||
import {DataTypes} from '../libraries/types/DataTypes.sol';
|
||||
import {IInitializableDebtToken} from '../../interfaces/IInitializableDebtToken.sol';
|
||||
import {IInitializableAToken} from '../../interfaces/IInitializableAToken.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
import {ILendingPoolConfigurator} from '../../interfaces/ILendingPoolConfigurator.sol';
|
||||
|
||||
/**
|
||||
* @title LendingPoolConfigurator contract
|
||||
|
@ -22,147 +25,11 @@ import {DataTypes} from '../libraries/types/DataTypes.sol';
|
|||
* @dev Implements the configuration methods for the Aave protocol
|
||||
**/
|
||||
|
||||
contract LendingPoolConfigurator is VersionedInitializable {
|
||||
contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigurator {
|
||||
using SafeMath for uint256;
|
||||
using PercentageMath for uint256;
|
||||
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is initialized.
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param aToken The address of the associated aToken contract
|
||||
* @param stableDebtToken The address of the associated stable rate debt token
|
||||
* @param variableDebtToken The address of the associated variable rate debt token
|
||||
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
|
||||
**/
|
||||
event ReserveInitialized(
|
||||
address indexed asset,
|
||||
address indexed aToken,
|
||||
address stableDebtToken,
|
||||
address variableDebtToken,
|
||||
address interestRateStrategyAddress
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when borrowing is enabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise
|
||||
**/
|
||||
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
|
||||
|
||||
/**
|
||||
* @dev Emitted when borrowing is disabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event BorrowingDisabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param ltv The loan to value of the asset when used as collateral
|
||||
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
|
||||
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
|
||||
**/
|
||||
event CollateralConfigurationChanged(
|
||||
address indexed asset,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when stable rate borrowing is enabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event StableRateEnabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when stable rate borrowing is disabled on a reserve
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event StableRateDisabledOnReserve(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is activated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveActivated(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is deactivated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveDeactivated(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is frozen
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveFrozen(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve is unfrozen
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
**/
|
||||
event ReserveUnfrozen(address indexed asset);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve factor is updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param factor The new reserve factor
|
||||
**/
|
||||
event ReserveFactorChanged(address indexed asset, uint256 factor);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the reserve decimals are updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param decimals The new decimals
|
||||
**/
|
||||
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a reserve interest strategy contract is updated
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param strategy The new address of the interest strategy contract
|
||||
**/
|
||||
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
|
||||
|
||||
/**
|
||||
* @dev Emitted when an aToken implementation is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The aToken proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event ATokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation of a stable debt token is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The stable debt token proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event StableDebtTokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation of a variable debt token is upgraded
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param proxy The variable debt token proxy address
|
||||
* @param implementation The new aToken implementation
|
||||
**/
|
||||
event VariableDebtTokenUpgraded(
|
||||
address indexed asset,
|
||||
address indexed proxy,
|
||||
address indexed implementation
|
||||
);
|
||||
|
||||
ILendingPoolAddressesProvider internal addressesProvider;
|
||||
ILendingPool internal pool;
|
||||
|
||||
|
@ -191,114 +58,186 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Initializes a reserve
|
||||
* @param aTokenImpl The address of the aToken contract implementation
|
||||
* @param stableDebtTokenImpl The address of the stable debt token contract
|
||||
* @param variableDebtTokenImpl The address of the variable debt token contract
|
||||
* @param underlyingAssetDecimals The decimals of the reserve underlying asset
|
||||
* @param interestRateStrategyAddress The address of the interest rate strategy contract for this reserve
|
||||
* @dev Initializes reserves in batch
|
||||
**/
|
||||
function initReserve(
|
||||
address aTokenImpl,
|
||||
address stableDebtTokenImpl,
|
||||
address variableDebtTokenImpl,
|
||||
uint8 underlyingAssetDecimals,
|
||||
address interestRateStrategyAddress
|
||||
) public onlyPoolAdmin {
|
||||
address asset = ITokenConfiguration(aTokenImpl).UNDERLYING_ASSET_ADDRESS();
|
||||
function batchInitReserve(InitReserveInput[] calldata inputParams) public onlyPoolAdmin {
|
||||
ILendingPool cachedPool = pool;
|
||||
for (uint256 i = 0; i < inputParams.length; i++) {
|
||||
_initReserve(cachedPool, inputParams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
require(
|
||||
address(pool) == ITokenConfiguration(aTokenImpl).POOL(),
|
||||
Errors.LPC_INVALID_ATOKEN_POOL_ADDRESS
|
||||
);
|
||||
require(
|
||||
address(pool) == ITokenConfiguration(stableDebtTokenImpl).POOL(),
|
||||
Errors.LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS
|
||||
);
|
||||
require(
|
||||
address(pool) == ITokenConfiguration(variableDebtTokenImpl).POOL(),
|
||||
Errors.LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS
|
||||
);
|
||||
require(
|
||||
asset == ITokenConfiguration(stableDebtTokenImpl).UNDERLYING_ASSET_ADDRESS(),
|
||||
Errors.LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS
|
||||
);
|
||||
require(
|
||||
asset == ITokenConfiguration(variableDebtTokenImpl).UNDERLYING_ASSET_ADDRESS(),
|
||||
Errors.LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS
|
||||
);
|
||||
|
||||
address aTokenProxyAddress = _initTokenWithProxy(aTokenImpl, underlyingAssetDecimals);
|
||||
function _initReserve(ILendingPool pool, InitReserveInput calldata inputParams) internal {
|
||||
address aTokenProxyAddress =
|
||||
_initTokenWithProxy(
|
||||
inputParams.aTokenImpl,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableAToken.initialize.selector,
|
||||
pool,
|
||||
inputParams.treasury,
|
||||
inputParams.underlyingAsset,
|
||||
IAaveIncentivesController(inputParams.incentivesController),
|
||||
inputParams.underlyingAssetDecimals,
|
||||
inputParams.aTokenName,
|
||||
inputParams.aTokenSymbol
|
||||
)
|
||||
);
|
||||
|
||||
address stableDebtTokenProxyAddress =
|
||||
_initTokenWithProxy(stableDebtTokenImpl, underlyingAssetDecimals);
|
||||
_initTokenWithProxy(
|
||||
inputParams.stableDebtTokenImpl,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableDebtToken.initialize.selector,
|
||||
pool,
|
||||
inputParams.underlyingAsset,
|
||||
IAaveIncentivesController(inputParams.incentivesController),
|
||||
inputParams.underlyingAssetDecimals,
|
||||
inputParams.stableDebtTokenName,
|
||||
inputParams.stableDebtTokenSymbol
|
||||
)
|
||||
);
|
||||
|
||||
address variableDebtTokenProxyAddress =
|
||||
_initTokenWithProxy(variableDebtTokenImpl, underlyingAssetDecimals);
|
||||
_initTokenWithProxy(
|
||||
inputParams.variableDebtTokenImpl,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableDebtToken.initialize.selector,
|
||||
pool,
|
||||
inputParams.underlyingAsset,
|
||||
IAaveIncentivesController(inputParams.incentivesController),
|
||||
inputParams.underlyingAssetDecimals,
|
||||
inputParams.variableDebtTokenName,
|
||||
inputParams.variableDebtTokenSymbol
|
||||
)
|
||||
);
|
||||
|
||||
pool.initReserve(
|
||||
asset,
|
||||
inputParams.underlyingAsset,
|
||||
aTokenProxyAddress,
|
||||
stableDebtTokenProxyAddress,
|
||||
variableDebtTokenProxyAddress,
|
||||
interestRateStrategyAddress
|
||||
inputParams.interestRateStrategyAddress
|
||||
);
|
||||
|
||||
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
|
||||
DataTypes.ReserveConfigurationMap memory currentConfig =
|
||||
pool.getConfiguration(inputParams.underlyingAsset);
|
||||
|
||||
currentConfig.setDecimals(underlyingAssetDecimals);
|
||||
currentConfig.setDecimals(inputParams.underlyingAssetDecimals);
|
||||
|
||||
currentConfig.setActive(true);
|
||||
currentConfig.setFrozen(false);
|
||||
|
||||
pool.setConfiguration(asset, currentConfig.data);
|
||||
pool.setConfiguration(inputParams.underlyingAsset, currentConfig.data);
|
||||
|
||||
emit ReserveInitialized(
|
||||
asset,
|
||||
inputParams.underlyingAsset,
|
||||
aTokenProxyAddress,
|
||||
stableDebtTokenProxyAddress,
|
||||
variableDebtTokenProxyAddress,
|
||||
interestRateStrategyAddress
|
||||
inputParams.interestRateStrategyAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Updates the aToken implementation for the reserve
|
||||
* @param asset The address of the underlying asset of the reserve to be updated
|
||||
* @param implementation The address of the new aToken implementation
|
||||
**/
|
||||
function updateAToken(address asset, address implementation) external onlyPoolAdmin {
|
||||
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
|
||||
function updateAToken(UpdateATokenInput calldata inputParams) external onlyPoolAdmin {
|
||||
ILendingPool cachedPool = pool;
|
||||
|
||||
_upgradeTokenImplementation(asset, reserveData.aTokenAddress, implementation);
|
||||
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
|
||||
|
||||
emit ATokenUpgraded(asset, reserveData.aTokenAddress, implementation);
|
||||
DataTypes.ReserveConfigurationMap memory configuration =
|
||||
cachedPool.getConfiguration(inputParams.asset);
|
||||
|
||||
(, , , uint256 decimals, ) = configuration.getParamsMemory();
|
||||
|
||||
_upgradeTokenImplementation(
|
||||
reserveData.aTokenAddress,
|
||||
inputParams.implementation,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableAToken.initialize.selector,
|
||||
cachedPool,
|
||||
inputParams.treasury,
|
||||
inputParams.asset,
|
||||
inputParams.incentivesController,
|
||||
decimals,
|
||||
inputParams.name,
|
||||
inputParams.symbol
|
||||
)
|
||||
);
|
||||
|
||||
emit ATokenUpgraded(inputParams.asset, reserveData.aTokenAddress, inputParams.implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Updates the stable debt token implementation for the reserve
|
||||
* @param asset The address of the underlying asset of the reserve to be updated
|
||||
* @param implementation The address of the new aToken implementation
|
||||
**/
|
||||
function updateStableDebtToken(address asset, address implementation) external onlyPoolAdmin {
|
||||
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
|
||||
function updateStableDebtToken(UpdateDebtTokenInput calldata inputParams) external onlyPoolAdmin {
|
||||
ILendingPool cachedPool = pool;
|
||||
|
||||
_upgradeTokenImplementation(asset, reserveData.stableDebtTokenAddress, implementation);
|
||||
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
|
||||
|
||||
emit StableDebtTokenUpgraded(asset, reserveData.stableDebtTokenAddress, implementation);
|
||||
DataTypes.ReserveConfigurationMap memory configuration =
|
||||
cachedPool.getConfiguration(inputParams.asset);
|
||||
|
||||
(, , , uint256 decimals, ) = configuration.getParamsMemory();
|
||||
|
||||
_upgradeTokenImplementation(
|
||||
reserveData.stableDebtTokenAddress,
|
||||
inputParams.implementation,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableDebtToken.initialize.selector,
|
||||
cachedPool,
|
||||
inputParams.asset,
|
||||
inputParams.incentivesController,
|
||||
decimals,
|
||||
inputParams.name,
|
||||
inputParams.symbol
|
||||
)
|
||||
);
|
||||
|
||||
emit StableDebtTokenUpgraded(
|
||||
inputParams.asset,
|
||||
reserveData.stableDebtTokenAddress,
|
||||
inputParams.implementation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Updates the variable debt token implementation for the asset
|
||||
* @param asset The address of the underlying asset of the reserve to be updated
|
||||
* @param implementation The address of the new aToken implementation
|
||||
**/
|
||||
function updateVariableDebtToken(address asset, address implementation) external onlyPoolAdmin {
|
||||
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
|
||||
function updateVariableDebtToken(UpdateDebtTokenInput calldata inputParams)
|
||||
external
|
||||
onlyPoolAdmin
|
||||
{
|
||||
ILendingPool cachedPool = pool;
|
||||
|
||||
_upgradeTokenImplementation(asset, reserveData.variableDebtTokenAddress, implementation);
|
||||
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
|
||||
|
||||
emit VariableDebtTokenUpgraded(asset, reserveData.variableDebtTokenAddress, implementation);
|
||||
DataTypes.ReserveConfigurationMap memory configuration =
|
||||
cachedPool.getConfiguration(inputParams.asset);
|
||||
|
||||
(, , , uint256 decimals, ) = configuration.getParamsMemory();
|
||||
|
||||
_upgradeTokenImplementation(
|
||||
reserveData.variableDebtTokenAddress,
|
||||
inputParams.implementation,
|
||||
abi.encodeWithSelector(
|
||||
IInitializableDebtToken.initialize.selector,
|
||||
cachedPool,
|
||||
inputParams.asset,
|
||||
inputParams.incentivesController,
|
||||
decimals,
|
||||
inputParams.name,
|
||||
inputParams.symbol
|
||||
)
|
||||
);
|
||||
|
||||
emit VariableDebtTokenUpgraded(
|
||||
inputParams.asset,
|
||||
reserveData.variableDebtTokenAddress,
|
||||
inputParams.implementation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -509,44 +448,27 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
pool.setPause(val);
|
||||
}
|
||||
|
||||
function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) {
|
||||
function _initTokenWithProxy(address implementation, bytes memory initParams)
|
||||
internal
|
||||
returns (address)
|
||||
{
|
||||
InitializableImmutableAdminUpgradeabilityProxy proxy =
|
||||
new InitializableImmutableAdminUpgradeabilityProxy(address(this));
|
||||
|
||||
bytes memory params =
|
||||
abi.encodeWithSignature(
|
||||
'initialize(uint8,string,string)',
|
||||
decimals,
|
||||
IERC20Detailed(implementation).name(),
|
||||
IERC20Detailed(implementation).symbol()
|
||||
);
|
||||
|
||||
proxy.initialize(implementation, params);
|
||||
proxy.initialize(implementation, initParams);
|
||||
|
||||
return address(proxy);
|
||||
}
|
||||
|
||||
function _upgradeTokenImplementation(
|
||||
address asset,
|
||||
address proxyAddress,
|
||||
address implementation
|
||||
address implementation,
|
||||
bytes memory initParams
|
||||
) internal {
|
||||
InitializableImmutableAdminUpgradeabilityProxy proxy =
|
||||
InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
|
||||
|
||||
DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(asset);
|
||||
|
||||
(, , , uint256 decimals, ) = configuration.getParamsMemory();
|
||||
|
||||
bytes memory params =
|
||||
abi.encodeWithSignature(
|
||||
'initialize(uint8,string,string)',
|
||||
uint8(decimals),
|
||||
IERC20Detailed(implementation).name(),
|
||||
IERC20Detailed(implementation).symbol()
|
||||
);
|
||||
|
||||
proxy.upgradeToAndCall(implementation, params);
|
||||
proxy.upgradeToAndCall(implementation, initParams);
|
||||
}
|
||||
|
||||
function _checkNoLiquidity(address asset) internal view {
|
||||
|
|
|
@ -23,4 +23,10 @@ contract LendingPoolStorage {
|
|||
uint256 internal _reservesCount;
|
||||
|
||||
bool internal _paused;
|
||||
|
||||
uint256 internal _maxStableRateBorrowSizePercent;
|
||||
|
||||
uint256 internal _flashLoanPremiumTotal;
|
||||
|
||||
uint256 internal _maxNumberOfReserves;
|
||||
}
|
||||
|
|
|
@ -89,20 +89,13 @@ library ValidationLogic {
|
|||
}
|
||||
|
||||
struct ValidateBorrowLocalVars {
|
||||
uint256 principalBorrowBalance;
|
||||
uint256 currentLtv;
|
||||
uint256 currentLiquidationThreshold;
|
||||
uint256 requestedBorrowAmountETH;
|
||||
uint256 amountOfCollateralNeededETH;
|
||||
uint256 userCollateralBalanceETH;
|
||||
uint256 userBorrowBalanceETH;
|
||||
uint256 borrowBalanceIncrease;
|
||||
uint256 currentReserveStableRate;
|
||||
uint256 availableLiquidity;
|
||||
uint256 finalUserBorrowRate;
|
||||
uint256 healthFactor;
|
||||
DataTypes.InterestRateMode rateMode;
|
||||
bool healthFactorBelowThreshold;
|
||||
bool isActive;
|
||||
bool isFrozen;
|
||||
bool borrowingEnabled;
|
||||
|
@ -197,7 +190,7 @@ library ValidationLogic {
|
|||
* 3. Users will be able to borrow only a portion of the total available liquidity
|
||||
**/
|
||||
|
||||
if (vars.rateMode == DataTypes.InterestRateMode.STABLE) {
|
||||
if (interestRateMode == uint256(DataTypes.InterestRateMode.STABLE)) {
|
||||
//check if the borrow mode is stable and if stable rate borrowing is enabled on this reserve
|
||||
|
||||
require(vars.stableRateBorrowingEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED);
|
||||
|
|
|
@ -9,13 +9,18 @@ import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
|||
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
|
||||
import {IncentivizedERC20} from './IncentivizedERC20.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title Aave ERC20 AToken
|
||||
* @dev Implementation of the interest bearing token for the Aave protocol
|
||||
* @author Aave
|
||||
*/
|
||||
contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
||||
contract AToken is
|
||||
VersionedInitializable,
|
||||
IncentivizedERC20('ATOKEN_IMPL', 'ATOKEN_IMPL', 0),
|
||||
IAToken
|
||||
{
|
||||
using WadRayMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
|
@ -25,44 +30,46 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
bytes32 public constant PERMIT_TYPEHASH =
|
||||
keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
|
||||
|
||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||
uint256 public constant ATOKEN_REVISION = 0x1;
|
||||
address public immutable UNDERLYING_ASSET_ADDRESS;
|
||||
address public immutable RESERVE_TREASURY_ADDRESS;
|
||||
ILendingPool public immutable POOL;
|
||||
|
||||
/// @dev owner => next valid nonce to submit with permit()
|
||||
mapping(address => uint256) public _nonces;
|
||||
|
||||
bytes32 public DOMAIN_SEPARATOR;
|
||||
|
||||
modifier onlyLendingPool {
|
||||
require(_msgSender() == address(POOL), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
|
||||
_;
|
||||
}
|
||||
ILendingPool internal _pool;
|
||||
address internal _treasury;
|
||||
address internal _underlyingAsset;
|
||||
IAaveIncentivesController internal _incentivesController;
|
||||
|
||||
constructor(
|
||||
ILendingPool pool,
|
||||
address underlyingAssetAddress,
|
||||
address reserveTreasuryAddress,
|
||||
string memory tokenName,
|
||||
string memory tokenSymbol,
|
||||
address incentivesController
|
||||
) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) {
|
||||
POOL = pool;
|
||||
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
|
||||
RESERVE_TREASURY_ADDRESS = reserveTreasuryAddress;
|
||||
modifier onlyLendingPool {
|
||||
require(_msgSender() == address(_pool), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
|
||||
_;
|
||||
}
|
||||
|
||||
function getRevision() internal pure virtual override returns (uint256) {
|
||||
return ATOKEN_REVISION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initializes the aToken
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
|
||||
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
* @param incentivesController The smart contract managing potential incentives distribution
|
||||
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
|
||||
* @param aTokenName The name of the aToken
|
||||
* @param aTokenSymbol The symbol of the aToken
|
||||
*/
|
||||
function initialize(
|
||||
uint8 underlyingAssetDecimals,
|
||||
string calldata tokenName,
|
||||
string calldata tokenSymbol
|
||||
) external virtual initializer {
|
||||
ILendingPool pool,
|
||||
address treasury,
|
||||
address underlyingAsset,
|
||||
IAaveIncentivesController incentivesController,
|
||||
uint8 aTokenDecimals,
|
||||
string calldata aTokenName,
|
||||
string calldata aTokenSymbol
|
||||
) external override initializer {
|
||||
uint256 chainId;
|
||||
|
||||
//solium-disable-next-line
|
||||
|
@ -73,16 +80,21 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
DOMAIN_SEPARATOR = keccak256(
|
||||
abi.encode(
|
||||
EIP712_DOMAIN,
|
||||
keccak256(bytes(tokenName)),
|
||||
keccak256(bytes(aTokenName)),
|
||||
keccak256(EIP712_REVISION),
|
||||
chainId,
|
||||
address(this)
|
||||
)
|
||||
);
|
||||
|
||||
_setName(tokenName);
|
||||
_setSymbol(tokenSymbol);
|
||||
_setDecimals(underlyingAssetDecimals);
|
||||
_setName(aTokenName);
|
||||
_setSymbol(aTokenSymbol);
|
||||
_setDecimals(aTokenDecimals);
|
||||
|
||||
_pool = pool;
|
||||
_treasury = treasury;
|
||||
_underlyingAsset = underlyingAsset;
|
||||
_incentivesController = incentivesController;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +115,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
|
||||
_burn(user, amountScaled);
|
||||
|
||||
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
||||
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
|
||||
|
||||
emit Transfer(user, address(0), amount);
|
||||
emit Burn(user, receiverOfUnderlying, amount, index);
|
||||
|
@ -145,14 +157,16 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
return;
|
||||
}
|
||||
|
||||
address treasury = _treasury;
|
||||
|
||||
// Compared to the normal mint, we don't check for rounding errors.
|
||||
// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
|
||||
// In that case, the treasury will experience a (very small) loss, but it
|
||||
// wont cause potentially valid transactions to fail.
|
||||
_mint(RESERVE_TREASURY_ADDRESS, amount.rayDiv(index));
|
||||
_mint(treasury, amount.rayDiv(index));
|
||||
|
||||
emit Transfer(address(0), RESERVE_TREASURY_ADDRESS, amount);
|
||||
emit Mint(RESERVE_TREASURY_ADDRESS, amount, index);
|
||||
emit Transfer(address(0), treasury, amount);
|
||||
emit Mint(treasury, amount, index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,7 +199,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
override(IncentivizedERC20, IERC20)
|
||||
returns (uint256)
|
||||
{
|
||||
return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||
return super.balanceOf(user).rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,7 +240,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||
return currentSupplyScaled.rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,6 +251,41 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the Aave treasury, receiving the fees on this aToken
|
||||
**/
|
||||
function RESERVE_TREASURY_ADDRESS() public view returns (address) {
|
||||
return _treasury;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
**/
|
||||
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
|
||||
return _underlyingAsset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the lending pool where this aToken is used
|
||||
**/
|
||||
function POOL() public view returns (ILendingPool) {
|
||||
return _pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev For internal usage in the logic of the parent contract IncentivizedERC20
|
||||
**/
|
||||
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
|
||||
return _incentivesController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view override returns (IAaveIncentivesController) {
|
||||
return _getIncentivesController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
|
||||
* assets in borrow(), withdraw() and flashLoan()
|
||||
|
@ -250,7 +299,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
onlyLendingPool
|
||||
returns (uint256)
|
||||
{
|
||||
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
|
||||
IERC20(_underlyingAsset).safeTransfer(target, amount);
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
@ -305,7 +354,10 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
uint256 amount,
|
||||
bool validate
|
||||
) internal {
|
||||
uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
|
||||
address underlyingAsset = _underlyingAsset;
|
||||
ILendingPool pool = _pool;
|
||||
|
||||
uint256 index = pool.getReserveNormalizedIncome(underlyingAsset);
|
||||
|
||||
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
|
||||
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
|
||||
|
@ -313,14 +365,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
super._transfer(from, to, amount.rayDiv(index));
|
||||
|
||||
if (validate) {
|
||||
POOL.finalizeTransfer(
|
||||
UNDERLYING_ASSET_ADDRESS,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
fromBalanceBefore,
|
||||
toBalanceBefore
|
||||
);
|
||||
pool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
|
||||
}
|
||||
|
||||
emit BalanceTransfer(from, to, amount, index);
|
||||
|
|
|
@ -14,36 +14,17 @@ import {AToken} from './AToken.sol';
|
|||
contract DelegationAwareAToken is AToken {
|
||||
modifier onlyPoolAdmin {
|
||||
require(
|
||||
_msgSender() == ILendingPool(POOL).getAddressesProvider().getPoolAdmin(),
|
||||
_msgSender() == ILendingPool(_pool).getAddressesProvider().getPoolAdmin(),
|
||||
Errors.CALLER_NOT_POOL_ADMIN
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(
|
||||
ILendingPool pool,
|
||||
address underlyingAssetAddress,
|
||||
address reserveTreasury,
|
||||
string memory tokenName,
|
||||
string memory tokenSymbol,
|
||||
address incentivesController
|
||||
)
|
||||
public
|
||||
AToken(
|
||||
pool,
|
||||
underlyingAssetAddress,
|
||||
reserveTreasury,
|
||||
tokenName,
|
||||
tokenSymbol,
|
||||
incentivesController
|
||||
)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @dev Delegates voting power of the underlying asset to a `delegatee` address
|
||||
* @param delegatee The address that will receive the delegation
|
||||
**/
|
||||
function delegateUnderlyingTo(address delegatee) external onlyPoolAdmin {
|
||||
IDelegationToken(UNDERLYING_ASSET_ADDRESS).delegate(delegatee);
|
||||
IDelegationToken(_underlyingAsset).delegate(delegatee);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,9 @@ import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesControl
|
|||
* @notice Basic ERC20 implementation
|
||||
* @author Aave, inspired by the Openzeppelin ERC20 implementation
|
||||
**/
|
||||
contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
||||
abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
||||
using SafeMath for uint256;
|
||||
|
||||
IAaveIncentivesController internal immutable _incentivesController;
|
||||
|
||||
mapping(address => uint256) internal _balances;
|
||||
|
||||
mapping(address => mapping(address => uint256)) private _allowances;
|
||||
|
@ -28,13 +26,11 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
constructor(
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
uint8 decimals,
|
||||
address incentivesController
|
||||
uint8 decimals
|
||||
) public {
|
||||
_name = name;
|
||||
_symbol = symbol;
|
||||
_decimals = decimals;
|
||||
_incentivesController = IAaveIncentivesController(incentivesController);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,6 +68,12 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
return _balances[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Abstract function implemented by the child aToken/debtToken.
|
||||
* Done this way in order to not break compatibility with previous versions of aTokens/debtTokens
|
||||
**/
|
||||
function _getIncentivesController() internal view virtual returns(IAaveIncentivesController);
|
||||
|
||||
/**
|
||||
* @dev Executes a transfer of tokens from _msgSender() to recipient
|
||||
* @param recipient The recipient of the tokens
|
||||
|
@ -180,11 +182,11 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
uint256 oldRecipientBalance = _balances[recipient];
|
||||
_balances[recipient] = _balances[recipient].add(amount);
|
||||
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
uint256 currentTotalSupply = _totalSupply;
|
||||
_incentivesController.handleAction(sender, currentTotalSupply, oldSenderBalance);
|
||||
_getIncentivesController().handleAction(sender, currentTotalSupply, oldSenderBalance);
|
||||
if (sender != recipient) {
|
||||
_incentivesController.handleAction(recipient, currentTotalSupply, oldRecipientBalance);
|
||||
_getIncentivesController().handleAction(recipient, currentTotalSupply, oldRecipientBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,8 +202,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.add(amount);
|
||||
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,8 +218,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
|
||||
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import {DebtTokenBase} from './base/DebtTokenBase.sol';
|
|||
import {MathUtils} from '../libraries/math/MathUtils.sol';
|
||||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||
import {IStableDebtToken} from '../../interfaces/IStableDebtToken.sol';
|
||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||
|
||||
/**
|
||||
|
@ -23,13 +25,35 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
mapping(address => uint256) internal _usersStableRate;
|
||||
uint40 internal _totalSupplyTimestamp;
|
||||
|
||||
constructor(
|
||||
address pool,
|
||||
ILendingPool internal _pool;
|
||||
address internal _underlyingAsset;
|
||||
IAaveIncentivesController internal _incentivesController;
|
||||
|
||||
/**
|
||||
* @dev Initializes the debt token.
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
* @param incentivesController The smart contract managing potential incentives distribution
|
||||
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
|
||||
* @param debtTokenName The name of the token
|
||||
* @param debtTokenSymbol The symbol of the token
|
||||
*/
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address underlyingAsset,
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
address incentivesController
|
||||
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
|
||||
IAaveIncentivesController incentivesController,
|
||||
uint8 debtTokenDecimals,
|
||||
string memory debtTokenName,
|
||||
string memory debtTokenSymbol
|
||||
) public override initializer {
|
||||
_setName(debtTokenName);
|
||||
_setSymbol(debtTokenSymbol);
|
||||
_setDecimals(debtTokenDecimals);
|
||||
|
||||
_pool = pool;
|
||||
_underlyingAsset = underlyingAsset;
|
||||
_incentivesController = incentivesController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the revision of the stable debt token implementation
|
||||
|
@ -300,6 +324,48 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
return super.balanceOf(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
**/
|
||||
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
|
||||
return _underlyingAsset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the lending pool where this aToken is used
|
||||
**/
|
||||
function POOL() public view returns (ILendingPool) {
|
||||
return _pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view override returns (IAaveIncentivesController) {
|
||||
return _getIncentivesController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev For internal usage in the logic of the parent contracts
|
||||
**/
|
||||
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
|
||||
return _incentivesController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev For internal usage in the logic of the parent contracts
|
||||
**/
|
||||
function _getUnderlyingAssetAddress() internal view override returns (address) {
|
||||
return _underlyingAsset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev For internal usage in the logic of the parent contracts
|
||||
**/
|
||||
function _getLendingPool() internal view override returns (ILendingPool) {
|
||||
return _pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the total supply
|
||||
* @param avgRate The average rate at which the total supply increases
|
||||
|
|
|
@ -5,6 +5,8 @@ import {IVariableDebtToken} from '../../interfaces/IVariableDebtToken.sol';
|
|||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||
import {DebtTokenBase} from './base/DebtTokenBase.sol';
|
||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title VariableDebtToken
|
||||
|
@ -17,13 +19,35 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
|
||||
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
|
||||
|
||||
constructor(
|
||||
address pool,
|
||||
ILendingPool internal _pool;
|
||||
address internal _underlyingAsset;
|
||||
IAaveIncentivesController internal _incentivesController;
|
||||
|
||||
/**
|
||||
* @dev Initializes the debt token.
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
* @param incentivesController The smart contract managing potential incentives distribution
|
||||
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
|
||||
* @param debtTokenName The name of the token
|
||||
* @param debtTokenSymbol The symbol of the token
|
||||
*/
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address underlyingAsset,
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
address incentivesController
|
||||
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
|
||||
IAaveIncentivesController incentivesController,
|
||||
uint8 debtTokenDecimals,
|
||||
string memory debtTokenName,
|
||||
string memory debtTokenSymbol
|
||||
) public override initializer {
|
||||
_setName(debtTokenName);
|
||||
_setSymbol(debtTokenSymbol);
|
||||
_setDecimals(debtTokenDecimals);
|
||||
|
||||
_pool = pool;
|
||||
_underlyingAsset = underlyingAsset;
|
||||
_incentivesController = incentivesController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the revision of the stable debt token implementation
|
||||
|
@ -44,7 +68,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return scaledBalance.rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS));
|
||||
return scaledBalance.rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAsset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,8 +137,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
* @return The total supply
|
||||
**/
|
||||
function totalSupply() public view virtual override returns (uint256) {
|
||||
return
|
||||
super.totalSupply().rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS));
|
||||
return super.totalSupply().rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAsset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,4 +162,37 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
{
|
||||
return (super.balanceOf(user), super.totalSupply());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
|
||||
**/
|
||||
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
|
||||
return _underlyingAsset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the incentives controller contract
|
||||
**/
|
||||
function getIncentivesController() external view override returns (IAaveIncentivesController) {
|
||||
return _getIncentivesController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the lending pool where this aToken is used
|
||||
**/
|
||||
function POOL() public view returns (ILendingPool) {
|
||||
return _pool;
|
||||
}
|
||||
|
||||
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
|
||||
return _incentivesController;
|
||||
}
|
||||
|
||||
function _getUnderlyingAssetAddress() internal view override returns (address) {
|
||||
return _underlyingAsset;
|
||||
}
|
||||
|
||||
function _getLendingPool() internal view override returns (ILendingPool) {
|
||||
return _pool;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,54 +16,20 @@ import {Errors} from '../../libraries/helpers/Errors.sol';
|
|||
*/
|
||||
|
||||
abstract contract DebtTokenBase is
|
||||
IncentivizedERC20,
|
||||
IncentivizedERC20('DEBTTOKEN_IMPL', 'DEBTTOKEN_IMPL', 0),
|
||||
VersionedInitializable,
|
||||
ICreditDelegationToken
|
||||
{
|
||||
address public immutable UNDERLYING_ASSET_ADDRESS;
|
||||
ILendingPool public immutable POOL;
|
||||
|
||||
mapping(address => mapping(address => uint256)) internal _borrowAllowances;
|
||||
|
||||
/**
|
||||
* @dev Only lending pool can call functions marked by this modifier
|
||||
**/
|
||||
modifier onlyLendingPool {
|
||||
require(_msgSender() == address(POOL), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
|
||||
require(_msgSender() == address(_getLendingPool()), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev The metadata of the token will be set on the proxy, that the reason of
|
||||
* passing "NULL" and 0 as metadata
|
||||
*/
|
||||
constructor(
|
||||
address pool,
|
||||
address underlyingAssetAddress,
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
address incentivesController
|
||||
) public IncentivizedERC20(name, symbol, 18, incentivesController) {
|
||||
POOL = ILendingPool(pool);
|
||||
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initializes the debt token.
|
||||
* @param name The name of the token
|
||||
* @param symbol The symbol of the token
|
||||
* @param decimals The decimals of the token
|
||||
*/
|
||||
function initialize(
|
||||
uint8 decimals,
|
||||
string memory name,
|
||||
string memory symbol
|
||||
) public initializer {
|
||||
_setName(name);
|
||||
_setSymbol(symbol);
|
||||
_setDecimals(decimals);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev delegates borrowing power to a user on the specific debt token
|
||||
* @param delegatee the address receiving the delegated borrowing power
|
||||
|
@ -73,7 +39,7 @@ abstract contract DebtTokenBase is
|
|||
**/
|
||||
function approveDelegation(address delegatee, uint256 amount) external override {
|
||||
_borrowAllowances[_msgSender()][delegatee] = amount;
|
||||
emit BorrowAllowanceDelegated(_msgSender(), delegatee, UNDERLYING_ASSET_ADDRESS, amount);
|
||||
emit BorrowAllowanceDelegated(_msgSender(), delegatee, _getUnderlyingAssetAddress(), amount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,6 +128,10 @@ abstract contract DebtTokenBase is
|
|||
|
||||
_borrowAllowances[delegator][delegatee] = newAllowance;
|
||||
|
||||
emit BorrowAllowanceDelegated(delegator, delegatee, UNDERLYING_ASSET_ADDRESS, newAllowance);
|
||||
emit BorrowAllowanceDelegated(delegator, delegatee, _getUnderlyingAssetAddress(), newAllowance);
|
||||
}
|
||||
|
||||
function _getUnderlyingAssetAddress() internal view virtual returns (address);
|
||||
|
||||
function _getLendingPool() internal view virtual returns (ILendingPool);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user