adoption to the latest

This commit is contained in:
andyk 2020-11-30 17:14:29 +04:00
parent b4a0841577
commit a21757d0fc
9 changed files with 370 additions and 252 deletions

View File

@ -8,70 +8,65 @@ 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 {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {ILendingPool} from '../interfaces/ILendingPool.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
**/
contract BaseUniswapAdapter {
abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapter {
using SafeMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20;
struct PermitSignature {
uint256 amount;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
struct AmountCalc {
uint256 calculatedAmount;
uint256 relativePrice;
uint256 amountInUsd;
uint256 amountOutUsd;
}
// Max slippage percent allowed
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
uint256 public constant override MAX_SLIPPAGE_PERCENT = 3000; // 30%
// FLash Loan fee set in lending pool
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
uint256 public constant override FLASHLOAN_PREMIUM_TOTAL = 9;
// USD oracle asset address
address public constant USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
address public constant override USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
ILendingPool public immutable POOL;
IPriceOracleGetter public immutable ORACLE;
IUniswapV2Router02 public immutable UNISWAP_ROUTER;
IPriceOracleGetter public immutable override ORACLE;
IUniswapV2Router02 public immutable override UNISWAP_ROUTER;
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter) public {
POOL = ILendingPool(addressesProvider.getLendingPool());
constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter)
public
FlashLoanReceiverBase(addressesProvider)
{
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
UNISWAP_ROUTER = uniswapRouter;
}
/**
* @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)
* @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
returns (uint256, uint256, uint256, uint256)
override
returns (
uint256,
uint256,
uint256,
uint256
)
{
AmountCalc memory results = _getAmountsOutData(reserveIn, reserveOut, amountIn);
@ -93,10 +88,20 @@ contract BaseUniswapAdapter {
* @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)
function getAmountsIn(
uint256 amountOut,
address reserveIn,
address reserveOut
)
external
view
returns (uint256, uint256, uint256, uint256)
override
returns (
uint256,
uint256,
uint256,
uint256
)
{
AmountCalc memory results = _getAmountsInData(reserveIn, reserveOut, amountOut);
@ -121,20 +126,18 @@ contract BaseUniswapAdapter {
address assetToSwapTo,
uint256 amountToSwap,
uint256 minAmountOut
)
internal
returns (uint256)
{
) 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));
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');
@ -143,7 +146,14 @@ contract BaseUniswapAdapter {
address[] memory path = new address[](2);
path[0] = assetToSwapFrom;
path[1] = assetToSwapTo;
uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, minAmountOut, path, address(this), block.timestamp);
uint256[] memory amounts =
UNISWAP_ROUTER.swapExactTokensForTokens(
amountToSwap,
minAmountOut,
path,
address(this),
block.timestamp
);
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
@ -164,20 +174,18 @@ contract BaseUniswapAdapter {
address assetToSwapTo,
uint256 maxAmountToSwap,
uint256 amountToReceive
)
internal
returns (uint256)
{
) 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));
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');
@ -186,7 +194,14 @@ contract BaseUniswapAdapter {
address[] memory path = new address[](2);
path[0] = assetToSwapFrom;
path[1] = assetToSwapTo;
uint256[] memory amounts = UNISWAP_ROUTER.swapTokensForExactTokens(amountToReceive, maxAmountToSwap, path, address(this), block.timestamp);
uint256[] memory amounts =
UNISWAP_ROUTER.swapTokensForExactTokens(
amountToReceive,
maxAmountToSwap,
path,
address(this),
block.timestamp
);
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
@ -215,7 +230,7 @@ contract BaseUniswapAdapter {
* @return address of the aToken
*/
function _getReserveData(address asset) internal view returns (DataTypes.ReserveData memory) {
return POOL.getReserveData(asset);
return LENDING_POOL.getReserveData(asset);
}
/**
@ -249,7 +264,7 @@ contract BaseUniswapAdapter {
IERC20(reserveAToken).safeTransferFrom(user, address(this), amount);
// withdraw reserve
POOL.withdraw(reserve, amount, address(this));
LENDING_POOL.withdraw(reserve, amount, address(this));
}
/**
@ -259,7 +274,8 @@ contract BaseUniswapAdapter {
* @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);
return
!(uint256(signature.deadline) == uint256(signature.v) && uint256(signature.deadline) == 0);
}
/**
@ -269,15 +285,15 @@ contract BaseUniswapAdapter {
* @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) {
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);
return amount.mul(reservePrice).div(10**decimals).mul(ethUsdPrice).div(10**18);
}
/**
@ -291,7 +307,11 @@ contract BaseUniswapAdapter {
* 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) {
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));
@ -304,17 +324,18 @@ contract BaseUniswapAdapter {
uint256 reserveInDecimals = _getDecimals(reserveIn);
uint256 reserveOutDecimals = _getDecimals(reserveOut);
uint256 outPerInPrice = finalAmountIn
.mul(10**18)
.mul(10**reserveOutDecimals)
.div(amounts[1].mul(10**reserveInDecimals));
uint256 outPerInPrice =
finalAmountIn.mul(10**18).mul(10**reserveOutDecimals).div(
amounts[1].mul(10**reserveInDecimals)
);
return AmountCalc(
amounts[1],
outPerInPrice,
_calcUsdValue(reserveIn, amountIn, reserveInDecimals),
_calcUsdValue(reserveOut, amounts[1], reserveOutDecimals)
);
return
AmountCalc(
amounts[1],
outPerInPrice,
_calcUsdValue(reserveIn, amountIn, reserveInDecimals),
_calcUsdValue(reserveOut, amounts[1], reserveOutDecimals)
);
}
/**
@ -328,7 +349,11 @@ contract BaseUniswapAdapter {
* 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) {
function _getAmountsInData(
address reserveIn,
address reserveOut,
uint256 amountOut
) internal view returns (AmountCalc memory) {
uint256[] memory amounts = _getAmountsIn(reserveIn, reserveOut, amountOut);
// Add flash loan fee
@ -337,27 +362,32 @@ contract BaseUniswapAdapter {
uint256 reserveInDecimals = _getDecimals(reserveIn);
uint256 reserveOutDecimals = _getDecimals(reserveOut);
uint256 inPerOutPrice = amountOut
.mul(10**18)
.mul(10**reserveInDecimals)
.div(finalAmountIn.mul(10**reserveOutDecimals));
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)
);
return
AmountCalc(
finalAmountIn,
inPerOutPrice,
_calcUsdValue(reserveIn, finalAmountIn, reserveInDecimals),
_calcUsdValue(reserveOut, amountOut, reserveOutDecimals)
);
}
/**
* @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) internal view returns (uint256[] memory) {
* @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
) internal view returns (uint256[] memory) {
address[] memory path = new address[](2);
path[0] = reserveIn;
path[1] = reserveOut;

View File

@ -5,7 +5,6 @@ pragma experimental ABIEncoderV2;
import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
/**
@ -13,8 +12,7 @@ import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
* @notice Uniswap V2 Adapter to swap liquidity.
* @author Aave
**/
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
struct PermitParams {
uint256[] amount;
uint256[] deadline;
@ -30,10 +28,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
PermitParams permitParams;
}
constructor(
ILendingPoolAddressesProvider addressesProvider,
IUniswapV2Router02 uniswapRouter
)
constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter)
public
BaseUniswapAdapter(addressesProvider, uniswapRouter)
{}
@ -64,19 +59,19 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
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.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,
'INCONSISTENT_PARAMS'
);
@ -127,10 +122,10 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
PermitSignature[] calldata permitParams
) external {
require(
assetToSwapFromList.length == assetToSwapToList.length
&& assetToSwapFromList.length == amountToSwapList.length
&& assetToSwapFromList.length == minAmountsToReceive.length
&& assetToSwapFromList.length == permitParams.length,
assetToSwapFromList.length == assetToSwapToList.length &&
assetToSwapFromList.length == amountToSwapList.length &&
assetToSwapFromList.length == minAmountsToReceive.length &&
assetToSwapFromList.length == permitParams.length,
'INCONSISTENT_PARAMS'
);
@ -138,26 +133,22 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
address aToken = _getReserveData(assetToSwapFromList[i]).aTokenAddress;
uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(msg.sender);
uint256 amountToSwap = amountToSwapList[i] > aTokenInitiatorBalance ? aTokenInitiatorBalance : amountToSwapList[i];
uint256 amountToSwap =
amountToSwapList[i] > aTokenInitiatorBalance ? aTokenInitiatorBalance : amountToSwapList[i];
_pullAToken(
assetToSwapFromList[i],
aToken,
msg.sender,
amountToSwap,
permitParams[i]
);
_pullAToken(assetToSwapFromList[i], aToken, msg.sender, amountToSwap, permitParams[i]);
uint256 receivedAmount = _swapExactTokensForTokens(
assetToSwapFromList[i],
assetToSwapToList[i],
amountToSwap,
minAmountsToReceive[i]
);
uint256 receivedAmount =
_swapExactTokensForTokens(
assetToSwapFromList[i],
assetToSwapToList[i],
amountToSwap,
minAmountsToReceive[i]
);
// Deposit new reserve
IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
IERC20(assetToSwapToList[i]).approve(address(LENDING_POOL), receivedAmount);
LENDING_POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
}
}
@ -184,20 +175,17 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
address aToken = _getReserveData(assetFrom).aTokenAddress;
uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(initiator);
uint256 amountToSwap = swapAllBalance && aTokenInitiatorBalance.sub(premium) <= amount
? aTokenInitiatorBalance.sub(premium)
: amount;
uint256 amountToSwap =
swapAllBalance && aTokenInitiatorBalance.sub(premium) <= amount
? aTokenInitiatorBalance.sub(premium)
: amount;
uint256 receivedAmount = _swapExactTokensForTokens(
assetFrom,
assetTo,
amountToSwap,
minAmountToReceive
);
uint256 receivedAmount =
_swapExactTokensForTokens(assetFrom, assetTo, amountToSwap, minAmountToReceive);
// Deposit new reserve
IERC20(assetTo).approve(address(POOL), receivedAmount);
POOL.deposit(assetTo, receivedAmount, initiator, 0);
IERC20(assetTo).approve(address(LENDING_POOL), receivedAmount);
LENDING_POOL.deposit(assetTo, receivedAmount, initiator, 0);
uint256 flashLoanDebt = amount.add(premium);
uint256 amountToPull = amountToSwap.add(premium);
@ -205,7 +193,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
_pullAToken(assetFrom, aToken, initiator, amountToPull, permitSignature);
// Repay flash loan
IERC20(assetFrom).approve(address(POOL), flashLoanDebt);
IERC20(assetFrom).approve(address(LENDING_POOL), flashLoanDebt);
}
/**
@ -231,19 +219,18 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s
) = abi.decode(params, (address[], uint256[], bool[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
) =
abi.decode(
params,
(address[], uint256[], bool[], uint256[], uint256[], uint8[], bytes32[], bytes32[])
);
return SwapParams(
assetToSwapToList,
minAmountsToReceive,
swapAllBalance,
PermitParams(
permitAmount,
deadline,
v,
r,
s
)
);
return
SwapParams(
assetToSwapToList,
minAmountsToReceive,
swapAllBalance,
PermitParams(permitAmount, deadline, v, r, s)
);
}
}

View File

@ -5,7 +5,6 @@ pragma experimental ABIEncoderV2;
import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
@ -14,8 +13,7 @@ import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
* @notice Uniswap V2 Adapter to perform a repay of a debt with collateral.
* @author Aave
**/
contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
contract UniswapRepayAdapter is BaseUniswapAdapter {
struct RepayParams {
address collateralAsset;
uint256 collateralAmount;
@ -23,10 +21,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
PermitSignature permitSignature;
}
constructor(
ILendingPoolAddressesProvider addressesProvider,
IUniswapV2Router02 uniswapRouter
)
constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter)
public
BaseUniswapAdapter(addressesProvider, uniswapRouter)
{}
@ -58,20 +53,20 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
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
);
_swapAndRepay(
decodedParams.collateralAsset,
assets[0],
amounts[0],
decodedParams.collateralAmount,
decodedParams.rateMode,
initiator,
premiums[0],
decodedParams.permitSignature
);
return true;
}
@ -99,9 +94,10 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
DataTypes.ReserveData memory debtReserveData = _getReserveData(debtAsset);
address debtToken = DataTypes.InterestRateMode(debtRateMode) == DataTypes.InterestRateMode.STABLE
? debtReserveData.stableDebtTokenAddress
: debtReserveData.variableDebtTokenAddress;
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;
@ -117,21 +113,32 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
require(amounts[0] <= maxCollateralToSwap, 'slippage too high');
// Pull aTokens from user
_pullAToken(collateralAsset, collateralReserveData.aTokenAddress, msg.sender, amounts[0], permitSignature);
_pullAToken(
collateralAsset,
collateralReserveData.aTokenAddress,
msg.sender,
amounts[0],
permitSignature
);
// Swap collateral for debt asset
_swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], amountToRepay);
} else {
// Pull aTokens from user
_pullAToken(collateralAsset, collateralReserveData.aTokenAddress, msg.sender, amountToRepay, permitSignature);
_pullAToken(
collateralAsset,
collateralReserveData.aTokenAddress,
msg.sender,
amountToRepay,
permitSignature
);
}
// Repay debt
IERC20(debtAsset).approve(address(POOL), amountToRepay);
POOL.repay(debtAsset, amountToRepay, debtRateMode, msg.sender);
IERC20(debtAsset).approve(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
*
@ -157,9 +164,9 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
// Repay debt
IERC20(debtAsset).approve(address(POOL), amount);
IERC20(debtAsset).approve(address(LENDING_POOL), amount);
uint256 repaidAmount = IERC20(debtAsset).balanceOf(address(this));
POOL.repay(debtAsset, amount, rateMode, initiator);
LENDING_POOL.repay(debtAsset, amount, rateMode, initiator);
repaidAmount = repaidAmount.sub(IERC20(debtAsset).balanceOf(address(this)));
if (collateralAsset != debtAsset) {
@ -195,7 +202,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
}
// Repay flash loan
IERC20(debtAsset).approve(address(POOL), amount.add(premium));
IERC20(debtAsset).approve(address(LENDING_POOL), amount.add(premium));
}
/**
@ -223,17 +230,12 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
bytes32 s
) = abi.decode(params, (address, uint256, uint256, uint256, uint256, uint8, bytes32, bytes32));
return RepayParams(
collateralAsset,
collateralAmount,
rateMode,
PermitSignature(
permitAmount,
deadline,
v,
r,
s
)
);
return
RepayParams(
collateralAsset,
collateralAmount,
rateMode,
PermitSignature(permitAmount, deadline, v, r, s)
);
}
}

View File

@ -0,0 +1,83 @@
// 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;
}
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)
*/
function getAmountsOut(
uint256 amountIn,
address reserveIn,
address reserveOut
)
external
view
returns (
uint256,
uint256,
uint256,
uint256
);
/**
* @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
returns (
uint256,
uint256,
uint256,
uint256
);
}

View File

@ -1,10 +1,13 @@
import path from 'path';
import fs from 'fs';
import {HardhatUserConfig} from 'hardhat/types';
import { HardhatUserConfig } from 'hardhat/types';
require('dotenv').config();
// @ts-ignore
import {accounts} from './test-wallets.js';
import {eEthereumNetwork} from './helpers/types';
import {BUIDLEREVM_CHAINID, COVERAGE_CHAINID} from './helpers/buidler-constants';
import { accounts } from './test-wallets.js';
import { eEthereumNetwork } from './helpers/types';
import { BUIDLEREVM_CHAINID, COVERAGE_CHAINID } from './helpers/buidler-constants';
import '@nomiclabs/hardhat-ethers';
import '@nomiclabs/hardhat-waffle';
@ -27,7 +30,7 @@ const MAINNET_FORK = process.env.MAINNET_FORK === 'true';
// Prevent to load scripts before compilation and typechain
if (!SKIP_LOAD) {
['misc', 'migrations', 'dev', 'full', 'verifications'].forEach((folder) => {
['misc', 'migrations', 'dev', 'full', 'verifications', 'deployments'].forEach((folder) => {
const tasksPath = path.join(__dirname, 'tasks', folder);
fs.readdirSync(tasksPath)
.filter((pth) => pth.includes('.ts'))
@ -73,7 +76,7 @@ const buidlerConfig: HardhatUserConfig = {
solidity: {
version: '0.6.12',
settings: {
optimizer: {enabled: true, runs: 200},
optimizer: { enabled: true, runs: 200 },
evmVersion: 'istanbul',
},
},
@ -109,7 +112,7 @@ const buidlerConfig: HardhatUserConfig = {
chainId: BUIDLEREVM_CHAINID,
throwOnTransactionFailures: true,
throwOnCallFailures: true,
accounts: accounts.map(({secretKey, balance}: {secretKey: string; balance: string}) => ({
accounts: accounts.map(({ secretKey, balance }: { secretKey: string; balance: string }) => ({
privateKey: secretKey,
balance,
})),

62
package-lock.json generated
View File

@ -9504,14 +9504,6 @@
"prr": "~1.0.1",
"semver": "~5.4.1",
"xtend": "~4.0.0"
},
"dependencies": {
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
}
}
},
"merkle-patricia-tree": {
@ -9901,14 +9893,6 @@
"prr": "~1.0.1",
"semver": "~5.4.1",
"xtend": "~4.0.0"
},
"dependencies": {
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
}
}
},
"merkle-patricia-tree": {
@ -10200,14 +10184,6 @@
"prr": "~1.0.1",
"semver": "~5.4.1",
"xtend": "~4.0.0"
},
"dependencies": {
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
}
}
},
"merkle-patricia-tree": {
@ -10459,14 +10435,6 @@
"prr": "~1.0.1",
"semver": "~5.4.1",
"xtend": "~4.0.0"
},
"dependencies": {
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
}
}
},
"merkle-patricia-tree": {
@ -12428,6 +12396,17 @@
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"safe-buffer": {
@ -12436,6 +12415,11 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@ -14250,6 +14234,12 @@
"integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==",
"dev": true
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
},
"semver-greatest-satisfied-range": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
@ -16306,14 +16296,6 @@
"prr": "~1.0.1",
"semver": "~5.4.1",
"xtend": "~4.0.0"
},
"dependencies": {
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
}
}
},
"merkle-patricia-tree": {

View File

@ -43,6 +43,7 @@
"print-contracts:main": "npm run hardhat:main -- print-contracts",
"print-contracts:ropsten": "npm run hardhat:main -- print-contracts",
"dev:deployUIProvider": "npm run hardhat:kovan deploy-UiPoolDataProvider",
"dev:deployUniswapRepayAdapter": "npm run hardhat:kovan deploy-UniswapRepayAdapter",
"kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave",
"ropsten:verify": "npm run hardhat:ropsten verify:general -- --all --pool Aave",
"mainnet:verify": "npm run hardhat:main verify:general -- --all --pool Aave",

View File

@ -1,13 +1,13 @@
import {task} from '@nomiclabs/buidler/config';
import { task } from 'hardhat/config';
import {UiPoolDataProviderFactory} from '../../types';
import {verifyContract} from '../../helpers/etherscan-verification';
import {eContractid} from '../../helpers/types';
import { UiPoolDataProviderFactory } from '../../types';
import { verifyContract } from '../../helpers/etherscan-verification';
import { eContractid } from '../../helpers/types';
task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider contract`)
.addFlag('verify', 'Verify UiPoolDataProvider contract via Etherscan API.')
.setAction(async ({verify}, localBRE) => {
await localBRE.run('set-bre');
.setAction(async ({ verify }, localBRE) => {
await localBRE.run('set-DRE');
if (!localBRE.network.config.chainId) {
throw new Error('INVALID_CHAIN_ID');
@ -21,7 +21,7 @@ task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider
).deploy();
await uiPoolDataProvider.deployTransaction.wait();
console.log('uiPoolDataProvider.address', uiPoolDataProvider.address);
await verifyContract(eContractid.UiPoolDataProvider, uiPoolDataProvider.address, []);
await verifyContract(uiPoolDataProvider.address, []);
console.log(`\tFinished UiPoolDataProvider proxy and implementation deployment`);
});

View File

@ -0,0 +1,30 @@
import { task } from 'hardhat/config';
import { UniswapRepayAdapterFactory } from '../../types';
import { verifyContract } from '../../helpers/etherscan-verification';
const CONTRACT_NAME = 'UniswapRepayAdapter';
task(`deploy-${CONTRACT_NAME}`, `Deploys the UniswapRepayAdapter contract`)
.addFlag('verify', 'Verify UniswapRepayAdapter contract via Etherscan API.')
.setAction(async ({ verify }, localBRE) => {
await localBRE.run('set-DRE');
if (!localBRE.network.config.chainId) {
throw new Error('INVALID_CHAIN_ID');
}
console.log(`\n- UniswapRepayAdapter deployment`);
const args = [
'0x9fe532197ad76c5a68961439604c037eb79681f0',
'0xfcd87315f0e4067070ade8682fcdbc3006631441',
];
const uniswapRepayAdapter = await new UniswapRepayAdapterFactory(
await localBRE.ethers.provider.getSigner()
).deploy(args[0], args[1]);
await uniswapRepayAdapter.deployTransaction.wait();
console.log('uniswapRepayAdapter.address', uniswapRepayAdapter.address);
await verifyContract(uniswapRepayAdapter.address, args);
console.log(`\tFinished UiPoolDataProvider proxy and implementation deployment`);
});