mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'master' into feat/188-avalanche-market
This commit is contained in:
commit
dc65b0b62e
122
contracts/adapters/BaseParaSwapAdapter.sol
Normal file
122
contracts/adapters/BaseParaSwapAdapter.sol
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
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 {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
||||||
|
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
||||||
|
import {FlashLoanReceiverBase} from '../flashloan/base/FlashLoanReceiverBase.sol';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title BaseParaSwapAdapter
|
||||||
|
* @notice Utility functions for adapters using ParaSwap
|
||||||
|
* @author Jason Raymond Bell
|
||||||
|
*/
|
||||||
|
abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable {
|
||||||
|
using SafeMath for uint256;
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
using SafeERC20 for IERC20Detailed;
|
||||||
|
using SafeERC20 for IERC20WithPermit;
|
||||||
|
|
||||||
|
struct PermitSignature {
|
||||||
|
uint256 amount;
|
||||||
|
uint256 deadline;
|
||||||
|
uint8 v;
|
||||||
|
bytes32 r;
|
||||||
|
bytes32 s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max slippage percent allowed
|
||||||
|
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
|
||||||
|
|
||||||
|
IPriceOracleGetter public immutable ORACLE;
|
||||||
|
|
||||||
|
event Swapped(address indexed fromAsset, address indexed toAsset, uint256 fromAmount, uint256 receivedAmount);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
ILendingPoolAddressesProvider addressesProvider
|
||||||
|
) public FlashLoanReceiverBase(addressesProvider) {
|
||||||
|
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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(IERC20Detailed asset) internal view returns (uint8) {
|
||||||
|
uint8 decimals = asset.decimals();
|
||||||
|
// Ensure 10**decimals won't overflow a uint256
|
||||||
|
require(decimals <= 77, 'TOO_MANY_DECIMALS_ON_TOKEN');
|
||||||
|
return 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 _pullATokenAndWithdraw(
|
||||||
|
address reserve,
|
||||||
|
IERC20WithPermit reserveAToken,
|
||||||
|
address user,
|
||||||
|
uint256 amount,
|
||||||
|
PermitSignature memory permitSignature
|
||||||
|
) internal {
|
||||||
|
// If deadline is set to zero, assume there is no signature for permit
|
||||||
|
if (permitSignature.deadline != 0) {
|
||||||
|
reserveAToken.permit(
|
||||||
|
user,
|
||||||
|
address(this),
|
||||||
|
permitSignature.amount,
|
||||||
|
permitSignature.deadline,
|
||||||
|
permitSignature.v,
|
||||||
|
permitSignature.r,
|
||||||
|
permitSignature.s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer from user to adapter
|
||||||
|
reserveAToken.safeTransferFrom(user, address(this), amount);
|
||||||
|
|
||||||
|
// withdraw reserve
|
||||||
|
require(
|
||||||
|
LENDING_POOL.withdraw(reserve, amount, address(this)) == amount,
|
||||||
|
'UNEXPECTED_AMOUNT_WITHDRAWN'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.safeTransfer(owner(), token.balanceOf(address(this)));
|
||||||
|
}
|
||||||
|
}
|
109
contracts/adapters/BaseParaSwapSellAdapter.sol
Normal file
109
contracts/adapters/BaseParaSwapSellAdapter.sol
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {BaseParaSwapAdapter} from './BaseParaSwapAdapter.sol';
|
||||||
|
import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
|
||||||
|
import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol';
|
||||||
|
import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol';
|
||||||
|
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
||||||
|
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title BaseParaSwapSellAdapter
|
||||||
|
* @notice Implements the logic for selling tokens on ParaSwap
|
||||||
|
* @author Jason Raymond Bell
|
||||||
|
*/
|
||||||
|
abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter {
|
||||||
|
using PercentageMath for uint256;
|
||||||
|
|
||||||
|
IParaSwapAugustusRegistry public immutable AUGUSTUS_REGISTRY;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
ILendingPoolAddressesProvider addressesProvider,
|
||||||
|
IParaSwapAugustusRegistry augustusRegistry
|
||||||
|
) public BaseParaSwapAdapter(addressesProvider) {
|
||||||
|
// Do something on Augustus registry to check the right contract was passed
|
||||||
|
require(!augustusRegistry.isValidAugustus(address(0)));
|
||||||
|
AUGUSTUS_REGISTRY = augustusRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Swaps a token for another using ParaSwap
|
||||||
|
* @param fromAmountOffset Offset of fromAmount in Augustus calldata if it should be overwritten, otherwise 0
|
||||||
|
* @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
||||||
|
* @param augustus Address of ParaSwap's AugustusSwapper contract
|
||||||
|
* @param assetToSwapFrom Address of the asset to be swapped from
|
||||||
|
* @param assetToSwapTo Address of the asset to be swapped to
|
||||||
|
* @param amountToSwap Amount to be swapped
|
||||||
|
* @param minAmountToReceive Minimum amount to be received from the swap
|
||||||
|
* @return amountReceived The amount received from the swap
|
||||||
|
*/
|
||||||
|
function _sellOnParaSwap(
|
||||||
|
uint256 fromAmountOffset,
|
||||||
|
bytes memory swapCalldata,
|
||||||
|
IParaSwapAugustus augustus,
|
||||||
|
IERC20Detailed assetToSwapFrom,
|
||||||
|
IERC20Detailed assetToSwapTo,
|
||||||
|
uint256 amountToSwap,
|
||||||
|
uint256 minAmountToReceive
|
||||||
|
) internal returns (uint256 amountReceived) {
|
||||||
|
require(AUGUSTUS_REGISTRY.isValidAugustus(address(augustus)), 'INVALID_AUGUSTUS');
|
||||||
|
|
||||||
|
{
|
||||||
|
uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
|
||||||
|
uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
|
||||||
|
|
||||||
|
uint256 fromAssetPrice = _getPrice(address(assetToSwapFrom));
|
||||||
|
uint256 toAssetPrice = _getPrice(address(assetToSwapTo));
|
||||||
|
|
||||||
|
uint256 expectedMinAmountOut =
|
||||||
|
amountToSwap
|
||||||
|
.mul(fromAssetPrice.mul(10**toAssetDecimals))
|
||||||
|
.div(toAssetPrice.mul(10**fromAssetDecimals))
|
||||||
|
.percentMul(PercentageMath.PERCENTAGE_FACTOR - MAX_SLIPPAGE_PERCENT);
|
||||||
|
|
||||||
|
require(expectedMinAmountOut <= minAmountToReceive, 'MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE');
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 balanceBeforeAssetFrom = assetToSwapFrom.balanceOf(address(this));
|
||||||
|
require(balanceBeforeAssetFrom >= amountToSwap, 'INSUFFICIENT_BALANCE_BEFORE_SWAP');
|
||||||
|
uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this));
|
||||||
|
|
||||||
|
address tokenTransferProxy = augustus.getTokenTransferProxy();
|
||||||
|
assetToSwapFrom.safeApprove(tokenTransferProxy, 0);
|
||||||
|
assetToSwapFrom.safeApprove(tokenTransferProxy, amountToSwap);
|
||||||
|
|
||||||
|
if (fromAmountOffset != 0) {
|
||||||
|
// Ensure 256 bit (32 bytes) fromAmount value is within bounds of the
|
||||||
|
// calldata, not overlapping with the first 4 bytes (function selector).
|
||||||
|
require(fromAmountOffset >= 4 &&
|
||||||
|
fromAmountOffset <= swapCalldata.length.sub(32),
|
||||||
|
'FROM_AMOUNT_OFFSET_OUT_OF_RANGE');
|
||||||
|
// Overwrite the fromAmount with the correct amount for the swap.
|
||||||
|
// In memory, swapCalldata consists of a 256 bit length field, followed by
|
||||||
|
// the actual bytes data, that is why 32 is added to the byte offset.
|
||||||
|
assembly {
|
||||||
|
mstore(add(swapCalldata, add(fromAmountOffset, 32)), amountToSwap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(bool success,) = address(augustus).call(swapCalldata);
|
||||||
|
if (!success) {
|
||||||
|
// Copy revert reason from call
|
||||||
|
assembly {
|
||||||
|
returndatacopy(0, 0, returndatasize())
|
||||||
|
revert(0, returndatasize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(assetToSwapFrom.balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP');
|
||||||
|
amountReceived = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
|
||||||
|
require(amountReceived >= minAmountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');
|
||||||
|
|
||||||
|
emit Swapped(
|
||||||
|
address(assetToSwapFrom),
|
||||||
|
address(assetToSwapTo),
|
||||||
|
amountToSwap,
|
||||||
|
amountReceived
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
210
contracts/adapters/ParaSwapLiquiditySwapAdapter.sol
Normal file
210
contracts/adapters/ParaSwapLiquiditySwapAdapter.sol
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {BaseParaSwapSellAdapter} from './BaseParaSwapSellAdapter.sol';
|
||||||
|
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
||||||
|
import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol';
|
||||||
|
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
||||||
|
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
||||||
|
import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol';
|
||||||
|
import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/ReentrancyGuard.sol';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title ParaSwapLiquiditySwapAdapter
|
||||||
|
* @notice Adapter to swap liquidity using ParaSwap.
|
||||||
|
* @author Jason Raymond Bell
|
||||||
|
*/
|
||||||
|
contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter, ReentrancyGuard {
|
||||||
|
constructor(
|
||||||
|
ILendingPoolAddressesProvider addressesProvider,
|
||||||
|
IParaSwapAugustusRegistry augustusRegistry
|
||||||
|
) public BaseParaSwapSellAdapter(addressesProvider, augustusRegistry) {
|
||||||
|
// This is only required to initialize BaseParaSwapSellAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 the underlying asset to be swapped from
|
||||||
|
* @param amounts Amount of the flash loan i.e. maximum amount to swap
|
||||||
|
* @param premiums Fee of the flash loan
|
||||||
|
* @param initiator Account that initiated the flash loan
|
||||||
|
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||||
|
* address assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
||||||
|
* uint256 minAmountToReceive Min amount to be received from the swap
|
||||||
|
* uint256 swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
||||||
|
* bytes swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
||||||
|
* address augustus Address of ParaSwap's AugustusSwapper contract
|
||||||
|
* PermitSignature permitParams Struct containing the permit signatures, set to all zeroes if not used
|
||||||
|
*/
|
||||||
|
function executeOperation(
|
||||||
|
address[] calldata assets,
|
||||||
|
uint256[] calldata amounts,
|
||||||
|
uint256[] calldata premiums,
|
||||||
|
address initiator,
|
||||||
|
bytes calldata params
|
||||||
|
) external override nonReentrant returns (bool) {
|
||||||
|
require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');
|
||||||
|
require(
|
||||||
|
assets.length == 1 && amounts.length == 1 && premiums.length == 1,
|
||||||
|
'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED'
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 flashLoanAmount = amounts[0];
|
||||||
|
uint256 premium = premiums[0];
|
||||||
|
address initiatorLocal = initiator;
|
||||||
|
IERC20Detailed assetToSwapFrom = IERC20Detailed(assets[0]);
|
||||||
|
(
|
||||||
|
IERC20Detailed assetToSwapTo,
|
||||||
|
uint256 minAmountToReceive,
|
||||||
|
uint256 swapAllBalanceOffset,
|
||||||
|
bytes memory swapCalldata,
|
||||||
|
IParaSwapAugustus augustus,
|
||||||
|
PermitSignature memory permitParams
|
||||||
|
) = abi.decode(params, (
|
||||||
|
IERC20Detailed,
|
||||||
|
uint256,
|
||||||
|
uint256,
|
||||||
|
bytes,
|
||||||
|
IParaSwapAugustus,
|
||||||
|
PermitSignature
|
||||||
|
));
|
||||||
|
|
||||||
|
_swapLiquidity(
|
||||||
|
swapAllBalanceOffset,
|
||||||
|
swapCalldata,
|
||||||
|
augustus,
|
||||||
|
permitParams,
|
||||||
|
flashLoanAmount,
|
||||||
|
premium,
|
||||||
|
initiatorLocal,
|
||||||
|
assetToSwapFrom,
|
||||||
|
assetToSwapTo,
|
||||||
|
minAmountToReceive
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 assetToSwapFrom Address of the underlying asset to be swapped from
|
||||||
|
* @param assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
||||||
|
* @param amountToSwap Amount to be swapped, or maximum amount when swapping all balance
|
||||||
|
* @param minAmountToReceive Minimum amount to be received from the swap
|
||||||
|
* @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
||||||
|
* @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
||||||
|
* @param augustus Address of ParaSwap's AugustusSwapper contract
|
||||||
|
* @param permitParams Struct containing the permit signatures, set to all zeroes if not used
|
||||||
|
*/
|
||||||
|
function swapAndDeposit(
|
||||||
|
IERC20Detailed assetToSwapFrom,
|
||||||
|
IERC20Detailed assetToSwapTo,
|
||||||
|
uint256 amountToSwap,
|
||||||
|
uint256 minAmountToReceive,
|
||||||
|
uint256 swapAllBalanceOffset,
|
||||||
|
bytes calldata swapCalldata,
|
||||||
|
IParaSwapAugustus augustus,
|
||||||
|
PermitSignature calldata permitParams
|
||||||
|
) external nonReentrant {
|
||||||
|
IERC20WithPermit aToken =
|
||||||
|
IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress);
|
||||||
|
|
||||||
|
if (swapAllBalanceOffset != 0) {
|
||||||
|
uint256 balance = aToken.balanceOf(msg.sender);
|
||||||
|
require(balance <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP');
|
||||||
|
amountToSwap = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pullATokenAndWithdraw(
|
||||||
|
address(assetToSwapFrom),
|
||||||
|
aToken,
|
||||||
|
msg.sender,
|
||||||
|
amountToSwap,
|
||||||
|
permitParams
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 amountReceived = _sellOnParaSwap(
|
||||||
|
swapAllBalanceOffset,
|
||||||
|
swapCalldata,
|
||||||
|
augustus,
|
||||||
|
assetToSwapFrom,
|
||||||
|
assetToSwapTo,
|
||||||
|
amountToSwap,
|
||||||
|
minAmountToReceive
|
||||||
|
);
|
||||||
|
|
||||||
|
assetToSwapTo.safeApprove(address(LENDING_POOL), 0);
|
||||||
|
assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived);
|
||||||
|
LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, msg.sender, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Swaps an amount of an asset to another and deposits the funds on behalf of the initiator.
|
||||||
|
* @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
||||||
|
* @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
||||||
|
* @param augustus Address of ParaSwap's AugustusSwapper contract
|
||||||
|
* @param permitParams Struct containing the permit signatures, set to all zeroes if not used
|
||||||
|
* @param flashLoanAmount Amount of the flash loan i.e. maximum amount to swap
|
||||||
|
* @param premium Fee of the flash loan
|
||||||
|
* @param initiator Account that initiated the flash loan
|
||||||
|
* @param assetToSwapFrom Address of the underyling asset to be swapped from
|
||||||
|
* @param assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
||||||
|
* @param minAmountToReceive Min amount to be received from the swap
|
||||||
|
*/
|
||||||
|
function _swapLiquidity (
|
||||||
|
uint256 swapAllBalanceOffset,
|
||||||
|
bytes memory swapCalldata,
|
||||||
|
IParaSwapAugustus augustus,
|
||||||
|
PermitSignature memory permitParams,
|
||||||
|
uint256 flashLoanAmount,
|
||||||
|
uint256 premium,
|
||||||
|
address initiator,
|
||||||
|
IERC20Detailed assetToSwapFrom,
|
||||||
|
IERC20Detailed assetToSwapTo,
|
||||||
|
uint256 minAmountToReceive
|
||||||
|
) internal {
|
||||||
|
IERC20WithPermit aToken =
|
||||||
|
IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress);
|
||||||
|
uint256 amountToSwap = flashLoanAmount;
|
||||||
|
|
||||||
|
uint256 balance = aToken.balanceOf(initiator);
|
||||||
|
if (swapAllBalanceOffset != 0) {
|
||||||
|
uint256 balanceToSwap = balance.sub(premium);
|
||||||
|
require(balanceToSwap <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP');
|
||||||
|
amountToSwap = balanceToSwap;
|
||||||
|
} else {
|
||||||
|
require(balance >= amountToSwap.add(premium), 'INSUFFICIENT_ATOKEN_BALANCE');
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 amountReceived = _sellOnParaSwap(
|
||||||
|
swapAllBalanceOffset,
|
||||||
|
swapCalldata,
|
||||||
|
augustus,
|
||||||
|
assetToSwapFrom,
|
||||||
|
assetToSwapTo,
|
||||||
|
amountToSwap,
|
||||||
|
minAmountToReceive
|
||||||
|
);
|
||||||
|
|
||||||
|
assetToSwapTo.safeApprove(address(LENDING_POOL), 0);
|
||||||
|
assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived);
|
||||||
|
LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, initiator, 0);
|
||||||
|
|
||||||
|
_pullATokenAndWithdraw(
|
||||||
|
address(assetToSwapFrom),
|
||||||
|
aToken,
|
||||||
|
initiator,
|
||||||
|
amountToSwap.add(premium),
|
||||||
|
permitParams
|
||||||
|
);
|
||||||
|
|
||||||
|
// Repay flash loan
|
||||||
|
assetToSwapFrom.safeApprove(address(LENDING_POOL), 0);
|
||||||
|
assetToSwapFrom.safeApprove(address(LENDING_POOL), flashLoanAmount.add(premium));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity >=0.6.0 <0.8.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Contract module that helps prevent reentrant calls to a function.
|
||||||
|
*
|
||||||
|
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
|
||||||
|
* available, which can be applied to functions to make sure there are no nested
|
||||||
|
* (reentrant) calls to them.
|
||||||
|
*
|
||||||
|
* Note that because there is a single `nonReentrant` guard, functions marked as
|
||||||
|
* `nonReentrant` may not call one another. This can be worked around by making
|
||||||
|
* those functions `private`, and then adding `external` `nonReentrant` entry
|
||||||
|
* points to them.
|
||||||
|
*
|
||||||
|
* TIP: If you would like to learn more about reentrancy and alternative ways
|
||||||
|
* to protect against it, check out our blog post
|
||||||
|
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
|
||||||
|
*/
|
||||||
|
abstract contract ReentrancyGuard {
|
||||||
|
// Booleans are more expensive than uint256 or any type that takes up a full
|
||||||
|
// word because each write operation emits an extra SLOAD to first read the
|
||||||
|
// slot's contents, replace the bits taken up by the boolean, and then write
|
||||||
|
// back. This is the compiler's defense against contract upgrades and
|
||||||
|
// pointer aliasing, and it cannot be disabled.
|
||||||
|
|
||||||
|
// The values being non-zero value makes deployment a bit more expensive,
|
||||||
|
// but in exchange the refund on every call to nonReentrant will be lower in
|
||||||
|
// amount. Since refunds are capped to a percentage of the total
|
||||||
|
// transaction's gas, it is best to keep them low in cases like this one, to
|
||||||
|
// increase the likelihood of the full refund coming into effect.
|
||||||
|
uint256 private constant _NOT_ENTERED = 1;
|
||||||
|
uint256 private constant _ENTERED = 2;
|
||||||
|
|
||||||
|
uint256 private _status;
|
||||||
|
|
||||||
|
constructor () internal {
|
||||||
|
_status = _NOT_ENTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Prevents a contract from calling itself, directly or indirectly.
|
||||||
|
* Calling a `nonReentrant` function from another `nonReentrant`
|
||||||
|
* function is not supported. It is possible to prevent this from happening
|
||||||
|
* by making the `nonReentrant` function external, and make it call a
|
||||||
|
* `private` function that does the actual work.
|
||||||
|
*/
|
||||||
|
modifier nonReentrant() {
|
||||||
|
// On the first call to nonReentrant, _notEntered will be true
|
||||||
|
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||||
|
|
||||||
|
// Any calls to nonReentrant after this point will fail
|
||||||
|
_status = _ENTERED;
|
||||||
|
|
||||||
|
_;
|
||||||
|
|
||||||
|
// By storing the original value once again, a refund is triggered (see
|
||||||
|
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||||
|
_status = _NOT_ENTERED;
|
||||||
|
}
|
||||||
|
}
|
7
contracts/interfaces/IParaSwapAugustus.sol
Normal file
7
contracts/interfaces/IParaSwapAugustus.sol
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IParaSwapAugustus {
|
||||||
|
function getTokenTransferProxy() external view returns (address);
|
||||||
|
}
|
7
contracts/interfaces/IParaSwapAugustusRegistry.sol
Normal file
7
contracts/interfaces/IParaSwapAugustusRegistry.sol
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IParaSwapAugustusRegistry {
|
||||||
|
function isValidAugustus(address augustus) external view returns (bool);
|
||||||
|
}
|
59
contracts/mocks/swap/MockParaSwapAugustus.sol
Normal file
59
contracts/mocks/swap/MockParaSwapAugustus.sol
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {IParaSwapAugustus} from '../../interfaces/IParaSwapAugustus.sol';
|
||||||
|
import {MockParaSwapTokenTransferProxy} from './MockParaSwapTokenTransferProxy.sol';
|
||||||
|
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||||
|
import {MintableERC20} from '../tokens/MintableERC20.sol';
|
||||||
|
|
||||||
|
contract MockParaSwapAugustus is IParaSwapAugustus {
|
||||||
|
MockParaSwapTokenTransferProxy immutable TOKEN_TRANSFER_PROXY;
|
||||||
|
bool _expectingSwap;
|
||||||
|
address _expectedFromToken;
|
||||||
|
address _expectedToToken;
|
||||||
|
uint256 _expectedFromAmountMin;
|
||||||
|
uint256 _expectedFromAmountMax;
|
||||||
|
uint256 _receivedAmount;
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
TOKEN_TRANSFER_PROXY = new MockParaSwapTokenTransferProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTokenTransferProxy() external view override returns (address) {
|
||||||
|
return address(TOKEN_TRANSFER_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectSwap(
|
||||||
|
address fromToken,
|
||||||
|
address toToken,
|
||||||
|
uint256 fromAmountMin,
|
||||||
|
uint256 fromAmountMax,
|
||||||
|
uint256 receivedAmount
|
||||||
|
) external {
|
||||||
|
_expectingSwap = true;
|
||||||
|
_expectedFromToken = fromToken;
|
||||||
|
_expectedToToken = toToken;
|
||||||
|
_expectedFromAmountMin = fromAmountMin;
|
||||||
|
_expectedFromAmountMax = fromAmountMax;
|
||||||
|
_receivedAmount = receivedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function swap(
|
||||||
|
address fromToken,
|
||||||
|
address toToken,
|
||||||
|
uint256 fromAmount,
|
||||||
|
uint256 toAmount
|
||||||
|
) external returns (uint256) {
|
||||||
|
require(_expectingSwap, 'Not expecting swap');
|
||||||
|
require(fromToken == _expectedFromToken, 'Unexpected from token');
|
||||||
|
require(toToken == _expectedToToken, 'Unexpected to token');
|
||||||
|
require(fromAmount >= _expectedFromAmountMin && fromAmount <= _expectedFromAmountMax, 'From amount out of range');
|
||||||
|
require(_receivedAmount >= toAmount, 'Received amount of tokens are less than expected');
|
||||||
|
TOKEN_TRANSFER_PROXY.transferFrom(fromToken, msg.sender, address(this), fromAmount);
|
||||||
|
MintableERC20(toToken).mint(_receivedAmount);
|
||||||
|
IERC20(toToken).transfer(msg.sender, _receivedAmount);
|
||||||
|
_expectingSwap = false;
|
||||||
|
return _receivedAmount;
|
||||||
|
}
|
||||||
|
}
|
17
contracts/mocks/swap/MockParaSwapAugustusRegistry.sol
Normal file
17
contracts/mocks/swap/MockParaSwapAugustusRegistry.sol
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {IParaSwapAugustusRegistry} from '../../interfaces/IParaSwapAugustusRegistry.sol';
|
||||||
|
|
||||||
|
contract MockParaSwapAugustusRegistry is IParaSwapAugustusRegistry {
|
||||||
|
address immutable AUGUSTUS;
|
||||||
|
|
||||||
|
constructor(address augustus) public {
|
||||||
|
AUGUSTUS = augustus;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidAugustus(address augustus) external view override returns (bool) {
|
||||||
|
return augustus == AUGUSTUS;
|
||||||
|
}
|
||||||
|
}
|
17
contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol
Normal file
17
contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol';
|
||||||
|
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||||
|
|
||||||
|
contract MockParaSwapTokenTransferProxy is Ownable {
|
||||||
|
function transferFrom(
|
||||||
|
address token,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) external onlyOwner {
|
||||||
|
IERC20(token).transferFrom(from, to, amount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,9 +34,12 @@ import {
|
||||||
MockAggregatorFactory,
|
MockAggregatorFactory,
|
||||||
MockATokenFactory,
|
MockATokenFactory,
|
||||||
MockFlashLoanReceiverFactory,
|
MockFlashLoanReceiverFactory,
|
||||||
|
MockParaSwapAugustusFactory,
|
||||||
|
MockParaSwapAugustusRegistryFactory,
|
||||||
MockStableDebtTokenFactory,
|
MockStableDebtTokenFactory,
|
||||||
MockVariableDebtTokenFactory,
|
MockVariableDebtTokenFactory,
|
||||||
MockUniswapV2Router02Factory,
|
MockUniswapV2Router02Factory,
|
||||||
|
ParaSwapLiquiditySwapAdapterFactory,
|
||||||
PriceOracleFactory,
|
PriceOracleFactory,
|
||||||
ReserveLogicFactory,
|
ReserveLogicFactory,
|
||||||
SelfdestructTransferFactory,
|
SelfdestructTransferFactory,
|
||||||
|
@ -708,3 +711,32 @@ export const deployRateStrategy = async (
|
||||||
).address;
|
).address;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
export const deployMockParaSwapAugustus = async (verify?: boolean) =>
|
||||||
|
withSaveAndVerify(
|
||||||
|
await new MockParaSwapAugustusFactory(await getFirstSigner()).deploy(),
|
||||||
|
eContractid.MockParaSwapAugustus,
|
||||||
|
[],
|
||||||
|
verify
|
||||||
|
);
|
||||||
|
|
||||||
|
export const deployMockParaSwapAugustusRegistry = async (
|
||||||
|
args: [tEthereumAddress],
|
||||||
|
verify?: boolean
|
||||||
|
) =>
|
||||||
|
withSaveAndVerify(
|
||||||
|
await new MockParaSwapAugustusRegistryFactory(await getFirstSigner()).deploy(...args),
|
||||||
|
eContractid.MockParaSwapAugustusRegistry,
|
||||||
|
args,
|
||||||
|
verify
|
||||||
|
);
|
||||||
|
|
||||||
|
export const deployParaSwapLiquiditySwapAdapter = async (
|
||||||
|
args: [tEthereumAddress, tEthereumAddress],
|
||||||
|
verify?: boolean
|
||||||
|
) =>
|
||||||
|
withSaveAndVerify(
|
||||||
|
await new ParaSwapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args),
|
||||||
|
eContractid.ParaSwapLiquiditySwapAdapter,
|
||||||
|
args,
|
||||||
|
verify
|
||||||
|
);
|
||||||
|
|
|
@ -18,6 +18,9 @@ import {
|
||||||
MockStableDebtTokenFactory,
|
MockStableDebtTokenFactory,
|
||||||
MockVariableDebtTokenFactory,
|
MockVariableDebtTokenFactory,
|
||||||
MockUniswapV2Router02Factory,
|
MockUniswapV2Router02Factory,
|
||||||
|
MockParaSwapAugustusFactory,
|
||||||
|
MockParaSwapAugustusRegistryFactory,
|
||||||
|
ParaSwapLiquiditySwapAdapterFactory,
|
||||||
PriceOracleFactory,
|
PriceOracleFactory,
|
||||||
ReserveLogicFactory,
|
ReserveLogicFactory,
|
||||||
SelfdestructTransferFactory,
|
SelfdestructTransferFactory,
|
||||||
|
@ -417,3 +420,27 @@ export const getFlashLiquidationAdapter = async (address?: tEthereumAddress) =>
|
||||||
).address,
|
).address,
|
||||||
await getFirstSigner()
|
await getFirstSigner()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getMockParaSwapAugustus = async (address?: tEthereumAddress) =>
|
||||||
|
await MockParaSwapAugustusFactory.connect(
|
||||||
|
address ||
|
||||||
|
(await getDb().get(`${eContractid.MockParaSwapAugustus}.${DRE.network.name}`).value())
|
||||||
|
.address,
|
||||||
|
await getFirstSigner()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getMockParaSwapAugustusRegistry = async (address?: tEthereumAddress) =>
|
||||||
|
await MockParaSwapAugustusRegistryFactory.connect(
|
||||||
|
address ||
|
||||||
|
(await getDb().get(`${eContractid.MockParaSwapAugustusRegistry}.${DRE.network.name}`).value())
|
||||||
|
.address,
|
||||||
|
await getFirstSigner()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getParaSwapLiquiditySwapAdapter = async (address?: tEthereumAddress) =>
|
||||||
|
await ParaSwapLiquiditySwapAdapterFactory.connect(
|
||||||
|
address ||
|
||||||
|
(await getDb().get(`${eContractid.ParaSwapLiquiditySwapAdapter}.${DRE.network.name}`).value())
|
||||||
|
.address,
|
||||||
|
await getFirstSigner()
|
||||||
|
);
|
||||||
|
|
|
@ -341,6 +341,38 @@ export const buildFlashLiquidationAdapterParams = (
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildParaSwapLiquiditySwapParams = (
|
||||||
|
assetToSwapTo: tEthereumAddress,
|
||||||
|
minAmountToReceive: BigNumberish,
|
||||||
|
swapAllBalanceOffset: BigNumberish,
|
||||||
|
swapCalldata: string | Buffer,
|
||||||
|
augustus: tEthereumAddress,
|
||||||
|
permitAmount: BigNumberish,
|
||||||
|
deadline: BigNumberish,
|
||||||
|
v: BigNumberish,
|
||||||
|
r: string | Buffer,
|
||||||
|
s: string | Buffer
|
||||||
|
) => {
|
||||||
|
return ethers.utils.defaultAbiCoder.encode(
|
||||||
|
[
|
||||||
|
'address',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'bytes',
|
||||||
|
'address',
|
||||||
|
'tuple(uint256,uint256,uint8,bytes32,bytes32)',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
assetToSwapTo,
|
||||||
|
minAmountToReceive,
|
||||||
|
swapAllBalanceOffset,
|
||||||
|
swapCalldata,
|
||||||
|
augustus,
|
||||||
|
[permitAmount, deadline, v, r, s],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const verifyContract = async (
|
export const verifyContract = async (
|
||||||
id: string,
|
id: string,
|
||||||
instance: Contract,
|
instance: Contract,
|
||||||
|
|
|
@ -95,6 +95,9 @@ export enum eContractid {
|
||||||
UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter',
|
UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter',
|
||||||
UniswapRepayAdapter = 'UniswapRepayAdapter',
|
UniswapRepayAdapter = 'UniswapRepayAdapter',
|
||||||
FlashLiquidationAdapter = 'FlashLiquidationAdapter',
|
FlashLiquidationAdapter = 'FlashLiquidationAdapter',
|
||||||
|
MockParaSwapAugustus = 'MockParaSwapAugustus',
|
||||||
|
MockParaSwapAugustusRegistry = 'MockParaSwapAugustusRegistry',
|
||||||
|
ParaSwapLiquiditySwapAdapter = 'ParaSwapLiquiditySwapAdapter',
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
"dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c",
|
"dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c",
|
||||||
"main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
"main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||||
"main:UniswapLiquiditySwapAdapter": "hardhat --network main deploy-UniswapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
"main:UniswapLiquiditySwapAdapter": "hardhat --network main deploy-UniswapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||||
|
"main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --augustusRegistry 0xa68bEA62Dc4034A689AA0F58A76681433caCa663",
|
||||||
"kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave",
|
"kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave",
|
||||||
"ropsten:verify": "npm run hardhat:ropsten 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",
|
"mainnet:verify": "npm run hardhat:main verify:general -- --all --pool Aave",
|
||||||
|
|
36
tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts
Normal file
36
tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { task } from 'hardhat/config';
|
||||||
|
|
||||||
|
import { ParaSwapLiquiditySwapAdapterFactory } from '../../types';
|
||||||
|
import { verifyContract } from '../../helpers/contracts-helpers';
|
||||||
|
import { getFirstSigner } from '../../helpers/contracts-getters';
|
||||||
|
import { eContractid } from '../../helpers/types';
|
||||||
|
|
||||||
|
const CONTRACT_NAME = 'ParaSwapLiquiditySwapAdapter';
|
||||||
|
|
||||||
|
task(`deploy-${CONTRACT_NAME}`, `Deploys the ${CONTRACT_NAME} contract`)
|
||||||
|
.addParam('provider', 'Address of the LendingPoolAddressesProvider')
|
||||||
|
.addParam('augustusRegistry', 'Address of ParaSwap AugustusRegistry')
|
||||||
|
.addFlag('verify', `Verify ${CONTRACT_NAME} contract via Etherscan API.`)
|
||||||
|
.setAction(async ({ provider, augustusRegistry, verify }, localBRE) => {
|
||||||
|
await localBRE.run('set-DRE');
|
||||||
|
|
||||||
|
if (!localBRE.network.config.chainId) {
|
||||||
|
throw new Error('INVALID_CHAIN_ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n- ${CONTRACT_NAME} deployment`);
|
||||||
|
const adapter = await new ParaSwapLiquiditySwapAdapterFactory(
|
||||||
|
await getFirstSigner()
|
||||||
|
).deploy(provider, augustusRegistry);
|
||||||
|
await adapter.deployTransaction.wait();
|
||||||
|
console.log(`${CONTRACT_NAME}.address`, adapter.address);
|
||||||
|
|
||||||
|
if (verify) {
|
||||||
|
await verifyContract(eContractid.ParaSwapLiquiditySwapAdapter, adapter, [
|
||||||
|
provider,
|
||||||
|
augustusRegistry,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\tFinished ${CONTRACT_NAME} deployment`);
|
||||||
|
});
|
|
@ -26,6 +26,9 @@ import {
|
||||||
deployUniswapLiquiditySwapAdapter,
|
deployUniswapLiquiditySwapAdapter,
|
||||||
deployUniswapRepayAdapter,
|
deployUniswapRepayAdapter,
|
||||||
deployFlashLiquidationAdapter,
|
deployFlashLiquidationAdapter,
|
||||||
|
deployMockParaSwapAugustus,
|
||||||
|
deployMockParaSwapAugustusRegistry,
|
||||||
|
deployParaSwapLiquiditySwapAdapter,
|
||||||
authorizeWETHGateway,
|
authorizeWETHGateway,
|
||||||
deployATokenImplementations,
|
deployATokenImplementations,
|
||||||
deployAaveOracle,
|
deployAaveOracle,
|
||||||
|
@ -293,6 +296,12 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
|
||||||
await deployUniswapRepayAdapter(adapterParams);
|
await deployUniswapRepayAdapter(adapterParams);
|
||||||
await deployFlashLiquidationAdapter(adapterParams);
|
await deployFlashLiquidationAdapter(adapterParams);
|
||||||
|
|
||||||
|
const augustus = await deployMockParaSwapAugustus();
|
||||||
|
|
||||||
|
const augustusRegistry = await deployMockParaSwapAugustusRegistry([augustus.address]);
|
||||||
|
|
||||||
|
await deployParaSwapLiquiditySwapAdapter([addressesProvider.address, augustusRegistry.address]);
|
||||||
|
|
||||||
await deployWalletBalancerProvider();
|
await deployWalletBalancerProvider();
|
||||||
|
|
||||||
const gateWay = await deployWETHGateway([mockTokens.WETH.address]);
|
const gateWay = await deployWETHGateway([mockTokens.WETH.address]);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
getUniswapLiquiditySwapAdapter,
|
getUniswapLiquiditySwapAdapter,
|
||||||
getUniswapRepayAdapter,
|
getUniswapRepayAdapter,
|
||||||
getFlashLiquidationAdapter,
|
getFlashLiquidationAdapter,
|
||||||
|
getParaSwapLiquiditySwapAdapter,
|
||||||
} from '../../../helpers/contracts-getters';
|
} from '../../../helpers/contracts-getters';
|
||||||
import { eEthereumNetwork, eNetwork, tEthereumAddress } from '../../../helpers/types';
|
import { eEthereumNetwork, eNetwork, tEthereumAddress } from '../../../helpers/types';
|
||||||
import { LendingPool } from '../../../types/LendingPool';
|
import { LendingPool } from '../../../types/LendingPool';
|
||||||
|
@ -32,6 +33,7 @@ import { LendingPoolAddressesProviderRegistry } from '../../../types/LendingPool
|
||||||
import { getEthersSigners } from '../../../helpers/contracts-helpers';
|
import { getEthersSigners } from '../../../helpers/contracts-helpers';
|
||||||
import { UniswapLiquiditySwapAdapter } from '../../../types/UniswapLiquiditySwapAdapter';
|
import { UniswapLiquiditySwapAdapter } from '../../../types/UniswapLiquiditySwapAdapter';
|
||||||
import { UniswapRepayAdapter } from '../../../types/UniswapRepayAdapter';
|
import { UniswapRepayAdapter } from '../../../types/UniswapRepayAdapter';
|
||||||
|
import { ParaSwapLiquiditySwapAdapter } from '../../../types/ParaSwapLiquiditySwapAdapter';
|
||||||
import { getParamPerNetwork } from '../../../helpers/contracts-helpers';
|
import { getParamPerNetwork } from '../../../helpers/contracts-helpers';
|
||||||
import { WETH9Mocked } from '../../../types/WETH9Mocked';
|
import { WETH9Mocked } from '../../../types/WETH9Mocked';
|
||||||
import { WETHGateway } from '../../../types/WETHGateway';
|
import { WETHGateway } from '../../../types/WETHGateway';
|
||||||
|
@ -68,6 +70,7 @@ export interface TestEnv {
|
||||||
registry: LendingPoolAddressesProviderRegistry;
|
registry: LendingPoolAddressesProviderRegistry;
|
||||||
wethGateway: WETHGateway;
|
wethGateway: WETHGateway;
|
||||||
flashLiquidationAdapter: FlashLiquidationAdapter;
|
flashLiquidationAdapter: FlashLiquidationAdapter;
|
||||||
|
paraswapLiquiditySwapAdapter: ParaSwapLiquiditySwapAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
let buidlerevmSnapshotId: string = '0x1';
|
let buidlerevmSnapshotId: string = '0x1';
|
||||||
|
@ -92,6 +95,7 @@ const testEnv: TestEnv = {
|
||||||
uniswapLiquiditySwapAdapter: {} as UniswapLiquiditySwapAdapter,
|
uniswapLiquiditySwapAdapter: {} as UniswapLiquiditySwapAdapter,
|
||||||
uniswapRepayAdapter: {} as UniswapRepayAdapter,
|
uniswapRepayAdapter: {} as UniswapRepayAdapter,
|
||||||
flashLiquidationAdapter: {} as FlashLiquidationAdapter,
|
flashLiquidationAdapter: {} as FlashLiquidationAdapter,
|
||||||
|
paraswapLiquiditySwapAdapter: {} as ParaSwapLiquiditySwapAdapter,
|
||||||
registry: {} as LendingPoolAddressesProviderRegistry,
|
registry: {} as LendingPoolAddressesProviderRegistry,
|
||||||
wethGateway: {} as WETHGateway,
|
wethGateway: {} as WETHGateway,
|
||||||
} as TestEnv;
|
} as TestEnv;
|
||||||
|
@ -158,6 +162,8 @@ export async function initializeMakeSuite() {
|
||||||
testEnv.uniswapLiquiditySwapAdapter = await getUniswapLiquiditySwapAdapter();
|
testEnv.uniswapLiquiditySwapAdapter = await getUniswapLiquiditySwapAdapter();
|
||||||
testEnv.uniswapRepayAdapter = await getUniswapRepayAdapter();
|
testEnv.uniswapRepayAdapter = await getUniswapRepayAdapter();
|
||||||
testEnv.flashLiquidationAdapter = await getFlashLiquidationAdapter();
|
testEnv.flashLiquidationAdapter = await getFlashLiquidationAdapter();
|
||||||
|
|
||||||
|
testEnv.paraswapLiquiditySwapAdapter = await getParaSwapLiquiditySwapAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSnapshot = async () => {
|
const setSnapshot = async () => {
|
||||||
|
|
2393
test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts
Normal file
2393
test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -198,7 +198,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
it('should revert if not valid addresses provider', async () => {
|
it('should revert if not valid addresses provider', async () => {
|
||||||
const { weth } = testEnv;
|
const { weth } = testEnv;
|
||||||
expect(
|
await expect(
|
||||||
deployFlashLiquidationAdapter([
|
deployFlashLiquidationAdapter([
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
|
|
|
@ -50,7 +50,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
it('should revert if not valid addresses provider', async () => {
|
it('should revert if not valid addresses provider', async () => {
|
||||||
const { weth } = testEnv;
|
const { weth } = testEnv;
|
||||||
expect(
|
await expect(
|
||||||
deployUniswapLiquiditySwapAdapter([
|
deployUniswapLiquiditySwapAdapter([
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
|
@ -196,6 +196,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
.div(
|
.div(
|
||||||
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
||||||
)
|
)
|
||||||
|
.div(new BigNumber(10).pow(principalDecimals))
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -318,6 +319,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
.div(
|
.div(
|
||||||
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
||||||
)
|
)
|
||||||
|
.div(new BigNumber(10).pow(principalDecimals))
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -871,6 +873,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
.div(
|
.div(
|
||||||
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
||||||
)
|
)
|
||||||
|
.div(new BigNumber(10).pow(principalDecimals))
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1493,6 +1496,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
.div(
|
.div(
|
||||||
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
||||||
)
|
)
|
||||||
|
.div(new BigNumber(10).pow(principalDecimals))
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1601,6 +1605,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
.div(
|
.div(
|
||||||
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
|
||||||
)
|
)
|
||||||
|
.div(new BigNumber(10).pow(principalDecimals))
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
it('should revert if not valid addresses provider', async () => {
|
it('should revert if not valid addresses provider', async () => {
|
||||||
const { weth } = testEnv;
|
const { weth } = testEnv;
|
||||||
expect(
|
await expect(
|
||||||
deployUniswapRepayAdapter([
|
deployUniswapRepayAdapter([
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user