Skip to content

Commit

Permalink
feat: extend AaveTestBase v3 (#12)
Browse files Browse the repository at this point in the history
- adds methods to test interest rate
- adds methods to test configurations
- adds methods to test emodes
sakulstra authored Sep 21, 2022
1 parent 80379df commit 8ee6ee7
Showing 3 changed files with 400 additions and 7 deletions.
2 changes: 1 addition & 1 deletion lib/aave-address-book
Submodule aave-address-book updated 50 files
+0 −1 .env.example
+0 −0 .github/workflows/cron.yaml
+12 −0 .github/workflows/dispatch-draft-release.yml
+17 −0 .github/workflows/merge-main.yml
+0 −36 .github/workflows/test.yaml
+3 −1 .gitignore
+15 −0 .npmignore
+63 −0 CHANGELOG.md
+2 −2 foundry.toml
+1 −1 lib/forge-std
+13 −8 package.json
+41 −31 scripts/config.ts
+13 −2 scripts/generator.ts
+21 −2 scripts/generator_v2.ts
+17 −0 scripts/generator_v3.ts
+4 −2 src/AaveAddressBook.sol
+1 −1 src/AaveAddressBookV2.sol
+23 −0 src/AaveAddressBookV2Testnet.sol
+1 −1 src/AaveAddressBookV3.sol
+54 −31 src/AaveAddressBookV3Testnet.sol
+35 −0 src/AaveV2Goerli.sol
+2 −1 src/AaveV2Polygon.sol
+34 −0 src/AaveV3ArbitrumGoerli.sol
+34 −0 src/AaveV3Goerli.sol
+34 −0 src/AaveV3OptimismGoerli.sol
+1 −1 src/AaveV3Polygon.sol
+20 −0 src/ts/AaveAddressBook.ts
+12 −0 src/ts/AaveV2Avalanche.ts
+13 −0 src/ts/AaveV2Ethereum.ts
+13 −0 src/ts/AaveV2EthereumAMM.ts
+13 −0 src/ts/AaveV2EthereumArc.ts
+12 −0 src/ts/AaveV2Fuji.ts
+12 −0 src/ts/AaveV2Goerli.ts
+12 −0 src/ts/AaveV2Mumbai.ts
+13 −0 src/ts/AaveV2Polygon.ts
+13 −0 src/ts/AaveV3Arbitrum.ts
+13 −0 src/ts/AaveV3ArbitrumGoerli.ts
+13 −0 src/ts/AaveV3Avalanche.ts
+13 −0 src/ts/AaveV3Fantom.ts
+13 −0 src/ts/AaveV3FantomTestnet.ts
+13 −0 src/ts/AaveV3Fuji.ts
+13 −0 src/ts/AaveV3Goerli.ts
+13 −0 src/ts/AaveV3Harmony.ts
+13 −0 src/ts/AaveV3Mumbai.ts
+13 −0 src/ts/AaveV3Optimism.ts
+13 −0 src/ts/AaveV3OptimismGoerli.ts
+13 −0 src/ts/AaveV3OptimismKovan.ts
+13 −0 src/ts/AaveV3Polygon.ts
+4 −3 tsconfig.json
+407 −84 yarn.lock
2 changes: 1 addition & 1 deletion lib/forge-std
403 changes: 398 additions & 5 deletions src/ProtocolV3TestBase.sol
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
pragma solidity >=0.7.5 <0.9.0;

import 'forge-std/Test.sol';
import {IPool, IPoolAddressesProvider, IAaveProtocolDataProvider, TokenData, IInterestRateStrategy, DataTypes} from 'aave-address-book/AaveV3.sol';
import {IAaveOracle, IPool, IPoolAddressesProvider, IAaveProtocolDataProvider, TokenData, IInterestRateStrategy, DataTypes} from 'aave-address-book/AaveV3.sol';
import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol';

struct ReserveTokens {
@@ -41,6 +41,28 @@ struct LocalVars {
ReserveConfig[] configs;
}

struct InterestStrategyValues {
address addressesProvider;
uint256 optimalUsageRatio;
uint256 optimalStableToTotalDebtRatio;
uint256 baseStableBorrowRate;
uint256 stableRateSlope1;
uint256 stableRateSlope2;
uint256 baseVariableBorrowRate;
uint256 variableRateSlope1;
uint256 variableRateSlope2;
}

interface IInitializableAdminUpgradeabilityProxy {
function upgradeTo(address newImplementation) external;

function upgradeToAndCall(address newImplementation, bytes calldata data) external payable;

function admin() external returns (address);

function implementation() external returns (address);
}

contract ProtocolV3TestBase is Test {
address public constant ETH_MOCK_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

@@ -84,6 +106,7 @@ contract ProtocolV3TestBase is Test {
*/
function _getFirstCollateral(ReserveConfig[] memory configs)
private
pure
returns (ReserveConfig memory config)
{
for (uint256 i = 0; i < configs.length; i++) {
@@ -123,7 +146,7 @@ contract ProtocolV3TestBase is Test {
for (uint256 i = 0; i < configs.length; i++) {
uint256 amount = 10**configs[i].decimals;
if (configs[i].borrowingEnabled) {
_borrow(configs[i], pool, 10**configs[i].decimals, false);
_borrow(configs[i], pool, amount, false);
} else {
console.log('SKIP: BORROWING_DISABLED %s', configs[i].symbol);
}
@@ -140,7 +163,7 @@ contract ProtocolV3TestBase is Test {
for (uint256 i = 0; i < configs.length; i++) {
uint256 amount = 10**configs[i].decimals;
if (configs[i].borrowingEnabled && configs[i].stableBorrowRateEnabled) {
_borrow(configs[i], pool, 10**configs[i].decimals, true);
_borrow(configs[i], pool, amount, true);
} else {
console.log('SKIP: STABLE_BORROWING_DISABLED %s', configs[i].symbol);
}
@@ -183,14 +206,22 @@ contract ProtocolV3TestBase is Test {
pool.borrow(config.underlying, amount, stable ? 1 : 2, 0, address(this));
}

function _isInUint256Array(uint256[] memory haystack, uint256 needle) private returns (bool) {
function _isInUint256Array(uint256[] memory haystack, uint256 needle)
private
pure
returns (bool)
{
for (uint256 i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) return true;
}
return false;
}

function _isInAddressArray(address[] memory haystack, address needle) private returns (bool) {
function _isInAddressArray(address[] memory haystack, address needle)
private
pure
returns (bool)
{
for (uint256 i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) return true;
}
@@ -448,4 +479,366 @@ contract ProtocolV3TestBase is Test {

return localConfig;
}

function _findReserveConfig(ReserveConfig[] memory configs, address underlying)
internal
pure
returns (ReserveConfig memory)
{
for (uint256 i = 0; i < configs.length; i++) {
if (configs[i].underlying == underlying) {
return configs[i];
}
}
revert('RESERVE_CONFIG_NOT_FOUND');
}

function _logReserveConfig(ReserveConfig memory config) internal view {
console.log('Symbol ', config.symbol);
console.log('Underlying address ', config.underlying);
console.log('AToken address ', config.aToken);
console.log('Stable debt token address ', config.stableDebtToken);
console.log('Variable debt token address ', config.variableDebtToken);
console.log('Decimals ', config.decimals);
console.log('LTV ', config.ltv);
console.log('Liquidation Threshold ', config.liquidationThreshold);
console.log('Liquidation Bonus ', config.liquidationBonus);
console.log('Liquidation protocol fee ', config.liquidationProtocolFee);
console.log('Reserve Factor ', config.reserveFactor);
console.log('Usage as collateral enabled ', (config.usageAsCollateralEnabled) ? 'Yes' : 'No');
console.log('Borrowing enabled ', (config.borrowingEnabled) ? 'Yes' : 'No');
console.log('Stable borrow rate enabled ', (config.stableBorrowRateEnabled) ? 'Yes' : 'No');
console.log('Supply cap ', config.supplyCap);
console.log('Borrow cap ', config.borrowCap);
console.log('Debt ceiling ', config.debtCeiling);
console.log('eMode category ', config.eModeCategory);
console.log('Interest rate strategy ', config.interestRateStrategy);
console.log('Is active ', (config.isActive) ? 'Yes' : 'No');
console.log('Is frozen ', (config.isFrozen) ? 'Yes' : 'No');
console.log('Is siloed ', (config.isSiloed) ? 'Yes' : 'No');
console.log('-----');
console.log('-----');
}

function _validateReserveConfig(
ReserveConfig memory expectedConfig,
ReserveConfig[] memory allConfigs
) internal pure {
ReserveConfig memory config = _findReserveConfig(allConfigs, expectedConfig.underlying);
require(
keccak256(bytes(config.symbol)) == keccak256(bytes(expectedConfig.symbol)),
'_validateConfigsInAave() : INVALID_SYMBOL'
);
require(
config.underlying == expectedConfig.underlying,
'_validateConfigsInAave() : INVALID_UNDERLYING'
);
require(config.decimals == expectedConfig.decimals, '_validateConfigsInAave: INVALID_DECIMALS');
require(config.ltv == expectedConfig.ltv, '_validateConfigsInAave: INVALID_LTV');
require(
config.liquidationThreshold == expectedConfig.liquidationThreshold,
'_validateConfigsInAave: INVALID_LIQ_THRESHOLD'
);
require(
config.liquidationBonus == expectedConfig.liquidationBonus,
'_validateConfigsInAave: INVALID_LIQ_BONUS'
);
require(
config.liquidationProtocolFee == expectedConfig.liquidationProtocolFee,
'_validateConfigsInAave: INVALID_LIQUIDATION_PROTOCOL_FEE'
);
require(
config.reserveFactor == expectedConfig.reserveFactor,
'_validateConfigsInAave: INVALID_RESERVE_FACTOR'
);

require(
config.usageAsCollateralEnabled == expectedConfig.usageAsCollateralEnabled,
'_validateConfigsInAave: INVALID_USAGE_AS_COLLATERAL'
);
require(
config.borrowingEnabled == expectedConfig.borrowingEnabled,
'_validateConfigsInAave: INVALID_BORROWING_ENABLED'
);
require(
config.stableBorrowRateEnabled == expectedConfig.stableBorrowRateEnabled,
'_validateConfigsInAave: INVALID_STABLE_BORROW_ENABLED'
);
require(
config.isActive == expectedConfig.isActive,
'_validateConfigsInAave: INVALID_IS_ACTIVE'
);
require(
config.isFrozen == expectedConfig.isFrozen,
'_validateConfigsInAave: INVALID_IS_FROZEN'
);
require(
config.isSiloed == expectedConfig.isSiloed,
'_validateConfigsInAave: INVALID_IS_SILOED'
);
require(
config.supplyCap == expectedConfig.supplyCap,
'_validateConfigsInAave: INVALID_SUPPLY_CAP'
);
require(
config.borrowCap == expectedConfig.borrowCap,
'_validateConfigsInAave: INVALID_BORROW_CAP'
);
require(
config.debtCeiling == expectedConfig.debtCeiling,
'_validateConfigsInAave: INVALID_DEBT_CEILING'
);
require(
config.eModeCategory == expectedConfig.eModeCategory,
'_validateConfigsInAave: INVALID_EMODE_CATEGORY'
);
require(
config.interestRateStrategy == expectedConfig.interestRateStrategy,
'_validateConfigsInAave: INVALID_INTEREST_RATE_STRATEGY'
);
}

function _validateInterestRateStrategy(
address interestRateStrategyAddress,
address expectedStrategy,
InterestStrategyValues memory expectedStrategyValues
) internal view {
IInterestRateStrategy strategy = IInterestRateStrategy(interestRateStrategyAddress);

require(
address(strategy) == expectedStrategy,
'_validateInterestRateStrategy() : INVALID_STRATEGY_ADDRESS'
);

require(
strategy.OPTIMAL_USAGE_RATIO() == expectedStrategyValues.optimalUsageRatio,
'_validateInterestRateStrategy() : INVALID_OPTIMAL_RATIO'
);
require(
strategy.OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO() ==
expectedStrategyValues.optimalStableToTotalDebtRatio,
'_validateInterestRateStrategy() : INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO'
);
require(
address(strategy.ADDRESSES_PROVIDER()) == expectedStrategyValues.addressesProvider,
'_validateInterestRateStrategy() : INVALID_ADDRESSES_PROVIDER'
);
require(
strategy.getBaseVariableBorrowRate() == expectedStrategyValues.baseVariableBorrowRate,
'_validateInterestRateStrategy() : INVALID_BASE_VARIABLE_BORROW'
);
require(
strategy.getBaseStableBorrowRate() == expectedStrategyValues.baseStableBorrowRate,
'_validateInterestRateStrategy() : INVALID_BASE_VARIABLE_BORROW'
);
require(
strategy.getStableRateSlope1() == expectedStrategyValues.stableRateSlope1,
'_validateInterestRateStrategy() : INVALID_STABLE_SLOPE_1'
);
require(
strategy.getStableRateSlope2() == expectedStrategyValues.stableRateSlope2,
'_validateInterestRateStrategy() : INVALID_STABLE_SLOPE_2'
);
require(
strategy.getVariableRateSlope1() == expectedStrategyValues.variableRateSlope1,
'_validateInterestRateStrategy() : INVALID_VARIABLE_SLOPE_1'
);
require(
strategy.getVariableRateSlope2() == expectedStrategyValues.variableRateSlope2,
'_validateInterestRateStrategy() : INVALID_VARIABLE_SLOPE_2'
);
}

function _noReservesConfigsChangesApartNewListings(
ReserveConfig[] memory allConfigsBefore,
ReserveConfig[] memory allConfigsAfter
) internal pure {
for (uint256 i = 0; i < allConfigsBefore.length; i++) {
_requireNoChangeInConfigs(allConfigsBefore[i], allConfigsAfter[i]);
}
}

function _noReservesConfigsChangesApartFrom(
ReserveConfig[] memory allConfigsBefore,
ReserveConfig[] memory allConfigsAfter,
address assetChangedUnderlying
) internal pure {
require(allConfigsBefore.length == allConfigsAfter.length, 'A_UNEXPECTED_NEW_LISTING_HAPPENED');

for (uint256 i = 0; i < allConfigsBefore.length; i++) {
if (assetChangedUnderlying != allConfigsBefore[i].underlying) {
_requireNoChangeInConfigs(allConfigsBefore[i], allConfigsAfter[i]);
}
}
}

function _requireNoChangeInConfigs(ReserveConfig memory config1, ReserveConfig memory config2)
internal
pure
{
require(
keccak256(abi.encodePacked(config1.symbol)) == keccak256(abi.encodePacked(config2.symbol)),
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_SYMBOL_CHANGED'
);
require(
config1.underlying == config2.underlying,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_UNDERLYING_CHANGED'
);
require(
config1.aToken == config2.aToken,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_A_TOKEN_CHANGED'
);
require(
config1.stableDebtToken == config2.stableDebtToken,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_STABLE_DEBT_TOKEN_CHANGED'
);
require(
config1.variableDebtToken == config2.variableDebtToken,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_VARIABLE_DEBT_TOKEN_CHANGED'
);
require(
config1.decimals == config2.decimals,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_DECIMALS_CHANGED'
);
require(
config1.ltv == config2.ltv,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_LTV_CHANGED'
);
require(
config1.liquidationThreshold == config2.liquidationThreshold,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_LIQ_THRESHOLD_CHANGED'
);
require(
config1.liquidationBonus == config2.liquidationBonus,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_LIQ_BONUS_CHANGED'
);
require(
config1.liquidationProtocolFee == config2.liquidationProtocolFee,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_LIQ_PROTOCOL_FEE_CHANGED'
);
require(
config1.reserveFactor == config2.reserveFactor,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_RESERVE_FACTOR_CHANGED'
);
require(
config1.usageAsCollateralEnabled == config2.usageAsCollateralEnabled,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_USAGE_AS_COLLATERAL_ENABLED_CHANGED'
);
require(
config1.borrowingEnabled == config2.borrowingEnabled,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_BORROWING_ENABLED_CHANGED'
);
require(
config1.interestRateStrategy == config2.interestRateStrategy,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_INTEREST_RATE_STRATEGY_CHANGED'
);
require(
config1.stableBorrowRateEnabled == config2.stableBorrowRateEnabled,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_STABLE_BORROWING_CHANGED'
);
require(
config1.isActive == config2.isActive,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_IS_ACTIVE_CHANGED'
);
require(
config1.isFrozen == config2.isFrozen,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_IS_FROZEN_CHANGED'
);
require(
config1.isSiloed == config2.isSiloed,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_IS_SILOED_CHANGED'
);
require(
config1.supplyCap == config2.supplyCap,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_SUPPLY_CAP_CHANGED'
);
require(
config1.borrowCap == config2.borrowCap,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_BORROW_CAP_CHANGED'
);
require(
config1.debtCeiling == config2.debtCeiling,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_DEBT_CEILING_CHANGED'
);
require(
config1.eModeCategory == config2.eModeCategory,
'_noReservesConfigsChangesApartNewListings() : UNEXPECTED_E_MODE_CATEGORY_CHANGED'
);
}

function _validateCountOfListings(
uint256 count,
ReserveConfig[] memory allConfigsBefore,
ReserveConfig[] memory allConfigsAfter
) internal pure {
require(
allConfigsBefore.length == allConfigsAfter.length - count,
'_validateCountOfListings() : INVALID_COUNT_OF_LISTINGS'
);
}

function _validateReserveTokensImpls(
IPoolAddressesProvider addressProvider,
ReserveConfig memory config,
ReserveTokens memory expectedImpls
) internal {
address poolConfigurator = addressProvider.getPoolConfigurator();
vm.startPrank(poolConfigurator);
require(
IInitializableAdminUpgradeabilityProxy(config.aToken).implementation() ==
expectedImpls.aToken,
'_validateReserveTokensImpls() : INVALID_ATOKEN_IMPL'
);
require(
IInitializableAdminUpgradeabilityProxy(config.variableDebtToken).implementation() ==
expectedImpls.variableDebtToken,
'_validateReserveTokensImpls() : INVALID_ATOKEN_IMPL'
);
require(
IInitializableAdminUpgradeabilityProxy(config.stableDebtToken).implementation() ==
expectedImpls.stableDebtToken,
'_validateReserveTokensImpls() : INVALID_ATOKEN_IMPL'
);
vm.stopPrank();
}

function _validateAssetSourceOnOracle(
IPoolAddressesProvider addressProvider,
address asset,
address expectedSource
) external view {
IAaveOracle oracle = IAaveOracle(addressProvider.getPriceOracle());

require(
oracle.getSourceOfAsset(asset) == expectedSource,
'_validateAssetSourceOnOracle() : INVALID_PRICE_SOURCE'
);
}

function _validateAssetsOnEmodeCategory(
uint256 category,
ReserveConfig[] memory assetsConfigs,
string[] memory expectedAssets
) internal pure {
string[] memory assetsInCategory = new string[](assetsConfigs.length);

uint256 countCategory;
for (uint256 i = 0; i < assetsConfigs.length; i++) {
if (assetsConfigs[i].eModeCategory == category) {
assetsInCategory[countCategory] = assetsConfigs[i].symbol;
require(
keccak256(bytes(assetsInCategory[countCategory])) ==
keccak256(bytes(expectedAssets[countCategory])),
'_getAssetOnEmodeCategory(): INCONSISTENT_ASSETS'
);
countCategory++;
if (countCategory > expectedAssets.length) {
revert('_getAssetOnEmodeCategory(): MORE_ASSETS_IN_CATEGORY_THAN_EXPECTED');
}
}
}
if (countCategory < expectedAssets.length) {
revert('_getAssetOnEmodeCategory(): LESS_ASSETS_IN_CATEGORY_THAN_EXPECTED');
}
}
}

0 comments on commit 8ee6ee7

Please sign in to comment.