Skip to content

Commit 312a899

Browse files
fix: config engine base payload (aave-dao#131)
* fix: config engine base payload * chore: some cleanup * chore: fix docs * test: asset listing with emode creation * chore: fix lint * chore: fix build * chore: fix build * chore: fix lint * test: fix bitmap * chore: move mocks to different file
1 parent 95d1cc3 commit 312a899

File tree

8 files changed

+426
-32
lines changed

8 files changed

+426
-32
lines changed

src/contracts/extensions/v3-config-engine/AaveV3Payload.sol

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,30 @@ abstract contract AaveV3Payload {
4242
function execute() external {
4343
_preExecute();
4444

45-
IEngine.EModeCategoryCreation[] memory newEmodes = eModeCategoryCreations();
46-
IEngine.EModeCategoryUpdate[] memory eModeCategories = eModeCategoriesUpdates();
4745
IEngine.Listing[] memory listings = newListings();
4846
IEngine.ListingWithCustomImpl[] memory listingsCustom = newListingsCustom();
47+
IEngine.EModeCategoryUpdate[] memory eModeCategories = eModeCategoriesUpdates();
48+
IEngine.AssetEModeUpdate[] memory assetsEModes = assetsEModeUpdates();
49+
IEngine.EModeCategoryCreation[] memory newEmodes = eModeCategoryCreations();
4950
IEngine.CollateralUpdate[] memory collaterals = collateralsUpdates();
5051
IEngine.BorrowUpdate[] memory borrows = borrowsUpdates();
5152
IEngine.RateStrategyUpdate[] memory rates = rateStrategiesUpdates();
5253
IEngine.PriceFeedUpdate[] memory priceFeeds = priceFeedsUpdates();
53-
IEngine.AssetEModeUpdate[] memory assetsEModes = assetsEModeUpdates();
5454
IEngine.CapsUpdate[] memory caps = capsUpdates();
5555

56-
if (newEmodes.length != 0) {
56+
if (listings.length != 0) {
5757
address(CONFIG_ENGINE).functionDelegateCall(
58-
abi.encodeWithSelector(CONFIG_ENGINE.createEModeCategories.selector, newEmodes)
58+
abi.encodeWithSelector(CONFIG_ENGINE.listAssets.selector, getPoolContext(), listings)
59+
);
60+
}
61+
62+
if (listingsCustom.length != 0) {
63+
address(CONFIG_ENGINE).functionDelegateCall(
64+
abi.encodeWithSelector(
65+
CONFIG_ENGINE.listAssetsCustom.selector,
66+
getPoolContext(),
67+
listingsCustom
68+
)
5969
);
6070
}
6171

@@ -65,19 +75,15 @@ abstract contract AaveV3Payload {
6575
);
6676
}
6777

68-
if (listings.length != 0) {
78+
if (assetsEModes.length != 0) {
6979
address(CONFIG_ENGINE).functionDelegateCall(
70-
abi.encodeWithSelector(CONFIG_ENGINE.listAssets.selector, getPoolContext(), listings)
80+
abi.encodeWithSelector(CONFIG_ENGINE.updateAssetsEMode.selector, assetsEModes)
7181
);
7282
}
7383

74-
if (listingsCustom.length != 0) {
84+
if (newEmodes.length != 0) {
7585
address(CONFIG_ENGINE).functionDelegateCall(
76-
abi.encodeWithSelector(
77-
CONFIG_ENGINE.listAssetsCustom.selector,
78-
getPoolContext(),
79-
listingsCustom
80-
)
86+
abi.encodeWithSelector(CONFIG_ENGINE.createEModeCategories.selector, newEmodes)
8187
);
8288
}
8389

@@ -105,12 +111,6 @@ abstract contract AaveV3Payload {
105111
);
106112
}
107113

108-
if (assetsEModes.length != 0) {
109-
address(CONFIG_ENGINE).functionDelegateCall(
110-
abi.encodeWithSelector(CONFIG_ENGINE.updateAssetsEMode.selector, assetsEModes)
111-
);
112-
}
113-
114114
if (caps.length != 0) {
115115
address(CONFIG_ENGINE).functionDelegateCall(
116116
abi.encodeWithSelector(CONFIG_ENGINE.updateCaps.selector, caps)

src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ interface IAaveV3ConfigEngine {
7777
* borrowCap: 60_000, // 60k AAVE
7878
* debtCeiling: 100_000, // 100k USD
7979
* liqProtocolFee: 10_00, // 10%
80-
* eModeCategory: 0, // No category
8180
* }
8281
*/
8382
struct Listing {

src/contracts/extensions/v3-config-engine/README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,26 @@ Change eMode category configuration? Same as previous, just define the update wi
3232

3333
Change eMode category of a particular asset? Same as previous, just define the update within a `assetsEModeUpdates()` function, and the base payload will take care of the rest.
3434

35+
Create a new eMode category? Same as previous, just define the update within a `eModeCategoryCreations()` function, and the base payload will take care of the rest.
36+
3537
### Internal aspects to consider
3638

3739
- Frequently, at the same time that you want to do an update of parameters or listing, you also want to do something extra before or after.
3840
The `Base Aave v3 Payload` defines `_preExecute()` and `_postExecute()` hook functions, that you can redefine on your payload and will the execute before and after all configs changes/listings you define.
3941

4042
- The payload also allow you to group changes of parameters and listings, just by defining at the same time the aforementioned `newListings()`, `capsUpdate()` and/or `collateralsUpdates()` and so on. For reference, the execution ordering is the following:
4143
1. `_preExecute()`
42-
2. `eModeCategoriesUpdates()`
43-
3. `newListings()`
44-
4. `newListingsCustom()`
45-
5. `borrowsUpdates()`
46-
6. `collateralsUpdates()`
47-
7. `rateStrategiesUpdates()`
48-
8. `priceFeedsUpdates()`
49-
9. `assetsEModeUpdates()`
50-
10. `capsUpdates()`
51-
11. `_postExecute()`
44+
2. `newListings()`
45+
3. `newListingsCustom()`
46+
4. `eModeCategoriesUpdates()`
47+
5. `assetsEModeUpdates()`
48+
6. `eModeCategoryCreations()`
49+
7. `borrowsUpdates()`
50+
8. `collateralsUpdates()`
51+
9. `rateStrategiesUpdates()`
52+
10. `priceFeedsUpdates()`
53+
11. `capsUpdates()`
54+
12. `_postExecute()`
5255

5356
## Links to examples
5457

src/contracts/extensions/v3-config-engine/libraries/ListingEngine.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {PriceFeedEngine} from './PriceFeedEngine.sol';
77
import {CapsEngine} from './CapsEngine.sol';
88
import {BorrowEngine} from './BorrowEngine.sol';
99
import {CollateralEngine} from './CollateralEngine.sol';
10-
import {EModeEngine} from './EModeEngine.sol';
1110
import {ConfiguratorInputTypes} from '../../../protocol/libraries/types/ConfiguratorInputTypes.sol';
1211
import {SafeCast} from 'openzeppelin-contracts/contracts/utils/math/SafeCast.sol';
1312

tests/extensions/v3-config-engine/AaveV3ConfigEngineTest.t.sol

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import 'forge-std/Test.sol';
55
import {VmSafe} from 'forge-std/Base.sol';
66
import {IAaveV3ConfigEngine} from '../../../src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol';
77
import {AaveV3MockListing} from './mocks/AaveV3MockListing.sol';
8+
import {AaveV3MockListingWithEModeCreation} from './mocks/AaveV3MockListingWithEModeCreation.sol';
89
import {AaveV3MockListingCustom} from './mocks/AaveV3MockListingCustom.sol';
10+
import {AaveV3MockListingCustomWithEModeCreation} from './mocks/AaveV3MockListingCustomWithEModeCreation.sol';
911
import {AaveV3MockCapUpdate} from './mocks/AaveV3MockCapUpdate.sol';
1012
import {AaveV3MockCollateralUpdate} from './mocks/AaveV3MockCollateralUpdate.sol';
1113
import {AaveV3MockCollateralUpdateNoChange} from './mocks/AaveV3MockCollateralUpdateNoChange.sol';
@@ -126,6 +128,111 @@ contract AaveV3ConfigEngineTest is TestnetProcedures, ProtocolV3TestBase {
126128
);
127129
}
128130

131+
function testListingWithEModeCategoryCreation() public {
132+
address asset = address(new TestnetERC20('1INCH', '1INCH', 18, address(this)));
133+
134+
address feed = address(new MockAggregator(int256(25e8)));
135+
AaveV3MockListingWithEModeCreation payload = new AaveV3MockListingWithEModeCreation(
136+
asset,
137+
feed,
138+
configEngine
139+
);
140+
141+
vm.prank(roleList.marketOwner);
142+
contracts.aclManager.addPoolAdmin(address(payload));
143+
144+
ReserveConfig[] memory allConfigsBefore = createConfigurationSnapshot(
145+
'preTestEngineListingWithEModeCreation',
146+
IPool(address(contracts.poolProxy))
147+
);
148+
149+
payload.execute();
150+
151+
ReserveConfig[] memory allConfigsAfter = createConfigurationSnapshot(
152+
'postTestEngineListingWithEModeCreation',
153+
IPool(address(contracts.poolProxy))
154+
);
155+
156+
diffReports('preTestEngineListingWithEModeCreation', 'postTestEngineListingWithEModeCreation');
157+
158+
ReserveConfig memory expectedAssetConfig = ReserveConfig({
159+
symbol: '1INCH',
160+
underlying: asset,
161+
aToken: address(0), // Mock, as they don't get validated, because of the "dynamic" deployment on proposal execution
162+
variableDebtToken: address(0), // Mock, as they don't get validated, because of the "dynamic" deployment on proposal execution
163+
decimals: 18,
164+
ltv: 82_50,
165+
liquidationThreshold: 86_00,
166+
liquidationBonus: 105_00,
167+
liquidationProtocolFee: 10_00,
168+
reserveFactor: 10_00,
169+
usageAsCollateralEnabled: true,
170+
borrowingEnabled: true,
171+
interestRateStrategy: AaveV3ConfigEngine(configEngine).DEFAULT_INTEREST_RATE_STRATEGY(),
172+
isPaused: false,
173+
isActive: true,
174+
isFrozen: false,
175+
isSiloed: false,
176+
isBorrowableInIsolation: false,
177+
isFlashloanable: false,
178+
supplyCap: 85_000,
179+
borrowCap: 60_000,
180+
debtCeiling: 0,
181+
virtualBalance: 0,
182+
aTokenUnderlyingBalance: 0
183+
});
184+
185+
_validateReserveConfig(expectedAssetConfig, allConfigsAfter);
186+
187+
_noReservesConfigsChangesApartNewListings(allConfigsBefore, allConfigsAfter);
188+
189+
_validateReserveTokensImpls(
190+
_findReserveConfigBySymbol(allConfigsAfter, '1INCH'),
191+
ReserveTokens({
192+
aToken: address(contracts.aToken),
193+
variableDebtToken: address(contracts.variableDebtToken)
194+
})
195+
);
196+
197+
_validateAssetSourceOnOracle(
198+
IPoolAddressesProvider(address(contracts.poolAddressesProvider)),
199+
asset,
200+
feed
201+
);
202+
203+
_validateInterestRateStrategy(
204+
asset,
205+
contracts.protocolDataProvider.getInterestRateStrategyAddress(asset),
206+
AaveV3ConfigEngine(configEngine).DEFAULT_INTEREST_RATE_STRATEGY(),
207+
IDefaultInterestRateStrategyV2.InterestRateDataRay({
208+
optimalUsageRatio: _bpsToRay(payload.newListings()[0].rateStrategyParams.optimalUsageRatio),
209+
baseVariableBorrowRate: _bpsToRay(
210+
payload.newListings()[0].rateStrategyParams.baseVariableBorrowRate
211+
),
212+
variableRateSlope1: _bpsToRay(
213+
payload.newListings()[0].rateStrategyParams.variableRateSlope1
214+
),
215+
variableRateSlope2: _bpsToRay(
216+
payload.newListings()[0].rateStrategyParams.variableRateSlope2
217+
)
218+
})
219+
);
220+
221+
DataTypes.EModeCategory memory eModeCategoryData;
222+
eModeCategoryData.ltv = 97_40;
223+
eModeCategoryData.liquidationThreshold = 97_60;
224+
eModeCategoryData.liquidationBonus = 101_50; // 100_00 + 1_50
225+
eModeCategoryData.label = 'Listed Asset EMode';
226+
eModeCategoryData.collateralBitmap = 8; // 1000
227+
eModeCategoryData.borrowableBitmap = 8; // 1000
228+
229+
_validateEmodeCategory(
230+
IPoolAddressesProvider(address(contracts.poolAddressesProvider)),
231+
1,
232+
eModeCategoryData
233+
);
234+
}
235+
129236
function testListingsCustom() public {
130237
address asset = address(new TestnetERC20('PSP', 'PSP', 18, address(this)));
131238

@@ -225,6 +332,122 @@ contract AaveV3ConfigEngineTest is TestnetProcedures, ProtocolV3TestBase {
225332
);
226333
}
227334

335+
function testListingsCustomWithEModeCategoryCreation() public {
336+
address asset = address(new TestnetERC20('PSP', 'PSP', 18, address(this)));
337+
338+
address feed = address(new MockAggregator(int256(15e8)));
339+
address aTokenImpl = address(
340+
new ATokenInstance(contracts.poolProxy, report.rewardsControllerProxy, report.treasury)
341+
);
342+
address vTokenImpl = address(
343+
new VariableDebtTokenInstance(contracts.poolProxy, report.rewardsControllerProxy)
344+
);
345+
346+
AaveV3MockListingCustomWithEModeCreation payload = new AaveV3MockListingCustomWithEModeCreation(
347+
asset,
348+
feed,
349+
configEngine,
350+
aTokenImpl,
351+
vTokenImpl
352+
);
353+
354+
vm.prank(roleList.marketOwner);
355+
contracts.aclManager.addPoolAdmin(address(payload));
356+
357+
ReserveConfig[] memory allConfigsBefore = createConfigurationSnapshot(
358+
'preTestEngineListingCustomWithEModeCreation',
359+
IPool(address(contracts.poolProxy))
360+
);
361+
362+
payload.execute();
363+
364+
ReserveConfig[] memory allConfigsAfter = createConfigurationSnapshot(
365+
'postTestEngineListingCustomWithEModeCreation',
366+
IPool(address(contracts.poolProxy))
367+
);
368+
369+
diffReports(
370+
'preTestEngineListingCustomWithEModeCreation',
371+
'postTestEngineListingCustomWithEModeCreation'
372+
);
373+
374+
ReserveConfig memory expectedAssetConfig = ReserveConfig({
375+
symbol: 'PSP',
376+
underlying: asset,
377+
aToken: address(0), // Mock, as they don't get validated, because of the "dynamic" deployment on proposal execution
378+
variableDebtToken: address(0), // Mock, as they don't get validated, because of the "dynamic" deployment on proposal execution
379+
decimals: 18,
380+
ltv: 82_50,
381+
liquidationThreshold: 86_00,
382+
liquidationBonus: 105_00,
383+
liquidationProtocolFee: 10_00,
384+
reserveFactor: 10_00,
385+
usageAsCollateralEnabled: true,
386+
borrowingEnabled: true,
387+
interestRateStrategy: AaveV3ConfigEngine(configEngine).DEFAULT_INTEREST_RATE_STRATEGY(),
388+
isPaused: false,
389+
isActive: true,
390+
isFrozen: false,
391+
isSiloed: false,
392+
isBorrowableInIsolation: false,
393+
isFlashloanable: false,
394+
supplyCap: 85_000,
395+
borrowCap: 60_000,
396+
debtCeiling: 0,
397+
virtualBalance: 0,
398+
aTokenUnderlyingBalance: 0
399+
});
400+
401+
_validateReserveConfig(expectedAssetConfig, allConfigsAfter);
402+
403+
_noReservesConfigsChangesApartNewListings(allConfigsBefore, allConfigsAfter);
404+
405+
_validateReserveTokensImpls(
406+
_findReserveConfigBySymbol(allConfigsAfter, 'PSP'),
407+
ReserveTokens({aToken: aTokenImpl, variableDebtToken: vTokenImpl})
408+
);
409+
410+
_validateAssetSourceOnOracle(
411+
IPoolAddressesProvider(address(contracts.poolAddressesProvider)),
412+
asset,
413+
feed
414+
);
415+
416+
_validateInterestRateStrategy(
417+
asset,
418+
contracts.protocolDataProvider.getInterestRateStrategyAddress(asset),
419+
AaveV3ConfigEngine(configEngine).DEFAULT_INTEREST_RATE_STRATEGY(),
420+
IDefaultInterestRateStrategyV2.InterestRateDataRay({
421+
optimalUsageRatio: _bpsToRay(
422+
payload.newListingsCustom()[0].base.rateStrategyParams.optimalUsageRatio
423+
),
424+
baseVariableBorrowRate: _bpsToRay(
425+
payload.newListingsCustom()[0].base.rateStrategyParams.baseVariableBorrowRate
426+
),
427+
variableRateSlope1: _bpsToRay(
428+
payload.newListingsCustom()[0].base.rateStrategyParams.variableRateSlope1
429+
),
430+
variableRateSlope2: _bpsToRay(
431+
payload.newListingsCustom()[0].base.rateStrategyParams.variableRateSlope2
432+
)
433+
})
434+
);
435+
436+
DataTypes.EModeCategory memory eModeCategoryData;
437+
eModeCategoryData.ltv = 97_40;
438+
eModeCategoryData.liquidationThreshold = 97_60;
439+
eModeCategoryData.liquidationBonus = 101_50; // 100_00 + 1_50
440+
eModeCategoryData.label = 'Listed Asset EMode';
441+
eModeCategoryData.collateralBitmap = 8; // 1000
442+
eModeCategoryData.borrowableBitmap = 8; // 1000
443+
444+
_validateEmodeCategory(
445+
IPoolAddressesProvider(address(contracts.poolAddressesProvider)),
446+
1,
447+
eModeCategoryData
448+
);
449+
}
450+
228451
function testCapsUpdate() public {
229452
// this asset has been listed before
230453
address asset = tokenList.usdx;

tests/extensions/v3-config-engine/mocks/AaveV3MockEModeCategoryCreation.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ contract AaveV3MockEModeCategoryCreation is AaveV3Payload {
3636
returns (IEngine.EModeCategoryCreation[] memory)
3737
{
3838
IEngine.EModeCategoryCreation[] memory eModeUpdates = new IEngine.EModeCategoryCreation[](2);
39-
4039
address[] memory empty = new address[](0);
4140

4241
eModeUpdates[0] = IEngine.EModeCategoryCreation({
@@ -47,12 +46,14 @@ contract AaveV3MockEModeCategoryCreation is AaveV3Payload {
4746
borrowables: empty,
4847
collaterals: empty
4948
});
49+
5050
address[] memory collaterals = new address[](2);
5151
address[] memory borrowables = new address[](2);
5252
collaterals[0] = COLLATERAL_ONE;
5353
collaterals[1] = COLLATERAL_TWO;
5454
borrowables[0] = BORROWABLE_ONE;
5555
borrowables[1] = BORROWABLE_TWO;
56+
5657
eModeUpdates[1] = IEngine.EModeCategoryCreation({
5758
ltv: 97_40,
5859
liqThreshold: 97_60,

0 commit comments

Comments
 (0)