initial changes + test

This commit is contained in:
andyk 2020-09-09 13:47:27 +03:00
parent 23f99d30f0
commit 9d7bf388a6
12 changed files with 132 additions and 50 deletions

View File

@ -15,7 +15,8 @@ interface ILendingPool {
**/
event Deposit(
address indexed reserve,
address indexed user,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referral
);
@ -139,6 +140,7 @@ interface ILendingPool {
function deposit(
address reserve,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;

View File

@ -89,6 +89,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external override {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
@ -100,18 +101,18 @@ contract LendingPool is VersionedInitializable, ILendingPool {
reserve.updateCumulativeIndexesAndTimestamp();
reserve.updateInterestRates(asset, aToken, amount, 0);
bool isFirstDeposit = IAToken(aToken).balanceOf(msg.sender) == 0;
bool isFirstDeposit = IAToken(aToken).balanceOf(onBehalfOf) == 0;
if (isFirstDeposit) {
_usersConfig[msg.sender].setUsingAsCollateral(reserve.index, true);
_usersConfig[onBehalfOf].setUsingAsCollateral(reserve.index, true);
}
//minting AToken to user 1:1 with the specific exchange rate
IAToken(aToken).mint(msg.sender, amount);
IAToken(aToken).mint(onBehalfOf, amount);
//transfer to the aToken contract
IERC20(asset).safeTransferFrom(msg.sender, aToken, amount);
emit Deposit(asset, msg.sender, amount, referralCode);
emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode);
}
/**
@ -450,15 +451,13 @@ contract LendingPool is VersionedInitializable, ILendingPool {
vars.amountPlusPremium = amount.add(vars.premium);
if (debtMode == ReserveLogic.InterestRateMode.NONE) {
IERC20(asset).transferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium);
reserve.updateCumulativeIndexesAndTimestamp();
reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium);
reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0);
emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode);
emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode);
} else {
// If the transfer didn't succeed, the receiver either didn't return the funds, or didn't approve the transfer.
_executeBorrow(
@ -728,13 +727,11 @@ contract LendingPool is VersionedInitializable, ILendingPool {
oracle
);
uint256 reserveIndex = reserve.index;
if (!userConfig.isBorrowing(reserveIndex)) {
userConfig.setBorrowing(reserveIndex, true);
}
reserve.updateCumulativeIndexesAndTimestamp();
//caching the current stable borrow rate
@ -754,13 +751,17 @@ contract LendingPool is VersionedInitializable, ILendingPool {
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(vars.user, vars.amount);
}
reserve.updateInterestRates(vars.asset, vars.aTokenAddress, 0, vars.releaseUnderlying ? vars.amount : 0);
if(vars.releaseUnderlying){
IAToken(vars.aTokenAddress).transferUnderlyingTo(msg.sender, vars.amount);
reserve.updateInterestRates(
vars.asset,
vars.aTokenAddress,
0,
vars.releaseUnderlying ? vars.amount : 0
);
if (vars.releaseUnderlying) {
IAToken(vars.aTokenAddress).transferUnderlyingTo(msg.sender, vars.amount);
}
emit Borrow(
vars.asset,
msg.sender,

View File

@ -13,7 +13,7 @@
"types-gen": "typechain --target ethers-v5 --outDir ./types './artifacts/*.json'",
"test": "buidler test",
"test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts",
"test-flash": "buidler test test/__setup.spec.ts test/flashloan.spec.ts",
"test-flash": "buidler test test/__setup.spec.ts test/collateral-swap.spec.ts",
"dev:coverage": "buidler coverage",
"dev:deployment": "buidler dev-deployment",
"dev:deployExample": "buidler deploy-Example",

View File

@ -33,7 +33,9 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
//user 1 deposits 1000 DAI
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await pool.connect(users[0].signer).deposit(dai.address, amountDAItoDeposit, '0');
await pool
.connect(users[0].signer)
.deposit(dai.address, amountDAItoDeposit, users[0].address, '0');
await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit);
@ -94,12 +96,15 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
it('User 0 deposits 1 WETH and user 1 tries to borrow, but the aTokens received as a transfer are not available as collateral (revert expected)', async () => {
const {users, pool, weth} = testEnv;
const userAddress = await pool.signer.getAddress();
await weth.connect(users[0].signer).mint(await convertToCurrencyDecimals(weth.address, '1'));
await weth.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(users[0].signer).deposit(weth.address, ethers.utils.parseEther('1.0'), '0');
await pool
.connect(users[0].signer)
.deposit(weth.address, ethers.utils.parseEther('1.0'), userAddress, '0');
await expect(
pool
.connect(users[1].signer)

View File

@ -234,7 +234,7 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => {
it('Reverts when trying to disable the DAI reserve with liquidity on it', async () => {
const {dai, pool, configurator} = testEnv;
const userAddress = await pool.signer.getAddress();
await dai.mint(await convertToCurrencyDecimals(dai.address, '1000'));
//approve protocol to access depositor wallet
@ -242,7 +242,7 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => {
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
//user 1 deposits 1000 DAI
await pool.deposit(dai.address, amountDAItoDeposit, '0');
await pool.deposit(dai.address, amountDAItoDeposit, userAddress, '0');
await expect(
configurator.deactivateReserve(dai.address),

View File

@ -30,13 +30,14 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
it('Deposits ETH into the reserve', async () => {
const {pool, weth} = testEnv;
const userAddress = await pool.signer.getAddress();
const amountToDeposit = ethers.utils.parseEther('1');
await weth.mint(amountToDeposit);
await weth.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.deposit(weth.address, amountToDeposit, '0');
await pool.deposit(weth.address, amountToDeposit, userAddress, '0');
});
it('Takes WETH flashloan with mode = 0, returns the funds correctly', async () => {
@ -143,7 +144,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await pool.connect(caller.signer).deposit(dai.address, amountToDeposit, '0');
await pool.connect(caller.signer).deposit(dai.address, amountToDeposit, caller.address, '0');
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
@ -210,6 +211,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
it('Deposits USDC into the reserve', async () => {
const {usdc, pool} = testEnv;
const userAddress = await pool.signer.getAddress();
await usdc.mint(await convertToCurrencyDecimals(usdc.address, '1000'));
@ -217,7 +219,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const amountToDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
await pool.deposit(usdc.address, amountToDeposit, '0');
await pool.deposit(usdc.address, amountToDeposit, userAddress, '0');
});
it('Takes out a 500 USDC flashloan, returns the funds correctly', async () => {
@ -284,7 +286,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const amountToDeposit = await convertToCurrencyDecimals(weth.address, '5');
await pool.connect(caller.signer).deposit(weth.address, amountToDeposit, '0');
await pool.connect(caller.signer).deposit(weth.address, amountToDeposit, caller.address, '0');
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
@ -307,7 +309,6 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
it('Caller deposits 1000 DAI as collateral, Takes a WETH flashloan with mode = 0, does not approve the transfer of the funds', async () => {
const {dai, pool, weth, users} = testEnv;
const caller = users[3];
await dai.connect(caller.signer).mint(await convertToCurrencyDecimals(dai.address, '1000'));
@ -316,7 +317,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await pool.connect(caller.signer).deposit(dai.address, amountToDeposit, '0');
await pool.connect(caller.signer).deposit(dai.address, amountToDeposit, caller.address, '0');
const flashAmount = ethers.utils.parseEther('0.8');

View File

@ -133,7 +133,8 @@ export const approve = async (reserveSymbol: string, user: SignerWithAddress, te
export const deposit = async (
reserveSymbol: string,
amount: string,
user: SignerWithAddress,
sender: SignerWithAddress,
onBehalfOf: tEthereumAddress,
sendValue: string,
expectedResult: string,
testEnv: TestEnv,
@ -149,8 +150,9 @@ export const deposit = async (
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
reserve,
user.address,
testEnv
onBehalfOf,
testEnv,
sender.address
);
if (sendValue) {
@ -158,14 +160,16 @@ export const deposit = async (
}
if (expectedResult === 'success') {
const txResult = await waitForTx(
await await pool.connect(user.signer).deposit(reserve, amountToDeposit, '0', txOptions)
await pool
.connect(sender.signer)
.deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions)
);
const {
reserveData: reserveDataAfter,
userData: userDataAfter,
timestamp,
} = await getContractsData(reserve, user.address, testEnv);
} = await getContractsData(reserve, onBehalfOf, testEnv, sender.address);
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
@ -198,7 +202,7 @@ export const deposit = async (
// });
} else if (expectedResult === 'revert') {
await expect(
pool.connect(user.signer).deposit(reserve, amountToDeposit, '0', txOptions),
pool.connect(sender.signer).deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions),
revertMessage
).to.be.reverted;
}
@ -845,10 +849,15 @@ const getTxCostAndTimestamp = async (tx: ContractReceipt) => {
return {txCost, txTimestamp};
};
const getContractsData = async (reserve: string, user: string, testEnv: TestEnv) => {
const getContractsData = async (
reserve: string,
user: string,
testEnv: TestEnv,
sender?: string
) => {
const {pool} = testEnv;
const reserveData = await getReserveData(pool, reserve);
const userData = await getUserData(pool, reserve, user);
const userData = await getUserData(pool, reserve, user, sender || user);
const timestamp = await timeLatest();
return {

View File

@ -92,13 +92,25 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
case 'deposit':
{
const {amount, sendValue} = action.args;
const {amount, sendValue, onBehalfOf: onBehalfOfIndex} = action.args;
const onBehalfOf = onBehalfOfIndex
? users[parseInt(onBehalfOfIndex)].address
: user.address;
if (!amount || amount === '') {
throw `Invalid amount to deposit into the ${reserve} reserve`;
}
await deposit(reserve, amount, user, sendValue, expected, testEnv, revertMessage);
await deposit(
reserve,
amount,
user,
onBehalfOf,
sendValue,
expected,
testEnv,
revertMessage
);
}
break;

View File

@ -206,7 +206,6 @@
"name": "deposit",
"args": {
"reserve": "WETH",
"amount": "0",
"user": "1"
},
@ -229,6 +228,40 @@
"revertMessage": "Amount must be greater than 0"
}
]
},
{
"description": "User 1 deposits 100 DAI on behalf of user 2, user 2 tries to borrow 0.1 WETH",
"actions": [
{
"name": "mint",
"args": {
"reserve": "DAI",
"amount": "100",
"user": "1"
},
"expected": "success"
},
{
"name": "deposit",
"args": {
"reserve": "DAI",
"amount": "100",
"user": "1",
"onBehalfOf": "2"
},
"expected": "success"
},
{
"name": "borrow",
"args": {
"reserve": "WETH",
"amount": "0.1",
"borrowRateMode": "variable",
"user": "2"
},
"expected": "success"
}
]
}
]
}

View File

@ -61,7 +61,8 @@ export const getReserveData = async (
export const getUserData = async (
pool: LendingPool,
reserve: string,
user: string
user: tEthereumAddress,
sender?: tEthereumAddress
): Promise<UserReserveData> => {
const [userData, aTokenData] = await Promise.all([
pool.getUserReserveData(reserve, user),
@ -77,7 +78,7 @@ export const getUserData = async (
] = aTokenData;
const token = await getMintableErc20(reserve);
const walletBalance = new BigNumber((await token.balanceOf(user)).toString());
const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString());
return {
principalATokenBalance: new BigNumber(principalATokenBalance),

View File

@ -32,7 +32,9 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
//user 1 deposits 1000 DAI
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await pool.connect(depositor.signer).deposit(dai.address, amountDAItoDeposit, '0');
await pool
.connect(depositor.signer)
.deposit(dai.address, amountDAItoDeposit, depositor.address, '0');
const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
@ -43,7 +45,9 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
//user 2 deposits 1 WETH
await pool.connect(borrower.signer).deposit(weth.address, amountETHtoDeposit, '0');
await pool
.connect(borrower.signer)
.deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
//user 2 borrows
const userGlobalData = await pool.getUserAccountData(borrower.address);
@ -224,7 +228,9 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
//user 3 deposits 1000 USDC
const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
await pool.connect(depositor.signer).deposit(usdc.address, amountUSDCtoDeposit, '0');
await pool
.connect(depositor.signer)
.deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0');
//user 4 deposits 1 ETH
const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
@ -235,7 +241,9 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
//approve protocol to access borrower wallet
await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(borrower.signer).deposit(weth.address, amountETHtoDeposit, '0');
await pool
.connect(borrower.signer)
.deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
//user 4 borrows
const userGlobalData = await pool.getUserAccountData(borrower.address);

View File

@ -29,7 +29,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
//user 1 deposits 1000 DAI
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await pool.connect(depositor.signer).deposit(dai.address, amountDAItoDeposit, '0');
await pool
.connect(depositor.signer)
.deposit(dai.address, amountDAItoDeposit, depositor.address, '0');
//user 2 deposits 1 ETH
const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
@ -39,7 +41,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
//approve protocol to access the borrower wallet
await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(borrower.signer).deposit(weth.address, amountETHtoDeposit, '0');
await pool
.connect(borrower.signer)
.deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
//user 2 borrows
@ -194,7 +198,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
//depositor deposits 1000 USDC
const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
await pool.connect(depositor.signer).deposit(usdc.address, amountUSDCtoDeposit, '0');
await pool
.connect(depositor.signer)
.deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0');
//borrower deposits 1 ETH
const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
@ -205,7 +211,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
//approve protocol to access the borrower wallet
await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(borrower.signer).deposit(weth.address, amountETHtoDeposit, '0');
await pool
.connect(borrower.signer)
.deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
//borrower borrows
const userGlobalData = await pool.getUserAccountData(borrower.address);
@ -334,7 +342,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
//borrower deposits 1000 LEND
const amountLENDtoDeposit = await convertToCurrencyDecimals(lend.address, '1000');
await pool.connect(borrower.signer).deposit(lend.address, amountLENDtoDeposit, '0');
await pool
.connect(borrower.signer)
.deposit(lend.address, amountLENDtoDeposit, borrower.address, '0');
const usdcPrice = await oracle.getAssetPrice(usdc.address);
//drops HF below 1