fixed deposit, withdraw tests

This commit is contained in:
The3D 2020-09-14 19:25:45 +02:00
parent b2ec4dd2fa
commit d542f098c1
8 changed files with 157 additions and 82 deletions

View File

@ -31,7 +31,6 @@ library ReserveLogic {
* @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate
* @param averageStableBorrowRate the new average stable borrow rate
* @param variableBorrowRate the new variable borrow rate
* @param liquidityIndex the new liquidity index
* @param variableBorrowIndex the new variable borrow index
@ -40,7 +39,6 @@ library ReserveLogic {
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
@ -190,12 +188,13 @@ library ReserveLogic {
}
struct UpdateInterestRatesLocalVars {
uint256 currentAvgStableRate;
uint256 availableLiquidity;
address stableDebtTokenAddress;
uint256 availableLiquidity;
uint256 totalStableDebt;
uint256 newLiquidityRate;
uint256 newStableRate;
uint256 newVariableRate;
uint256 avgStableRate;
}
/**
@ -215,8 +214,10 @@ library ReserveLogic {
UpdateInterestRatesLocalVars memory vars;
vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress)
.getAverageStableRate();
(vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress)
.getTotalSupplyAndAvgRate();
vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress);
(
@ -226,9 +227,9 @@ library ReserveLogic {
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
reserveAddress,
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
IERC20(vars.stableDebtTokenAddress).totalSupply(),
vars.totalStableDebt,
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
vars.currentAvgStableRate,
vars.avgStableRate,
reserve.configuration.getReserveFactor()
);
require(vars.newLiquidityRate < (1 << 128), 'ReserveLogic: Liquidity rate overflow');
@ -243,7 +244,6 @@ library ReserveLogic {
reserveAddress,
vars.newLiquidityRate,
vars.newStableRate,
vars.currentAvgStableRate,
vars.newVariableRate,
reserve.liquidityIndex,
reserve.variableBorrowIndex
@ -318,7 +318,7 @@ library ReserveLogic {
currentLiquidityRate,
lastUpdateTimestamp
);
uint256 index = cumulatedLiquidityInterest.rayMul(reserve.liquidityIndex);
uint256 index = cumulatedLiquidityInterest.rayMul(liquidityIndex);
require(index < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
reserve.liquidityIndex = uint128(index);

View File

@ -219,18 +219,18 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
return (super.totalSupply(), _avgStableRate);
}
function totalSupply() public override view returns (uint256) {
uint256 principalSupply = super.totalSupply();
if (principalSupply == 0) {
return 0;
}
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
_avgStableRate,
_totalSupplyTimestamp
);
return principalSupply.rayMul(cumulatedInterest);
function getTotalSupplyAndAvgRate() public override view returns (uint256, uint256) {
uint256 avgRate = _avgStableRate;
return (_calcTotalSupply(avgRate), avgRate);
}
function totalSupply() public override view returns (uint256) {
_calcTotalSupply(_avgStableRate);
}
function getTotalSupplyLastUpdated() public override view returns(uint40) {
return _totalSupplyTimestamp;
}
/**
* @dev Returns the principal debt balance of the user from
* @return The debt balance of the user since the last burn/mint action
@ -238,4 +238,16 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
function principalBalanceOf(address user) external virtual override view returns (uint256) {
return super.balanceOf(user);
}
function _calcTotalSupply(uint256 avgRate) internal view returns(uint256) {
uint256 principalSupply = super.totalSupply();
if (principalSupply == 0) {
return 0;
}
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
avgRate,
_totalSupplyTimestamp
);
return principalSupply.rayMul(cumulatedInterest);
}
}

View File

@ -90,10 +90,20 @@ interface IStableDebtToken {
**/
function getPrincipalSupplyAndAvgRate() external view returns (uint256, uint256);
/**
* @dev Returns the principal debt balance of the user
/**
* @dev returns the timestamp of the last update of the total supply
* @return the timestamp
**/
function getTotalSupplyLastUpdated() external view returns (uint40);
/**
* @dev returns the total supply and the average stable rate
**/
function getTotalSupplyAndAvgRate() external view returns (uint256, uint256);
/**
* @dev Returns the principal debt balance of the user
* @return The debt balance of the user since the last burn/mint action
**/
function principalBalanceOf(address user) external view returns (uint256);
}

View File

@ -348,6 +348,21 @@ export const getAToken = async (address?: tEthereumAddress) => {
);
};
export const getStableDebtToken = async (address?: tEthereumAddress) => {
return await getContract<AToken>(
eContractid.StableDebtToken,
address || (await getDb().get(`${eContractid.StableDebtToken}.${BRE.network.name}`).value()).address
);
};
export const getVariableDebtToken = async (address?: tEthereumAddress) => {
return await getContract<AToken>(
eContractid.VariableDebtToken,
address || (await getDb().get(`${eContractid.VariableDebtToken}.${BRE.network.name}`).value()).address
);
};
export const getMintableErc20 = async (address: tEthereumAddress) => {
return await getContract<MintableErc20>(
eContractid.MintableERC20,

View File

@ -42,7 +42,7 @@ export const calcExpectedUserDataAfterDeposit = (
);
expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt;
expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt;
expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt;
expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex;
expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate;
expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated;
@ -115,7 +115,7 @@ export const calcExpectedUserDataAfterWithdraw = (
expectedUserData.currentATokenBalance = aTokenBalance.minus(amountWithdrawn);
expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt;
expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt;
expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt;
expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance(
userDataBeforeAction,
@ -166,9 +166,28 @@ export const calcExpectedReserveDataAfterDeposit = (
reserveDataBeforeAction.availableLiquidity
).plus(amountDeposited);
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt;
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.totalVariableDebt = calcExpectedTotalVariableDebt(
reserveDataBeforeAction,
expectedReserveData.variableBorrowIndex
);
expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt;
expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt;
expectedReserveData.utilizationRate = calcExpectedUtilizationRate(
expectedReserveData.totalStableDebt,
@ -186,17 +205,7 @@ export const calcExpectedReserveDataAfterDeposit = (
expectedReserveData.liquidityRate = rates[0];
expectedReserveData.stableBorrowRate = rates[1];
expectedReserveData.variableBorrowRate = rates[2];
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
return expectedReserveData;
};
@ -225,8 +234,21 @@ export const calcExpectedReserveDataAfterWithdraw = (
reserveDataBeforeAction.availableLiquidity
).minus(amountWithdrawn);
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt;
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt;
expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt(reserveDataBeforeAction, txTimestamp);
expectedReserveData.totalVariableDebt = calcExpectedTotalVariableDebt(reserveDataBeforeAction, expectedReserveData.variableBorrowIndex);
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.utilizationRate = calcExpectedUtilizationRate(
@ -246,16 +268,6 @@ export const calcExpectedReserveDataAfterWithdraw = (
expectedReserveData.stableBorrowRate = rates[1];
expectedReserveData.variableBorrowRate = rates[2];
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
return expectedReserveData;
};
@ -512,7 +524,9 @@ export const calcExpectedUserDataAfterBorrow = (
expectedDataAfterAction,
{
...userDataBeforeAction,
currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex),
currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
),
scaledVariableDebt: expectedUserData.scaledVariableDebt,
variableBorrowIndex:
interestRateMode == RateMode.Variable
@ -690,13 +704,14 @@ export const calcExpectedReserveDataAfterSwapRateMode = (
userDataBeforeAction.principalStableDebt
);
} else {
const totalDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex);
const totalDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
);
const debtAccrued = variableDebt.minus(totalDebtBefore);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus(
variableDebt
@ -838,9 +853,7 @@ export const calcExpectedReserveDataAfterStableRateRebalance = (
);
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus(
debtAccrued
);
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus(debtAccrued);
expectedReserveData.utilizationRate = calcExpectedUtilizationRate(
expectedReserveData.totalStableDebt,
@ -1223,3 +1236,19 @@ const calcExpectedVariableBorrowIndex = (reserveData: ReserveData, timestamp: Bi
return cumulatedInterest.rayMul(reserveData.variableBorrowIndex);
};
const calcExpectedTotalStableDebt = (reserveData: ReserveData, timestamp: BigNumber) => {
const cumulatedInterest = calcCompoundedInterest(
reserveData.averageStableBorrowRate,
timestamp,
reserveData.lastUpdateTimestamp
);
return cumulatedInterest.rayMul(reserveData.principalStableDebt);
}
const calcExpectedTotalVariableDebt = (reserveData: ReserveData, expectedVariableDebtIndex: BigNumber) => {
return reserveData.scaledVariableDebt.rayMul(expectedVariableDebtIndex);
}

View File

@ -4,9 +4,8 @@ import {
getLendingRateOracle,
getIErc20Detailed,
getMintableErc20,
getAToken,
getAToken, getStableDebtToken, getVariableDebtToken
} from '../../../helpers/contracts-helpers';
import {ZERO_ADDRESS} from '../../../helpers/constants';
import {tEthereumAddress} from '../../../helpers/types';
import BigNumber from 'bignumber.js';
import {getDb, BRE} from '../../../helpers/misc-utils';
@ -15,41 +14,51 @@ export const getReserveData = async (
pool: LendingPool,
reserve: tEthereumAddress
): Promise<ReserveData> => {
const data = await pool.getReserveData(reserve);
const tokenAddresses = await pool.getReserveTokensAddresses(reserve);
const rateOracle = await getLendingRateOracle();
const [reserveData, tokenAddresses, rateOracle, token] = await Promise.all([
pool.getReserveData(reserve),
pool.getReserveTokensAddresses(reserve),
getLendingRateOracle(),
getIErc20Detailed(reserve),
]);
const stableDebtToken = await getStableDebtToken(tokenAddresses.stableDebtTokenAddress);
const variableDebtToken = await getVariableDebtToken(tokenAddresses.variableDebtTokenAddress);
const [principalStableDebt] = await stableDebtToken.getPrincipalSupplyAndAvgRate();
const scaledVariableDebt = await variableDebtToken.scaledTotalSupply();
const rate = (await rateOracle.getMarketBorrowRate(reserve)).toString();
const token = await getIErc20Detailed(reserve);
const symbol = await token.symbol();
const decimals = new BigNumber(await token.decimals());
const totalLiquidity = new BigNumber(data.availableLiquidity.toString())
.plus(data.totalStableDebt.toString())
.plus(data.totalVariableDebt.toString());
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
.plus(reserveData.totalStableDebt.toString())
.plus(reserveData.totalVariableDebt.toString());
const utilizationRate = new BigNumber(
totalLiquidity.eq(0)
? 0
: new BigNumber(data.totalStableDebt.toString())
.plus(data.totalVariableDebt.toString())
: new BigNumber(reserveData.totalStableDebt.toString())
.plus(reserveData.totalVariableDebt.toString())
.rayDiv(totalLiquidity)
);
return {
totalLiquidity,
utilizationRate,
availableLiquidity: new BigNumber(data.availableLiquidity.toString()),
totalStableDebt: new BigNumber(data.totalStableDebt.toString()),
totalVariableDebt: new BigNumber(data.totalVariableDebt.toString()),
liquidityRate: new BigNumber(data.liquidityRate.toString()),
variableBorrowRate: new BigNumber(data.variableBorrowRate.toString()),
stableBorrowRate: new BigNumber(data.stableBorrowRate.toString()),
averageStableBorrowRate: new BigNumber(data.averageStableBorrowRate.toString()),
liquidityIndex: new BigNumber(data.liquidityIndex.toString()),
variableBorrowIndex: new BigNumber(data.variableBorrowIndex.toString()),
lastUpdateTimestamp: new BigNumber(data.lastUpdateTimestamp),
availableLiquidity: new BigNumber(reserveData.availableLiquidity.toString()),
totalStableDebt: new BigNumber(reserveData.totalStableDebt.toString()),
totalVariableDebt: new BigNumber(reserveData.totalVariableDebt.toString()),
liquidityRate: new BigNumber(reserveData.liquidityRate.toString()),
variableBorrowRate: new BigNumber(reserveData.variableBorrowRate.toString()),
stableBorrowRate: new BigNumber(reserveData.stableBorrowRate.toString()),
averageStableBorrowRate: new BigNumber(reserveData.averageStableBorrowRate.toString()),
liquidityIndex: new BigNumber(reserveData.liquidityIndex.toString()),
variableBorrowIndex: new BigNumber(reserveData.variableBorrowIndex.toString()),
lastUpdateTimestamp: new BigNumber(reserveData.lastUpdateTimestamp),
principalStableDebt: new BigNumber(principalStableDebt.toString()),
scaledVariableDebt: new BigNumber(scaledVariableDebt.toString()),
address: reserve,
aTokenAddress: tokenAddresses.aTokenAddress,
symbol,
@ -69,7 +78,6 @@ export const getUserData = async (
getATokenUserData(reserve, user, pool),
]);
const token = await getMintableErc20(reserve);
const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString());
@ -106,5 +114,4 @@ const getATokenUserData = async (reserve: string, user: string, pool: LendingPoo
const scaledBalance = await aToken.scaledBalanceOf(user);
return scaledBalance.toString();
};

View File

@ -23,6 +23,8 @@ export interface ReserveData {
availableLiquidity: BigNumber;
totalStableDebt: BigNumber;
totalVariableDebt: BigNumber;
principalStableDebt: BigNumber,
scaledVariableDebt: BigNumber,
averageStableBorrowRate: BigNumber;
variableBorrowRate: BigNumber;
stableBorrowRate: BigNumber;

View File

@ -10,7 +10,7 @@ import {executeStory} from './helpers/scenario-engine';
const scenarioFolder = './test/helpers/scenarios/';
const selectedScenarios: string[] = ['deposit.json'];
const selectedScenarios: string[] = ['withdraw.json'];
fs.readdirSync(scenarioFolder).forEach((file) => {
if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return;