mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Support using all the collateral for a debt repay
This commit is contained in:
parent
8a303c6195
commit
b48b50208a
|
@ -109,29 +109,40 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
||||||
PermitSignature memory permitSignature
|
PermitSignature memory permitSignature
|
||||||
) internal {
|
) internal {
|
||||||
uint256 debtRepayAmount;
|
uint256 debtRepayAmount;
|
||||||
|
uint256 amountSwapped;
|
||||||
|
|
||||||
if (repayMode == RepayMode.ALL_DEBT) {
|
ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom);
|
||||||
ReserveLogic.ReserveData memory reserveDebtData = _getReserveData(assetTo);
|
|
||||||
|
|
||||||
address debtToken = ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.STABLE
|
if (repayMode == RepayMode.ALL_COLLATERAL) {
|
||||||
? reserveDebtData.stableDebtTokenAddress
|
uint256 aTokenInitiatorBalance = IERC20(reserveData.aTokenAddress).balanceOf(initiator);
|
||||||
: reserveDebtData.variableDebtTokenAddress;
|
amountSwapped = aTokenInitiatorBalance.sub(premium);
|
||||||
|
|
||||||
debtRepayAmount = IERC20(debtToken).balanceOf(initiator);
|
debtRepayAmount = _swapExactTokensForTokens(assetFrom, assetTo, amountSwapped, repayAmount);
|
||||||
} else {
|
} else {
|
||||||
debtRepayAmount = repayAmount;
|
if (repayMode == RepayMode.ALL_DEBT) {
|
||||||
}
|
ReserveLogic.ReserveData memory reserveDebtData = _getReserveData(assetTo);
|
||||||
|
|
||||||
uint256 amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, amount, debtRepayAmount);
|
address debtToken = ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.STABLE
|
||||||
|
? reserveDebtData.stableDebtTokenAddress
|
||||||
|
: reserveDebtData.variableDebtTokenAddress;
|
||||||
|
|
||||||
|
debtRepayAmount = IERC20(debtToken).balanceOf(initiator);
|
||||||
|
} else {
|
||||||
|
debtRepayAmount = repayAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, amount, debtRepayAmount);
|
||||||
|
}
|
||||||
|
|
||||||
// Repay debt
|
// Repay debt
|
||||||
IERC20(assetTo).approve(address(POOL), debtRepayAmount);
|
IERC20(assetTo).approve(address(POOL), debtRepayAmount);
|
||||||
POOL.repay(assetTo, debtRepayAmount, rateMode, initiator);
|
POOL.repay(assetTo, debtRepayAmount, rateMode, initiator);
|
||||||
|
// In the case the repay amount provided exceeded the actual debt, send the leftovers to the user
|
||||||
|
_sendRepayLeftovers(assetTo, initiator);
|
||||||
|
|
||||||
uint256 flashLoanDebt = amount.add(premium);
|
uint256 flashLoanDebt = amount.add(premium);
|
||||||
uint256 amountToPull = amountSwapped.add(premium);
|
uint256 amountToPull = amountSwapped.add(premium);
|
||||||
|
|
||||||
ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom);
|
|
||||||
_pullAToken(assetFrom, reserveData.aTokenAddress, initiator, amountToPull, permitSignature);
|
_pullAToken(assetFrom, reserveData.aTokenAddress, initiator, amountToPull, permitSignature);
|
||||||
|
|
||||||
// Repay flashloan
|
// Repay flashloan
|
||||||
|
@ -179,4 +190,17 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfers the balance of the adapter to the user, as there shouldn't be any leftover in the adapter
|
||||||
|
* @param asset address of the asset
|
||||||
|
* @param user address
|
||||||
|
*/
|
||||||
|
function _sendRepayLeftovers(address asset, address user) internal {
|
||||||
|
uint256 assetLeftover = IERC20(asset).balanceOf(address(this));
|
||||||
|
|
||||||
|
if (assetLeftover > 0) {
|
||||||
|
IERC20(asset).transfer(user, assetLeftover);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ export const buildRepayAdapterParams = (
|
||||||
assetToSwapTo: tEthereumAddress,
|
assetToSwapTo: tEthereumAddress,
|
||||||
repayAmount: BigNumberish,
|
repayAmount: BigNumberish,
|
||||||
rateMode: BigNumberish,
|
rateMode: BigNumberish,
|
||||||
repayAllDebt: BigNumberish,
|
repayMode: BigNumberish,
|
||||||
permitAmount: BigNumberish,
|
permitAmount: BigNumberish,
|
||||||
deadline: BigNumberish,
|
deadline: BigNumberish,
|
||||||
v: BigNumberish,
|
v: BigNumberish,
|
||||||
|
@ -270,7 +270,17 @@ export const buildRepayAdapterParams = (
|
||||||
s: string | Buffer
|
s: string | Buffer
|
||||||
) => {
|
) => {
|
||||||
return ethers.utils.defaultAbiCoder.encode(
|
return ethers.utils.defaultAbiCoder.encode(
|
||||||
['address', 'uint256', 'uint256', 'bool', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32'],
|
[
|
||||||
[assetToSwapTo, repayAmount, rateMode, repayAllDebt, permitAmount, deadline, v, r, s]
|
'address',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint8',
|
||||||
|
'bytes32',
|
||||||
|
'bytes32',
|
||||||
|
],
|
||||||
|
[assetToSwapTo, repayAmount, rateMode, repayMode, permitAmount, deadline, v, r, s]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {makeSuite, TestEnv} from './helpers/make-suite';
|
import { makeSuite, TestEnv } from './helpers/make-suite';
|
||||||
import {
|
import {
|
||||||
convertToCurrencyDecimals,
|
convertToCurrencyDecimals,
|
||||||
getContract,
|
getContract,
|
||||||
|
@ -7,24 +7,24 @@ import {
|
||||||
buildLiquiditySwapParams,
|
buildLiquiditySwapParams,
|
||||||
buildRepayAdapterParams,
|
buildRepayAdapterParams,
|
||||||
} from '../helpers/contracts-helpers';
|
} from '../helpers/contracts-helpers';
|
||||||
import {getMockUniswapRouter} from '../helpers/contracts-getters';
|
import { getMockUniswapRouter } from '../helpers/contracts-getters';
|
||||||
import {
|
import {
|
||||||
deployUniswapLiquiditySwapAdapter,
|
deployUniswapLiquiditySwapAdapter,
|
||||||
deployUniswapRepayAdapter,
|
deployUniswapRepayAdapter,
|
||||||
} from '../helpers/contracts-deployments';
|
} from '../helpers/contracts-deployments';
|
||||||
import {MockUniswapV2Router02} from '../types/MockUniswapV2Router02';
|
import { MockUniswapV2Router02 } from '../types/MockUniswapV2Router02';
|
||||||
import {Zero} from '@ethersproject/constants';
|
import { Zero } from '@ethersproject/constants';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {DRE, evmRevert, evmSnapshot} from '../helpers/misc-utils';
|
import { DRE, evmRevert, evmSnapshot } from '../helpers/misc-utils';
|
||||||
import {ethers} from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import {eContractid} from '../helpers/types';
|
import { eContractid } from '../helpers/types';
|
||||||
import {AToken} from '../types/AToken';
|
import { AToken } from '../types/AToken';
|
||||||
import {StableDebtToken} from '../types/StableDebtToken';
|
import { StableDebtToken } from '../types/StableDebtToken';
|
||||||
import {BUIDLEREVM_CHAINID} from '../helpers/buidler-constants';
|
import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants';
|
||||||
import {MAX_UINT_AMOUNT, USD_ADDRESS} from '../helpers/constants';
|
import { MAX_UINT_AMOUNT, USD_ADDRESS } from '../helpers/constants';
|
||||||
const {parseEther} = ethers.utils;
|
const { parseEther } = ethers.utils;
|
||||||
|
|
||||||
const {expect} = require('chai');
|
const { expect } = require('chai');
|
||||||
|
|
||||||
makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
let mockUniswapRouter: MockUniswapV2Router02;
|
let mockUniswapRouter: MockUniswapV2Router02;
|
||||||
|
@ -45,7 +45,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
describe('BaseUniswapAdapter', () => {
|
describe('BaseUniswapAdapter', () => {
|
||||||
describe('getAmountsOut', () => {
|
describe('getAmountsOut', () => {
|
||||||
it('should return the estimated amountOut and prices for the asset swap', async () => {
|
it('should return the estimated amountOut and prices for the asset swap', async () => {
|
||||||
const {weth, dai, uniswapLiquiditySwapAdapter, oracle} = testEnv;
|
const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv;
|
||||||
|
|
||||||
const amountIn = parseEther('1');
|
const amountIn = parseEther('1');
|
||||||
const flashloanPremium = amountIn.mul(9).div(10000);
|
const flashloanPremium = amountIn.mul(9).div(10000);
|
||||||
|
@ -94,7 +94,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
expect(result['3']).to.be.eq(daiUsdValue);
|
expect(result['3']).to.be.eq(daiUsdValue);
|
||||||
});
|
});
|
||||||
it('should work correctly with different decimals', async () => {
|
it('should work correctly with different decimals', async () => {
|
||||||
const {aave, usdc, uniswapLiquiditySwapAdapter, oracle} = testEnv;
|
const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv;
|
||||||
|
|
||||||
const amountIn = parseEther('10');
|
const amountIn = parseEther('10');
|
||||||
const flashloanPremium = amountIn.mul(9).div(10000);
|
const flashloanPremium = amountIn.mul(9).div(10000);
|
||||||
|
@ -148,7 +148,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
describe('getAmountsIn', () => {
|
describe('getAmountsIn', () => {
|
||||||
it('should return the estimated required amountIn for the asset swap', async () => {
|
it('should return the estimated required amountIn for the asset swap', async () => {
|
||||||
const {weth, dai, uniswapLiquiditySwapAdapter, oracle} = testEnv;
|
const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv;
|
||||||
|
|
||||||
const amountIn = parseEther('1');
|
const amountIn = parseEther('1');
|
||||||
const flashloanPremium = amountIn.mul(9).div(10000);
|
const flashloanPremium = amountIn.mul(9).div(10000);
|
||||||
|
@ -193,7 +193,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
expect(result['3']).to.be.eq(daiUsdValue);
|
expect(result['3']).to.be.eq(daiUsdValue);
|
||||||
});
|
});
|
||||||
it('should work correctly with different decimals', async () => {
|
it('should work correctly with different decimals', async () => {
|
||||||
const {aave, usdc, uniswapLiquiditySwapAdapter, oracle} = testEnv;
|
const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv;
|
||||||
|
|
||||||
const amountIn = parseEther('10');
|
const amountIn = parseEther('10');
|
||||||
const flashloanPremium = amountIn.mul(9).div(10000);
|
const flashloanPremium = amountIn.mul(9).div(10000);
|
||||||
|
@ -244,7 +244,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
describe('UniswapLiquiditySwapAdapter', () => {
|
describe('UniswapLiquiditySwapAdapter', () => {
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('should deploy with correct parameters', async () => {
|
it('should deploy with correct parameters', async () => {
|
||||||
const {addressesProvider} = testEnv;
|
const { addressesProvider } = testEnv;
|
||||||
await deployUniswapLiquiditySwapAdapter([
|
await deployUniswapLiquiditySwapAdapter([
|
||||||
addressesProvider.address,
|
addressesProvider.address,
|
||||||
mockUniswapRouter.address,
|
mockUniswapRouter.address,
|
||||||
|
@ -260,7 +260,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
describe('executeOperation', () => {
|
describe('executeOperation', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const {users, weth, dai, usdc, pool, deployer} = testEnv;
|
const { users, weth, dai, usdc, pool, deployer } = testEnv;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
// Provide liquidity
|
// Provide liquidity
|
||||||
|
@ -280,7 +280,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
|
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const {
|
||||||
|
users,
|
||||||
|
weth,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
aDai,
|
||||||
|
aWETH,
|
||||||
|
pool,
|
||||||
|
uniswapLiquiditySwapAdapter,
|
||||||
|
} = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -542,7 +551,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
deadline,
|
deadline,
|
||||||
amountWETHtoSwap.toString()
|
amountWETHtoSwap.toString()
|
||||||
);
|
);
|
||||||
const {v: aWETHv, r: aWETHr, s: aWETHs} = getSignatureFromTypedData(
|
const { v: aWETHv, r: aWETHr, s: aWETHs } = getSignatureFromTypedData(
|
||||||
ownerPrivateKey,
|
ownerPrivateKey,
|
||||||
aWethMsgParams
|
aWethMsgParams
|
||||||
);
|
);
|
||||||
|
@ -559,7 +568,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
deadline,
|
deadline,
|
||||||
amountUSDCtoSwap.toString()
|
amountUSDCtoSwap.toString()
|
||||||
);
|
);
|
||||||
const {v: aUsdcv, r: aUsdcr, s: aUsdcs} = getSignatureFromTypedData(
|
const { v: aUsdcv, r: aUsdcr, s: aUsdcs } = getSignatureFromTypedData(
|
||||||
ownerPrivateKey,
|
ownerPrivateKey,
|
||||||
aUsdcMsgParams
|
aUsdcMsgParams
|
||||||
);
|
);
|
||||||
|
@ -607,7 +616,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens with permit', async () => {
|
it('should correctly swap tokens with permit', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const {
|
||||||
|
users,
|
||||||
|
weth,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
aDai,
|
||||||
|
aWETH,
|
||||||
|
pool,
|
||||||
|
uniswapLiquiditySwapAdapter,
|
||||||
|
} = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -648,7 +666,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
throw new Error('INVALID_OWNER_PK');
|
throw new Error('INVALID_OWNER_PK');
|
||||||
}
|
}
|
||||||
|
|
||||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||||
|
|
||||||
const params = buildLiquiditySwapParams(
|
const params = buildLiquiditySwapParams(
|
||||||
[dai.address],
|
[dai.address],
|
||||||
|
@ -695,7 +713,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if inconsistent params', async () => {
|
it('should revert if inconsistent params', async () => {
|
||||||
const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -924,7 +942,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if caller not lending pool', async () => {
|
it('should revert if caller not lending pool', async () => {
|
||||||
const {users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1066,7 +1084,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
|
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
|
||||||
const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1115,7 +1133,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens all the balance', async () => {
|
it('should correctly swap tokens all the balance', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const {
|
||||||
|
users,
|
||||||
|
weth,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
aDai,
|
||||||
|
aWETH,
|
||||||
|
pool,
|
||||||
|
uniswapLiquiditySwapAdapter,
|
||||||
|
} = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1188,7 +1215,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens all the balance using permit', async () => {
|
it('should correctly swap tokens all the balance using permit', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
const {
|
||||||
|
users,
|
||||||
|
weth,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
aDai,
|
||||||
|
aWETH,
|
||||||
|
pool,
|
||||||
|
uniswapLiquiditySwapAdapter,
|
||||||
|
} = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1229,7 +1265,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
throw new Error('INVALID_OWNER_PK');
|
throw new Error('INVALID_OWNER_PK');
|
||||||
}
|
}
|
||||||
|
|
||||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||||
|
|
||||||
const params = buildLiquiditySwapParams(
|
const params = buildLiquiditySwapParams(
|
||||||
[dai.address],
|
[dai.address],
|
||||||
|
@ -1283,7 +1319,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
describe('swapAndDeposit', () => {
|
describe('swapAndDeposit', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const {users, weth, dai, pool, deployer} = testEnv;
|
const { users, weth, dai, pool, deployer } = testEnv;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
// Provide liquidity
|
// Provide liquidity
|
||||||
|
@ -1298,7 +1334,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
|
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1355,7 +1391,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap tokens using permit', async () => {
|
it('should correctly swap tokens using permit', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1393,7 +1429,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
throw new Error('INVALID_OWNER_PK');
|
throw new Error('INVALID_OWNER_PK');
|
||||||
}
|
}
|
||||||
|
|
||||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
|
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
|
||||||
|
@ -1433,7 +1469,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if inconsistent params', async () => {
|
it('should revert if inconsistent params', async () => {
|
||||||
const {users, weth, dai, uniswapLiquiditySwapAdapter, oracle} = testEnv;
|
const { users, weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
|
|
||||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||||
|
@ -1529,7 +1565,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
|
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
|
||||||
const {users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
|
|
||||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||||
|
@ -1740,7 +1776,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
deadline,
|
deadline,
|
||||||
amountWETHtoSwap.toString()
|
amountWETHtoSwap.toString()
|
||||||
);
|
);
|
||||||
const {v: aWETHv, r: aWETHr, s: aWETHs} = getSignatureFromTypedData(
|
const { v: aWETHv, r: aWETHr, s: aWETHs } = getSignatureFromTypedData(
|
||||||
ownerPrivateKey,
|
ownerPrivateKey,
|
||||||
aWethMsgParams
|
aWethMsgParams
|
||||||
);
|
);
|
||||||
|
@ -1757,7 +1793,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
deadline,
|
deadline,
|
||||||
amountUSDCtoSwap.toString()
|
amountUSDCtoSwap.toString()
|
||||||
);
|
);
|
||||||
const {v: aUsdcv, r: aUsdcr, s: aUsdcs} = getSignatureFromTypedData(
|
const { v: aUsdcv, r: aUsdcr, s: aUsdcs } = getSignatureFromTypedData(
|
||||||
ownerPrivateKey,
|
ownerPrivateKey,
|
||||||
aUsdcMsgParams
|
aUsdcMsgParams
|
||||||
);
|
);
|
||||||
|
@ -1806,7 +1842,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap all the balance when using a bigger amount', async () => {
|
it('should correctly swap all the balance when using a bigger amount', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1873,7 +1909,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly swap all the balance when using permit', async () => {
|
it('should correctly swap all the balance when using permit', async () => {
|
||||||
const {users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -1917,7 +1953,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
deadline,
|
deadline,
|
||||||
bigAmountToSwap.toString()
|
bigAmountToSwap.toString()
|
||||||
);
|
);
|
||||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, aWethMsgParams);
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, aWethMsgParams);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
|
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
|
||||||
|
@ -1962,7 +1998,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
describe('UniswapRepayAdapter', () => {
|
describe('UniswapRepayAdapter', () => {
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('should deploy with correct parameters', async () => {
|
it('should deploy with correct parameters', async () => {
|
||||||
const {addressesProvider} = testEnv;
|
const { addressesProvider } = testEnv;
|
||||||
await deployUniswapRepayAdapter([addressesProvider.address, mockUniswapRouter.address]);
|
await deployUniswapRepayAdapter([addressesProvider.address, mockUniswapRouter.address]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1974,7 +2010,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
describe('executeOperation', () => {
|
describe('executeOperation', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const {users, weth, dai, usdc, aave, pool, deployer} = testEnv;
|
const { users, weth, dai, usdc, aave, pool, deployer } = testEnv;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
// Provide liquidity
|
// Provide liquidity
|
||||||
|
@ -2157,7 +2193,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
throw new Error('INVALID_OWNER_PK');
|
throw new Error('INVALID_OWNER_PK');
|
||||||
}
|
}
|
||||||
|
|
||||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||||
|
|
||||||
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount);
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount);
|
||||||
|
|
||||||
|
@ -2203,7 +2239,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if caller not lending pool', async () => {
|
it('should revert if caller not lending pool', async () => {
|
||||||
const {users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter} = testEnv;
|
const { users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -2252,7 +2288,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if there is not debt to repay with the specified rate mode', async () => {
|
it('should revert if there is not debt to repay with the specified rate mode', async () => {
|
||||||
const {users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH} = testEnv;
|
const { users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -2306,7 +2342,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if there is not debt to repay', async () => {
|
it('should revert if there is not debt to repay', async () => {
|
||||||
const {users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH} = testEnv;
|
const { users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -2357,7 +2393,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert when max amount allowed to swap is bigger than max slippage', async () => {
|
it('should revert when max amount allowed to swap is bigger than max slippage', async () => {
|
||||||
const {users, pool, weth, oracle, dai, aWETH, uniswapRepayAdapter} = testEnv;
|
const { users, pool, weth, oracle, dai, aWETH, uniswapRepayAdapter } = testEnv;
|
||||||
const user = users[0].signer;
|
const user = users[0].signer;
|
||||||
const userAddress = users[0].address;
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
@ -2681,6 +2717,192 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
||||||
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
||||||
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should swap and repay debt using all the collateral for a bigger debt', async () => {
|
||||||
|
const {
|
||||||
|
users,
|
||||||
|
pool,
|
||||||
|
weth,
|
||||||
|
aWETH,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
uniswapRepayAdapter,
|
||||||
|
helpersContract,
|
||||||
|
} = testEnv;
|
||||||
|
const user = users[0].signer;
|
||||||
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||||
|
|
||||||
|
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||||
|
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||||
|
dai.address,
|
||||||
|
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(1.1).toFixed(0);
|
||||||
|
// Open user Debt
|
||||||
|
await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress);
|
||||||
|
|
||||||
|
const daiStableDebtTokenAddress = (
|
||||||
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
||||||
|
).stableDebtTokenAddress;
|
||||||
|
|
||||||
|
const daiStableDebtContract = await getContract<StableDebtToken>(
|
||||||
|
eContractid.StableDebtToken,
|
||||||
|
daiStableDebtTokenAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
|
||||||
|
|
||||||
|
const liquidityToSwap = amountWETHtoSwap;
|
||||||
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||||
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||||
|
|
||||||
|
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||||
|
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||||
|
|
||||||
|
const actualWEthSwapped = new BigNumber(flashloanAmount.toString())
|
||||||
|
.multipliedBy(0.995)
|
||||||
|
.toFixed(0);
|
||||||
|
|
||||||
|
// Remove other balance
|
||||||
|
await aWETH
|
||||||
|
.connect(user)
|
||||||
|
.transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped));
|
||||||
|
|
||||||
|
await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount);
|
||||||
|
|
||||||
|
const params = buildRepayAdapterParams(
|
||||||
|
dai.address,
|
||||||
|
expectedDaiAmount,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'0x0000000000000000000000000000000000000000000000000000000000000000'
|
||||||
|
);
|
||||||
|
|
||||||
|
await pool
|
||||||
|
.connect(user)
|
||||||
|
.flashLoan(
|
||||||
|
uniswapRepayAdapter.address,
|
||||||
|
[weth.address],
|
||||||
|
[flashloanAmount.toString()],
|
||||||
|
[0],
|
||||||
|
userAddress,
|
||||||
|
params,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
|
||||||
|
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||||
|
const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
|
||||||
|
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||||
|
expect(adapterWethBalance).to.be.eq(Zero);
|
||||||
|
expect(adapterDaiBalance).to.be.eq(Zero);
|
||||||
|
expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
|
||||||
|
expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
|
||||||
|
expect(userAEthBalance).to.be.eq(Zero);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should swap and repay debt using all the collateral for a smaller debt', async () => {
|
||||||
|
const {
|
||||||
|
users,
|
||||||
|
pool,
|
||||||
|
weth,
|
||||||
|
aWETH,
|
||||||
|
oracle,
|
||||||
|
dai,
|
||||||
|
uniswapRepayAdapter,
|
||||||
|
helpersContract,
|
||||||
|
} = testEnv;
|
||||||
|
const user = users[0].signer;
|
||||||
|
const userAddress = users[0].address;
|
||||||
|
|
||||||
|
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||||
|
|
||||||
|
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||||
|
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||||
|
dai.address,
|
||||||
|
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(0.9).toFixed(0);
|
||||||
|
// Open user Debt
|
||||||
|
await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress);
|
||||||
|
|
||||||
|
const daiStableDebtTokenAddress = (
|
||||||
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
||||||
|
).stableDebtTokenAddress;
|
||||||
|
|
||||||
|
const daiStableDebtContract = await getContract<StableDebtToken>(
|
||||||
|
eContractid.StableDebtToken,
|
||||||
|
daiStableDebtTokenAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
|
||||||
|
|
||||||
|
const liquidityToSwap = amountWETHtoSwap;
|
||||||
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||||
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||||
|
|
||||||
|
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||||
|
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||||
|
|
||||||
|
const actualWEthSwapped = new BigNumber(flashloanAmount.toString())
|
||||||
|
.multipliedBy(0.995)
|
||||||
|
.toFixed(0);
|
||||||
|
|
||||||
|
// Remove other balance
|
||||||
|
await aWETH
|
||||||
|
.connect(user)
|
||||||
|
.transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped));
|
||||||
|
|
||||||
|
await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount);
|
||||||
|
|
||||||
|
const params = buildRepayAdapterParams(
|
||||||
|
dai.address,
|
||||||
|
expectedDaiAmount,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
'0x0000000000000000000000000000000000000000000000000000000000000000'
|
||||||
|
);
|
||||||
|
|
||||||
|
await pool
|
||||||
|
.connect(user)
|
||||||
|
.flashLoan(
|
||||||
|
uniswapRepayAdapter.address,
|
||||||
|
[weth.address],
|
||||||
|
[flashloanAmount.toString()],
|
||||||
|
[0],
|
||||||
|
userAddress,
|
||||||
|
params,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
|
||||||
|
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||||
|
const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address);
|
||||||
|
|
||||||
|
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||||
|
expect(adapterWethBalance).to.be.eq(Zero);
|
||||||
|
expect(adapterDaiBalance).to.be.eq(Zero); // Validate there are no leftovers
|
||||||
|
expect(userDaiStableDebtAmountBefore).to.be.gte(userDebt);
|
||||||
|
expect(userDaiStableDebtAmount).to.be.eq(Zero);
|
||||||
|
expect(userAEthBalance).to.be.eq(Zero);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user