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

View File

@ -219,18 +219,18 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
return (super.totalSupply(), _avgStableRate); return (super.totalSupply(), _avgStableRate);
} }
function totalSupply() public override view returns (uint256) { function getTotalSupplyAndAvgRate() public override view returns (uint256, uint256) {
uint256 principalSupply = super.totalSupply(); uint256 avgRate = _avgStableRate;
if (principalSupply == 0) { return (_calcTotalSupply(avgRate), avgRate);
return 0;
}
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
_avgStableRate,
_totalSupplyTimestamp
);
return principalSupply.rayMul(cumulatedInterest);
} }
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 * @dev Returns the principal debt balance of the user from
* @return The debt balance of the user since the last burn/mint action * @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) { function principalBalanceOf(address user) external virtual override view returns (uint256) {
return super.balanceOf(user); 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); function getPrincipalSupplyAndAvgRate() external view returns (uint256, uint256);
/**
* @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 * @dev Returns the principal debt balance of the user
* @return The debt balance of the user since the last burn/mint action * @return The debt balance of the user since the last burn/mint action
**/ **/
function principalBalanceOf(address user) external view returns (uint256); 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) => { export const getMintableErc20 = async (address: tEthereumAddress) => {
return await getContract<MintableErc20>( return await getContract<MintableErc20>(
eContractid.MintableERC20, eContractid.MintableERC20,

View File

@ -42,7 +42,7 @@ export const calcExpectedUserDataAfterDeposit = (
); );
expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt;
expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt; expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt;
expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex; expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex;
expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate;
expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated;
@ -115,7 +115,7 @@ export const calcExpectedUserDataAfterWithdraw = (
expectedUserData.currentATokenBalance = aTokenBalance.minus(amountWithdrawn); expectedUserData.currentATokenBalance = aTokenBalance.minus(amountWithdrawn);
expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt;
expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt; expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt;
expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance( expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance(
userDataBeforeAction, userDataBeforeAction,
@ -166,9 +166,28 @@ export const calcExpectedReserveDataAfterDeposit = (
reserveDataBeforeAction.availableLiquidity reserveDataBeforeAction.availableLiquidity
).plus(amountDeposited); ).plus(amountDeposited);
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt;
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate; 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.utilizationRate = calcExpectedUtilizationRate(
expectedReserveData.totalStableDebt, expectedReserveData.totalStableDebt,
@ -187,16 +206,6 @@ export const calcExpectedReserveDataAfterDeposit = (
expectedReserveData.stableBorrowRate = rates[1]; expectedReserveData.stableBorrowRate = rates[1];
expectedReserveData.variableBorrowRate = rates[2]; expectedReserveData.variableBorrowRate = rates[2];
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
return expectedReserveData; return expectedReserveData;
}; };
@ -225,8 +234,21 @@ export const calcExpectedReserveDataAfterWithdraw = (
reserveDataBeforeAction.availableLiquidity reserveDataBeforeAction.availableLiquidity
).minus(amountWithdrawn); ).minus(amountWithdrawn);
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt; expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt;
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt; 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.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.utilizationRate = calcExpectedUtilizationRate( expectedReserveData.utilizationRate = calcExpectedUtilizationRate(
@ -246,16 +268,6 @@ export const calcExpectedReserveDataAfterWithdraw = (
expectedReserveData.stableBorrowRate = rates[1]; expectedReserveData.stableBorrowRate = rates[1];
expectedReserveData.variableBorrowRate = rates[2]; expectedReserveData.variableBorrowRate = rates[2];
expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate;
expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex(
reserveDataBeforeAction,
txTimestamp
);
expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex(
reserveDataBeforeAction,
txTimestamp
);
return expectedReserveData; return expectedReserveData;
}; };
@ -512,7 +524,9 @@ export const calcExpectedUserDataAfterBorrow = (
expectedDataAfterAction, expectedDataAfterAction,
{ {
...userDataBeforeAction, ...userDataBeforeAction,
currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex), currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
),
scaledVariableDebt: expectedUserData.scaledVariableDebt, scaledVariableDebt: expectedUserData.scaledVariableDebt,
variableBorrowIndex: variableBorrowIndex:
interestRateMode == RateMode.Variable interestRateMode == RateMode.Variable
@ -690,14 +704,15 @@ export const calcExpectedReserveDataAfterSwapRateMode = (
userDataBeforeAction.principalStableDebt userDataBeforeAction.principalStableDebt
); );
} else { } else {
const totalDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex); const totalDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
);
const debtAccrued = variableDebt.minus(totalDebtBefore); const debtAccrued = variableDebt.minus(totalDebtBefore);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt; expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus( expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus(
variableDebt variableDebt
); );
@ -838,9 +853,7 @@ export const calcExpectedReserveDataAfterStableRateRebalance = (
); );
expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt; expectedReserveData.totalVariableDebt = reserveDataBeforeAction.totalVariableDebt;
expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus( expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt.plus(debtAccrued);
debtAccrued
);
expectedReserveData.utilizationRate = calcExpectedUtilizationRate( expectedReserveData.utilizationRate = calcExpectedUtilizationRate(
expectedReserveData.totalStableDebt, expectedReserveData.totalStableDebt,
@ -1223,3 +1236,19 @@ const calcExpectedVariableBorrowIndex = (reserveData: ReserveData, timestamp: Bi
return cumulatedInterest.rayMul(reserveData.variableBorrowIndex); 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, getLendingRateOracle,
getIErc20Detailed, getIErc20Detailed,
getMintableErc20, getMintableErc20,
getAToken, getAToken, getStableDebtToken, getVariableDebtToken
} from '../../../helpers/contracts-helpers'; } from '../../../helpers/contracts-helpers';
import {ZERO_ADDRESS} from '../../../helpers/constants';
import {tEthereumAddress} from '../../../helpers/types'; import {tEthereumAddress} from '../../../helpers/types';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import {getDb, BRE} from '../../../helpers/misc-utils'; import {getDb, BRE} from '../../../helpers/misc-utils';
@ -15,41 +14,51 @@ export const getReserveData = async (
pool: LendingPool, pool: LendingPool,
reserve: tEthereumAddress reserve: tEthereumAddress
): Promise<ReserveData> => { ): Promise<ReserveData> => {
const data = await pool.getReserveData(reserve); const [reserveData, tokenAddresses, rateOracle, token] = await Promise.all([
const tokenAddresses = await pool.getReserveTokensAddresses(reserve); pool.getReserveData(reserve),
const rateOracle = await getLendingRateOracle(); 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 rate = (await rateOracle.getMarketBorrowRate(reserve)).toString();
const token = await getIErc20Detailed(reserve);
const symbol = await token.symbol(); const symbol = await token.symbol();
const decimals = new BigNumber(await token.decimals()); const decimals = new BigNumber(await token.decimals());
const totalLiquidity = new BigNumber(data.availableLiquidity.toString()) const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
.plus(data.totalStableDebt.toString()) .plus(reserveData.totalStableDebt.toString())
.plus(data.totalVariableDebt.toString()); .plus(reserveData.totalVariableDebt.toString());
const utilizationRate = new BigNumber( const utilizationRate = new BigNumber(
totalLiquidity.eq(0) totalLiquidity.eq(0)
? 0 ? 0
: new BigNumber(data.totalStableDebt.toString()) : new BigNumber(reserveData.totalStableDebt.toString())
.plus(data.totalVariableDebt.toString()) .plus(reserveData.totalVariableDebt.toString())
.rayDiv(totalLiquidity) .rayDiv(totalLiquidity)
); );
return { return {
totalLiquidity, totalLiquidity,
utilizationRate, utilizationRate,
availableLiquidity: new BigNumber(data.availableLiquidity.toString()), availableLiquidity: new BigNumber(reserveData.availableLiquidity.toString()),
totalStableDebt: new BigNumber(data.totalStableDebt.toString()), totalStableDebt: new BigNumber(reserveData.totalStableDebt.toString()),
totalVariableDebt: new BigNumber(data.totalVariableDebt.toString()), totalVariableDebt: new BigNumber(reserveData.totalVariableDebt.toString()),
liquidityRate: new BigNumber(data.liquidityRate.toString()), liquidityRate: new BigNumber(reserveData.liquidityRate.toString()),
variableBorrowRate: new BigNumber(data.variableBorrowRate.toString()), variableBorrowRate: new BigNumber(reserveData.variableBorrowRate.toString()),
stableBorrowRate: new BigNumber(data.stableBorrowRate.toString()), stableBorrowRate: new BigNumber(reserveData.stableBorrowRate.toString()),
averageStableBorrowRate: new BigNumber(data.averageStableBorrowRate.toString()), averageStableBorrowRate: new BigNumber(reserveData.averageStableBorrowRate.toString()),
liquidityIndex: new BigNumber(data.liquidityIndex.toString()), liquidityIndex: new BigNumber(reserveData.liquidityIndex.toString()),
variableBorrowIndex: new BigNumber(data.variableBorrowIndex.toString()), variableBorrowIndex: new BigNumber(reserveData.variableBorrowIndex.toString()),
lastUpdateTimestamp: new BigNumber(data.lastUpdateTimestamp), lastUpdateTimestamp: new BigNumber(reserveData.lastUpdateTimestamp),
principalStableDebt: new BigNumber(principalStableDebt.toString()),
scaledVariableDebt: new BigNumber(scaledVariableDebt.toString()),
address: reserve, address: reserve,
aTokenAddress: tokenAddresses.aTokenAddress, aTokenAddress: tokenAddresses.aTokenAddress,
symbol, symbol,
@ -69,7 +78,6 @@ export const getUserData = async (
getATokenUserData(reserve, user, pool), getATokenUserData(reserve, user, pool),
]); ]);
const token = await getMintableErc20(reserve); const token = await getMintableErc20(reserve);
const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString()); 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); const scaledBalance = await aToken.scaledBalanceOf(user);
return scaledBalance.toString(); return scaledBalance.toString();
}; };

View File

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

View File

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