mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
fix: updated implementation of the atokens/debt tokens to store additional data (user index/borrow rate) per user
This commit is contained in:
parent
d62ef92d30
commit
b6ae954093
|
@ -23,4 +23,11 @@ interface IScaledBalanceToken {
|
|||
* @return The scaled total supply
|
||||
**/
|
||||
function scaledTotalSupply() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the index at the moment of the last action (mint/burn/transfer)
|
||||
* @param user The address of the user
|
||||
* @return The last user index
|
||||
**/
|
||||
function lastUserIndex(address user) external view returns (uint256);
|
||||
}
|
||||
|
|
|
@ -781,8 +781,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
vars.releaseUnderlying ? vars.amount : 0
|
||||
);
|
||||
|
||||
_usersLastBorrowTimestamp[vars.asset][vars.user] = block.timestamp;
|
||||
|
||||
if (vars.releaseUnderlying) {
|
||||
IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
|
||||
}
|
||||
|
@ -906,8 +904,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
interestRateMode,
|
||||
onBehalfOf,
|
||||
stableDebt,
|
||||
variableDebt,
|
||||
_usersLastBorrowTimestamp
|
||||
variableDebt
|
||||
);
|
||||
|
||||
uint256 paybackAmount =
|
||||
|
|
|
@ -35,7 +35,4 @@ contract LendingPoolStorage {
|
|||
mapping(address => bool) _authorizedFlashBorrowers;
|
||||
|
||||
uint256 internal _flashLoanPremiumToProtocol;
|
||||
|
||||
mapping(address => mapping(address => uint256)) _usersLastBorrowTimestamp;
|
||||
|
||||
}
|
||||
|
|
|
@ -255,7 +255,6 @@ library ValidationLogic {
|
|||
* @param onBehalfOf The address of the user msg.sender is repaying for
|
||||
* @param stableDebt The borrow balance of the user
|
||||
* @param variableDebt The borrow balance of the user
|
||||
* @param lastUsersBorrowTimestamp The data structure that keeps track of all the latest borrowings from the users
|
||||
*/
|
||||
function validateRepay(
|
||||
DataTypes.ReserveCache memory reserveCache,
|
||||
|
@ -264,8 +263,7 @@ library ValidationLogic {
|
|||
DataTypes.InterestRateMode rateMode,
|
||||
address onBehalfOf,
|
||||
uint256 stableDebt,
|
||||
uint256 variableDebt,
|
||||
mapping(address => mapping(address => uint256)) storage lastUsersBorrowTimestamp
|
||||
uint256 variableDebt
|
||||
) external view {
|
||||
(bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
|
||||
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
|
||||
|
@ -273,18 +271,22 @@ library ValidationLogic {
|
|||
|
||||
require(amountSent > 0, Errors.VL_INVALID_AMOUNT);
|
||||
|
||||
require(
|
||||
lastUsersBorrowTimestamp[asset][onBehalfOf] != uint40(block.timestamp),
|
||||
Errors.VL_SAME_BLOCK_BORROW_REPAY
|
||||
);
|
||||
|
||||
require(
|
||||
(stableDebt > 0 &&
|
||||
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) ||
|
||||
(variableDebt > 0 &&
|
||||
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE),
|
||||
Errors.VL_NO_DEBT_OF_SELECTED_TYPE
|
||||
);
|
||||
if (DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) {
|
||||
require(
|
||||
reserveCache.stableDebtLastUpdateTimestamp != block.timestamp,
|
||||
Errors.VL_SAME_BLOCK_BORROW_REPAY
|
||||
);
|
||||
require(stableDebt > 0, Errors.VL_NO_DEBT_OF_SELECTED_TYPE);
|
||||
} else if (DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE) {
|
||||
require(
|
||||
IVariableDebtToken(reserveCache.variableDebtTokenAddress).lastUserIndex(onBehalfOf) !=
|
||||
reserveCache.currVariableBorrowIndex,
|
||||
Errors.VL_SAME_BLOCK_BORROW_REPAY
|
||||
);
|
||||
require(variableDebt > 0, Errors.VL_NO_DEBT_OF_SELECTED_TYPE);
|
||||
} else {
|
||||
revert(Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED);
|
||||
}
|
||||
|
||||
require(
|
||||
amountSent != uint256(-1) || msg.sender == onBehalfOf,
|
||||
|
|
|
@ -125,7 +125,7 @@ contract AToken is
|
|||
) external override onlyLendingPool {
|
||||
uint256 amountScaled = amount.rayDiv(index);
|
||||
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
|
||||
_burn(user, amountScaled);
|
||||
_burn(user, amountScaled, index);
|
||||
|
||||
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
|
||||
|
||||
|
@ -150,7 +150,7 @@ contract AToken is
|
|||
|
||||
uint256 amountScaled = amount.rayDiv(index);
|
||||
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
|
||||
_mint(user, amountScaled);
|
||||
_mint(user, amountScaled, index);
|
||||
|
||||
emit Transfer(address(0), user, amount);
|
||||
emit Mint(user, amount, index);
|
||||
|
@ -175,7 +175,7 @@ contract AToken is
|
|||
// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
|
||||
// In that case, the treasury will experience a (very small) loss, but it
|
||||
// wont cause potentially valid transactions to fail.
|
||||
_mint(treasury, amount.rayDiv(index));
|
||||
_mint(treasury, amount.rayDiv(index), uint128(index));
|
||||
|
||||
emit Transfer(address(0), treasury, amount);
|
||||
emit Mint(treasury, amount, index);
|
||||
|
@ -263,6 +263,15 @@ contract AToken is
|
|||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the index at the moment of the last action (mint/burn/transfer)
|
||||
* @param user The address of the user
|
||||
* @return The last user index
|
||||
**/
|
||||
function lastUserIndex(address user) external view virtual override returns (uint256) {
|
||||
return _usersData[user].data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the Aave treasury, receiving the fees on this aToken
|
||||
**/
|
||||
|
@ -382,6 +391,9 @@ contract AToken is
|
|||
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
|
||||
|
||||
super._transfer(from, to, amount.rayDiv(index));
|
||||
|
||||
_usersData[from].data = uint128(index);
|
||||
_usersData[to].data = uint128(index);
|
||||
|
||||
if (validate) {
|
||||
pool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
|
||||
|
|
|
@ -15,7 +15,12 @@ import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesControl
|
|||
abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) internal _balances;
|
||||
struct BalanceInfo {
|
||||
uint128 balance;
|
||||
uint128 data;
|
||||
}
|
||||
|
||||
mapping(address => BalanceInfo) internal _usersData;
|
||||
|
||||
mapping(address => mapping(address => uint256)) private _allowances;
|
||||
uint256 internal _totalSupply;
|
||||
|
@ -65,7 +70,7 @@ abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
* @return The balance of the token
|
||||
**/
|
||||
function balanceOf(address account) public view virtual override returns (uint256) {
|
||||
return _balances[account];
|
||||
return _usersData[account].balance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,11 +182,12 @@ abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
|
||||
_beforeTokenTransfer(sender, recipient, amount);
|
||||
|
||||
uint256 oldSenderBalance = _balances[sender];
|
||||
_balances[sender] = oldSenderBalance.sub(amount, 'ERC20: transfer amount exceeds balance');
|
||||
uint256 oldRecipientBalance = _balances[recipient];
|
||||
_balances[recipient] = _balances[recipient].add(amount);
|
||||
uint256 oldSenderBalance = _usersData[sender].balance;
|
||||
_usersData[sender].balance = uint128(oldSenderBalance.sub(amount, 'ERC20: transfer amount exceeds balance'));
|
||||
|
||||
uint256 oldRecipientBalance = _usersData[recipient].balance;
|
||||
require((_usersData[recipient].balance = uint128(oldRecipientBalance.add(amount))) >= oldRecipientBalance, 'ERC20: Balance overflow');
|
||||
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
uint256 currentTotalSupply = _totalSupply;
|
||||
_getIncentivesController().handleAction(sender, currentTotalSupply, oldSenderBalance);
|
||||
|
@ -191,7 +197,7 @@ abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
}
|
||||
}
|
||||
|
||||
function _mint(address account, uint256 amount) internal virtual {
|
||||
function _mint(address account, uint256 amount, uint256 data) internal virtual {
|
||||
require(account != address(0), 'ERC20: mint to the zero address');
|
||||
|
||||
_beforeTokenTransfer(address(0), account, amount);
|
||||
|
@ -199,15 +205,16 @@ abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
uint256 oldTotalSupply = _totalSupply;
|
||||
_totalSupply = oldTotalSupply.add(amount);
|
||||
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.add(amount);
|
||||
uint256 oldAccountBalance = _usersData[account].balance;
|
||||
require((_usersData[account].balance = uint128(oldAccountBalance.add(amount))) >= oldAccountBalance, 'ERC20: Balance overflow');
|
||||
require((_usersData[account].data = uint128(data)) == data, 'ERC20: Data field overflow');
|
||||
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
}
|
||||
|
||||
function _burn(address account, uint256 amount) internal virtual {
|
||||
function _burn(address account, uint256 amount, uint256 data) internal virtual {
|
||||
require(account != address(0), 'ERC20: burn from the zero address');
|
||||
|
||||
_beforeTokenTransfer(account, address(0), amount);
|
||||
|
@ -215,8 +222,9 @@ abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
|||
uint256 oldTotalSupply = _totalSupply;
|
||||
_totalSupply = oldTotalSupply.sub(amount);
|
||||
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
|
||||
uint256 oldAccountBalance = _usersData[account].balance;
|
||||
_usersData[account].balance = uint128(oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance'));
|
||||
require((_usersData[account].data = uint128(data)) == data, 'ERC20: Data field overflow');
|
||||
|
||||
if (address(_getIncentivesController()) != address(0)) {
|
||||
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
|
|
|
@ -22,7 +22,6 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
|
||||
uint256 internal _avgStableRate;
|
||||
mapping(address => uint40) internal _timestamps;
|
||||
mapping(address => uint256) internal _usersStableRate;
|
||||
uint40 internal _totalSupplyTimestamp;
|
||||
|
||||
ILendingPool internal _pool;
|
||||
|
@ -96,7 +95,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
* @return The stable rate of user
|
||||
**/
|
||||
function getUserStableRate(address user) external view virtual override returns (uint256) {
|
||||
return _usersStableRate[user];
|
||||
return _usersData[user].data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +104,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
**/
|
||||
function balanceOf(address account) public view virtual override returns (uint256) {
|
||||
uint256 accountBalance = super.balanceOf(account);
|
||||
uint256 stableRate = _usersStableRate[account];
|
||||
uint256 stableRate = _usersData[account].data;
|
||||
if (accountBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,6 +119,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
uint256 amountInRay;
|
||||
uint256 newStableRate;
|
||||
uint256 currentAvgStableRate;
|
||||
uint256 currentStableRate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,16 +150,18 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
vars.previousSupply = totalSupply();
|
||||
vars.currentAvgStableRate = _avgStableRate;
|
||||
vars.nextSupply = _totalSupply = vars.previousSupply.add(amount);
|
||||
|
||||
vars.amountInRay = amount.wadToRay();
|
||||
vars.currentStableRate = _usersData[onBehalfOf].data;
|
||||
|
||||
vars.newStableRate = _usersStableRate[onBehalfOf]
|
||||
|
||||
if(vars.currentStableRate == 0){
|
||||
vars.newStableRate = rate;
|
||||
}else {
|
||||
vars.newStableRate = vars.currentStableRate
|
||||
.rayMul(currentBalance.wadToRay())
|
||||
.add(vars.amountInRay.rayMul(rate))
|
||||
.rayDiv(currentBalance.add(amount).wadToRay());
|
||||
|
||||
require(vars.newStableRate <= type(uint128).max, Errors.SDT_STABLE_DEBT_OVERFLOW);
|
||||
_usersStableRate[onBehalfOf] = vars.newStableRate;
|
||||
}
|
||||
|
||||
//solium-disable-next-line
|
||||
_totalSupplyTimestamp = _timestamps[onBehalfOf] = uint40(block.timestamp);
|
||||
|
@ -171,7 +173,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
.add(rate.rayMul(vars.amountInRay))
|
||||
.rayDiv(vars.nextSupply.wadToRay());
|
||||
|
||||
_mint(onBehalfOf, amount.add(balanceIncrease), vars.previousSupply);
|
||||
_mint(onBehalfOf, amount.add(balanceIncrease), vars.previousSupply, vars.newStableRate);
|
||||
|
||||
emit Transfer(address(0), onBehalfOf, amount);
|
||||
|
||||
|
@ -200,7 +202,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
uint256 previousSupply = totalSupply();
|
||||
uint256 newAvgStableRate = 0;
|
||||
uint256 nextSupply = 0;
|
||||
uint256 userStableRate = _usersStableRate[user];
|
||||
uint256 userStableRate = _usersData[user].data;
|
||||
|
||||
// Since the total supply and each single user debt accrue separately,
|
||||
// there might be accumulation errors so that the last borrower repaying
|
||||
|
@ -225,7 +227,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
}
|
||||
|
||||
if (amount == currentBalance) {
|
||||
_usersStableRate[user] = 0;
|
||||
_usersData[user].data = 0;
|
||||
_timestamps[user] = 0;
|
||||
} else {
|
||||
//solium-disable-next-line
|
||||
|
@ -236,7 +238,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
|
||||
if (balanceIncrease > amount) {
|
||||
uint256 amountToMint = balanceIncrease.sub(amount);
|
||||
_mint(user, amountToMint, previousSupply);
|
||||
_mint(user, amountToMint, previousSupply, userStableRate);
|
||||
emit Mint(
|
||||
user,
|
||||
user,
|
||||
|
@ -249,7 +251,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
);
|
||||
} else {
|
||||
uint256 amountToBurn = amount.sub(balanceIncrease);
|
||||
_burn(user, amountToBurn, previousSupply);
|
||||
_burn(user, amountToBurn, previousSupply, userStableRate);
|
||||
emit Burn(user, amountToBurn, currentBalance, balanceIncrease, newAvgStableRate, nextSupply);
|
||||
}
|
||||
|
||||
|
@ -404,11 +406,15 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
function _mint(
|
||||
address account,
|
||||
uint256 amount,
|
||||
uint256 oldTotalSupply
|
||||
uint256 oldTotalSupply,
|
||||
uint256 data
|
||||
) internal {
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.add(amount);
|
||||
|
||||
uint256 oldAccountBalance = _usersData[account].balance;
|
||||
require(
|
||||
(_usersData[account].balance = uint128(oldAccountBalance.add(amount))) >= oldAccountBalance,
|
||||
'ERC20: Balance overflow'
|
||||
);
|
||||
_usersData[account].data = uint128(data);
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
|
@ -423,11 +429,14 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
function _burn(
|
||||
address account,
|
||||
uint256 amount,
|
||||
uint256 oldTotalSupply
|
||||
uint256 oldTotalSupply,
|
||||
uint256 data
|
||||
) internal {
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.sub(amount, Errors.SDT_BURN_EXCEEDS_BALANCE);
|
||||
|
||||
uint256 oldAccountBalance = _usersData[account].balance;
|
||||
_usersData[account].balance = uint128(
|
||||
oldAccountBalance.sub(amount, Errors.SDT_BURN_EXCEEDS_BALANCE)
|
||||
);
|
||||
_usersData[account].data = uint128(data);
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
uint256 amountScaled = amount.rayDiv(index);
|
||||
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
|
||||
|
||||
_mint(onBehalfOf, amountScaled);
|
||||
_mint(onBehalfOf, amountScaled, index);
|
||||
|
||||
emit Transfer(address(0), onBehalfOf, amount);
|
||||
emit Mint(user, onBehalfOf, amount, index);
|
||||
|
@ -129,7 +129,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
uint256 amountScaled = amount.rayDiv(index);
|
||||
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
|
||||
|
||||
_burn(user, amountScaled);
|
||||
_burn(user, amountScaled, index);
|
||||
|
||||
emit Transfer(user, address(0), amount);
|
||||
emit Burn(user, amount, index);
|
||||
|
@ -159,6 +159,15 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the index at the moment of the last action (mint/burn/transfer)
|
||||
* @param user The address of the user
|
||||
* @return The last user index
|
||||
**/
|
||||
function lastUserIndex(address user) external view virtual override returns (uint256) {
|
||||
return _usersData[user].data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the principal balance of the user and principal total supply.
|
||||
* @param user The address of the user
|
||||
|
|
98
test-suites/test-aave/ltv-validation.spec.ts
Normal file
98
test-suites/test-aave/ltv-validation.spec.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { TestEnv, makeSuite } from './helpers/make-suite';
|
||||
import {
|
||||
APPROVAL_AMOUNT_LENDING_POOL,
|
||||
MAX_UINT_AMOUNT,
|
||||
RAY,
|
||||
MAX_EXPOSURE_CAP,
|
||||
MOCK_CHAINLINK_AGGREGATORS_PRICES,
|
||||
oneEther,
|
||||
} from '../../helpers/constants';
|
||||
import { ProtocolErrors } from '../../helpers/types';
|
||||
import { MintableERC20, WETH9, WETH9Mocked } from '../../types';
|
||||
import { parseEther } from '@ethersproject/units';
|
||||
import { BigNumber } from '@ethersproject/bignumber';
|
||||
import { strategyDAI } from '../../markets/amm/reservesConfigs';
|
||||
import { strategyUSDC } from '../../markets/amm/reservesConfigs';
|
||||
import { ethers } from 'ethers';
|
||||
import { convertToCurrencyDecimals } from '../../helpers/contracts-helpers';
|
||||
|
||||
const { expect } = require('chai');
|
||||
makeSuite('LTV validation tests', (testEnv: TestEnv) => {
|
||||
const {
|
||||
VL_LTV_VALIDATION_FAILED,
|
||||
RC_INVALID_EXPOSURE_CAP,
|
||||
VL_COLLATERAL_CANNOT_COVER_NEW_BORROW,
|
||||
} = ProtocolErrors;
|
||||
const daiPrice = Number(MOCK_CHAINLINK_AGGREGATORS_PRICES.DAI);
|
||||
const usdcPrice = Number(MOCK_CHAINLINK_AGGREGATORS_PRICES.USDC);
|
||||
const daiLTV = Number(strategyDAI.baseLTVAsCollateral);
|
||||
const usdcLTV = Number(strategyUSDC.baseLTVAsCollateral);
|
||||
|
||||
it('User 1 deposits 10 Dai, 10 USDC, user 2 deposits 1 WETH', async () => {
|
||||
const {
|
||||
pool,
|
||||
dai,
|
||||
usdc,
|
||||
weth,
|
||||
users: [user1, user2],
|
||||
} = testEnv;
|
||||
|
||||
const daiAmount = await convertToCurrencyDecimals(dai.address, '10');
|
||||
const usdcAmount = await convertToCurrencyDecimals(usdc.address, '10');
|
||||
const wethAmount = await convertToCurrencyDecimals(weth.address, '1');
|
||||
|
||||
await dai.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT);
|
||||
await usdc.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT);
|
||||
await weth.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT);
|
||||
|
||||
await dai.connect(user1.signer).mint(daiAmount);
|
||||
await usdc.connect(user1.signer).mint(usdcAmount);
|
||||
await weth.connect(user2.signer).mint(wethAmount);
|
||||
|
||||
await pool.connect(user1.signer).deposit(dai.address, daiAmount, user1.address, 0);
|
||||
|
||||
await pool.connect(user1.signer).deposit(usdc.address, usdcAmount, user1.address, 0);
|
||||
|
||||
await pool.connect(user2.signer).deposit(weth.address, wethAmount, user2.address, 0);
|
||||
});
|
||||
|
||||
it('Sets the ltv of DAI to 0', async () => {
|
||||
const {
|
||||
configurator,
|
||||
dai,
|
||||
helpersContract,
|
||||
users: [],
|
||||
} = testEnv;
|
||||
|
||||
await configurator.configureReserveAsCollateral(dai.address, 0, 8000, 10500);
|
||||
|
||||
const ltv = (await helpersContract.getReserveConfigurationData(dai.address)).ltv;
|
||||
|
||||
expect(ltv).to.be.equal(0);
|
||||
});
|
||||
|
||||
it('Borrows 0.01 weth', async () => {
|
||||
const {
|
||||
pool,
|
||||
weth,
|
||||
users: [user1],
|
||||
} = testEnv;
|
||||
const borrowedAmount = await convertToCurrencyDecimals(weth.address, "0.01");
|
||||
|
||||
pool.connect(user1.signer).borrow(weth.address, borrowedAmount, 1, 0, user1.address);
|
||||
});
|
||||
|
||||
it('Tries to withdraw USDC (revert expected)', async () => {
|
||||
const {
|
||||
pool,
|
||||
usdc,
|
||||
users: [user1],
|
||||
} = testEnv;
|
||||
|
||||
const withdrawnAmount = await convertToCurrencyDecimals(usdc.address, "1");
|
||||
|
||||
await expect(
|
||||
pool.connect(user1.signer).withdraw(usdc.address, withdrawnAmount, user1.address)
|
||||
).to.be.revertedWith(VL_LTV_VALIDATION_FAILED);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user