mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Add permit support in swap adapters
This commit is contained in:
parent
e7183536b3
commit
fa7fa9f948
|
@ -12,6 +12,7 @@ import {ILendingPool} from '../interfaces/ILendingPool.sol';
|
|||
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
|
||||
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
|
||||
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
||||
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
||||
|
||||
/**
|
||||
* @title BaseUniswapAdapter
|
||||
|
@ -25,6 +26,20 @@ contract BaseUniswapAdapter {
|
|||
|
||||
enum LeftoverAction {DEPOSIT, TRANSFER}
|
||||
|
||||
struct PermitParams {
|
||||
uint256[] deadline;
|
||||
uint8[] v;
|
||||
bytes32[] r;
|
||||
bytes32[] s;
|
||||
}
|
||||
|
||||
struct PermitSignature {
|
||||
uint256 deadline;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
}
|
||||
|
||||
// Max slippage percent allow by param
|
||||
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
|
||||
// Min slippage percent allow by param
|
||||
|
@ -221,14 +236,28 @@ contract BaseUniswapAdapter {
|
|||
* @param reserve address of the asset
|
||||
* @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 user,
|
||||
uint256 amount
|
||||
uint256 amount,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
address reserveAToken = getAToken(reserve);
|
||||
|
||||
if (_usePermit(permitSignature)) {
|
||||
IERC20WithPermit(reserveAToken).permit(
|
||||
user,
|
||||
address(this),
|
||||
amount,
|
||||
permitSignature.deadline,
|
||||
permitSignature.v,
|
||||
permitSignature.r,
|
||||
permitSignature.s
|
||||
);
|
||||
}
|
||||
|
||||
// transfer from user to adapter
|
||||
IERC20(reserveAToken).safeTransferFrom(user, address(this), amount);
|
||||
|
||||
|
@ -241,15 +270,28 @@ contract BaseUniswapAdapter {
|
|||
* @param reserve address of the asset
|
||||
* @param user address
|
||||
* @param flashLoanDebt need to be repaid
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function pullATokenAndRepayFlashLoan(
|
||||
address reserve,
|
||||
address user,
|
||||
uint256 flashLoanDebt
|
||||
uint256 flashLoanDebt,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
pullAToken(reserve, user, flashLoanDebt);
|
||||
pullAToken(reserve, user, flashLoanDebt, permitSignature);
|
||||
|
||||
// Repay flashloan
|
||||
IERC20(reserve).approve(address(POOL), flashLoanDebt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@ import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
|||
**/
|
||||
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
||||
|
||||
struct SwapParams {
|
||||
address[] assetToSwapToList;
|
||||
uint256 slippage;
|
||||
PermitParams permitParams;
|
||||
}
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter
|
||||
|
@ -35,6 +41,10 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @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 slippage The max slippage percentage allowed for the swap
|
||||
* 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,
|
||||
|
@ -45,19 +55,46 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
) external override returns (bool) {
|
||||
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
|
||||
|
||||
(address[] memory assetToSwapToList, uint256 slippage) = abi.decode(params, (address[], uint256));
|
||||
require(slippage < MAX_SLIPPAGE_PERCENT && slippage >= MIN_SLIPPAGE_PERCENT, 'SLIPPAGE_OUT_OF_RANGE');
|
||||
require(assetToSwapToList.length == assets.length, 'INCONSISTENT_PARAMS');
|
||||
SwapParams memory decodedParams = _decodeParams(params);
|
||||
|
||||
require(
|
||||
decodedParams.slippage < MAX_SLIPPAGE_PERCENT && decodedParams.slippage >= MIN_SLIPPAGE_PERCENT,
|
||||
'SLIPPAGE_OUT_OF_RANGE'
|
||||
);
|
||||
|
||||
require(
|
||||
decodedParams.assetToSwapToList.length == assets.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'
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
uint256 receivedAmount = swapExactTokensForTokens(assets[i], assetToSwapToList[i], amounts[i], slippage);
|
||||
uint256 receivedAmount = swapExactTokensForTokens(
|
||||
assets[i],
|
||||
decodedParams.assetToSwapToList[i],
|
||||
amounts[i],
|
||||
decodedParams.slippage
|
||||
);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(assetToSwapToList[i], receivedAmount, initiator, 0);
|
||||
IERC20(decodedParams.assetToSwapToList[i]).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(decodedParams.assetToSwapToList[i], receivedAmount, initiator, 0);
|
||||
|
||||
uint256 flashLoanDebt = amounts[i].add(premiums[i]);
|
||||
pullATokenAndRepayFlashLoan(assets[i], initiator, flashLoanDebt);
|
||||
pullATokenAndRepayFlashLoan(
|
||||
assets[i],
|
||||
initiator,
|
||||
flashLoanDebt,
|
||||
PermitSignature(
|
||||
decodedParams.permitParams.deadline[i],
|
||||
decodedParams.permitParams.v[i],
|
||||
decodedParams.permitParams.r[i],
|
||||
decodedParams.permitParams.s[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -72,20 +109,32 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @param assetToSwapToList List of addresses of the underlying asset to be swap to and deposited
|
||||
* @param amountToSwapList List of amounts to be swapped
|
||||
* @param slippage The max slippage percentage allowed for the swap
|
||||
* 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 swapAndDeposit(
|
||||
address[] calldata assetToSwapFromList,
|
||||
address[] calldata assetToSwapToList,
|
||||
uint256[] calldata amountToSwapList,
|
||||
uint256 slippage
|
||||
uint256 slippage,
|
||||
PermitSignature[] calldata permitParams
|
||||
) external {
|
||||
require(
|
||||
assetToSwapFromList.length == assetToSwapToList.length && assetToSwapFromList.length == amountToSwapList.length,
|
||||
assetToSwapFromList.length == assetToSwapToList.length
|
||||
&& assetToSwapFromList.length == amountToSwapList.length
|
||||
&& assetToSwapFromList.length == permitParams.length,
|
||||
'INCONSISTENT_PARAMS'
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < assetToSwapFromList.length; i++) {
|
||||
pullAToken(assetToSwapFromList[i], msg.sender, amountToSwapList[i]);
|
||||
pullAToken(
|
||||
assetToSwapFromList[i],
|
||||
msg.sender,
|
||||
amountToSwapList[i],
|
||||
permitParams[i]
|
||||
);
|
||||
|
||||
uint256 receivedAmount = swapExactTokensForTokens(
|
||||
assetToSwapFromList[i],
|
||||
|
@ -99,4 +148,29 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decodes debt information encoded in flashloan 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 slippage The max slippage percentage allowed for the swap
|
||||
* uint256[] deadline List of deadlines 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
|
||||
* @return SwapParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal returns (SwapParams memory) {
|
||||
(
|
||||
address[] memory assetToSwapToList,
|
||||
uint256 slippage,
|
||||
uint256[] memory deadline,
|
||||
uint8[] memory v,
|
||||
bytes32[] memory r,
|
||||
bytes32[] memory s
|
||||
) = abi.decode(params, (address[], uint256, uint256[], uint8[], bytes32[], bytes32[]));
|
||||
|
||||
return SwapParams(assetToSwapToList, slippage, PermitParams(deadline, v, r, s));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
LeftoverAction leftOverAction;
|
||||
uint256[] repayAmounts;
|
||||
uint256[] rateModes;
|
||||
PermitParams permitParams;
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
@ -46,6 +47,10 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* (1) Direct transfer to user
|
||||
* uint256[] repayAmounts List of amounts of debt to be repaid
|
||||
* uint256[] rateModes List of the rate modes of the debt to be repaid
|
||||
* 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,
|
||||
|
@ -61,7 +66,11 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
require(
|
||||
assets.length == decodedParams.assetToSwapToList.length
|
||||
&& assets.length == decodedParams.repayAmounts.length
|
||||
&& assets.length == decodedParams.rateModes.length,
|
||||
&& assets.length == decodedParams.rateModes.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');
|
||||
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
|
@ -73,7 +82,13 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
decodedParams.rateModes[i],
|
||||
initiator,
|
||||
decodedParams.leftOverAction,
|
||||
premiums[i]
|
||||
premiums[i],
|
||||
PermitSignature(
|
||||
decodedParams.permitParams.deadline[i],
|
||||
decodedParams.permitParams.v[i],
|
||||
decodedParams.permitParams.r[i],
|
||||
decodedParams.permitParams.s[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -91,6 +106,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @param initiator Address of the user
|
||||
* @param leftOverAction enum indicating what to do with the left over balance from the swap
|
||||
* @param premium Fee of the flash loan
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function _swapAndRepay(
|
||||
address assetFrom,
|
||||
|
@ -100,7 +116,8 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
uint256 rateMode,
|
||||
address initiator,
|
||||
LeftoverAction leftOverAction,
|
||||
uint256 premium
|
||||
uint256 premium,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
swapTokensForExactTokens(assetFrom, assetTo, amount, repayAmount);
|
||||
|
||||
|
@ -109,7 +126,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
POOL.repay(assetTo, repayAmount, rateMode, initiator);
|
||||
|
||||
uint256 flashLoanDebt = amount.add(premium);
|
||||
pullATokenAndRepayFlashLoan(assetFrom, initiator, flashLoanDebt);
|
||||
pullATokenAndRepayFlashLoan(assetFrom, initiator, flashLoanDebt, permitSignature);
|
||||
|
||||
// Take care of reserve leftover from the swap
|
||||
sendLeftovers(assetFrom, flashLoanDebt, leftOverAction, initiator);
|
||||
|
@ -124,6 +141,10 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* (1) Direct transfer to user
|
||||
* uint256[] repayAmounts List of amounts of debt to be repaid
|
||||
* uint256[] rateModes List of the rate modes of the debt to be repaid
|
||||
* 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
|
||||
* @return RepayParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal returns (RepayParams memory) {
|
||||
|
@ -131,9 +152,24 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
address[] memory assetToSwapToList,
|
||||
LeftoverAction leftOverAction,
|
||||
uint256[] memory repayAmounts,
|
||||
uint256[] memory rateModes
|
||||
) = abi.decode(params, (address[], LeftoverAction, uint256[], uint256[]));
|
||||
uint256[] memory rateModes,
|
||||
uint256[] memory deadline,
|
||||
uint8[] memory v,
|
||||
bytes32[] memory r,
|
||||
bytes32[] memory s
|
||||
) = abi.decode(params, (address[], LeftoverAction, uint256[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
|
||||
|
||||
return RepayParams(assetToSwapToList, leftOverAction, repayAmounts, rateModes);
|
||||
return RepayParams(
|
||||
assetToSwapToList,
|
||||
leftOverAction,
|
||||
repayAmounts,
|
||||
rateModes,
|
||||
PermitParams(
|
||||
deadline,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
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.8;
|
||||
|
||||
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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user