Skip to content

Commit 6749e38

Browse files
feat: emode (merge to certora) (#39)
* feat: add emode and remove using data provider * test: emode updates * fix: use bytes20 for timelock * feat: add generator for emode updates * fix: use pool instead of addresses provider * feat: add pendle price cap * fix: test * test: pendle price cap * fix: edge risk stewards * Update src/contracts/RiskSteward.sol * Update src/contracts/RiskSteward.sol * chore: fix ci * fix: certora ci * fix: ci * refactor: config struct * refactor: rename stablePriceCapUpdates * Revert "refactor: rename stablePriceCapUpdates" This reverts commit ae8d10d. * fix: remove bytes from timelock mapping * fix: use different mapping for emode timelock * fix: struct * fix: timelock * Update src/interfaces/IRiskSteward.sol Co-authored-by: Andrey <[email protected]> * fix: Debounce struct order * fix: dont allow emode label change * refactor: rename to updatePendleDiscountRates --------- Co-authored-by: Andrey <[email protected]>
1 parent 8773713 commit 6749e38

32 files changed

+8923
-481
lines changed

.github/workflows/certora.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ jobs:
3232

3333
- name: Install solc
3434
run: |
35-
wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux
35+
wget https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux
3636
chmod +x solc-static-linux
37-
sudo mv solc-static-linux /usr/local/bin/solc8.19
37+
sudo mv solc-static-linux /usr/local/bin/solc8.24
3838
3939
- name: Verify rule ${{ matrix.rule }}
4040
run: |

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ zkout/
1111
.idea
1212
.vscode
1313

14-
# well, looks strange to ignore package-lock, but we have only pretter and it's temproray
15-
package-lock.json
1614
node_modules
1715

1816
# ignore foundry deploy artifacts

certora/confs/rules.conf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@
1414
"lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src",
1515
"aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin",
1616
"aave-capo=lib/aave-capo/src",
17-
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src"
17+
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src",
18+
"openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable",
19+
"openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts"
1820
],
1921
"optimistic_loop": true,
2022
"loop_iter": "2",
2123
"rule_sanity": "basic",
2224
"prover_args": ["-depth 15","-mediumTimeout 1000"],
2325
"smt_timeout": "2000",
24-
"solc": "solc8.19",
26+
"solc": "solc8.24",
2527
"verify": "RiskSteward:certora/specs/rules.spec",
2628
"cache" :"none",
2729
"msg": "RISK-STEWARD::rules"

certora/confs/sanity.conf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
"lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src",
1111
"aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin",
1212
"aave-capo=lib/aave-capo/src",
13-
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src"
13+
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src",
14+
"openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable",
15+
"openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts"
1416
],
1517
"optimistic_loop": true,
1618
"prover_args": ["-depth 15","-mediumTimeout 1000"],
1719
"smt_timeout": "2000",
18-
"solc": "solc8.19",
20+
"solc": "solc8.24",
1921
"verify": "RiskSteward:certora/specs/sanity.spec",
2022
"cache" :"none",
2123
"msg": "RISK-STEWARD::sanity"

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ src = 'src'
33
test = 'tests'
44
script = 'scripts'
55
out = 'out'
6-
solc = '0.8.22'
6+
solc = '0.8.24'
77
optimizer = true
88
optimizer_runs = 200
99
libs = ['lib']

generator/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import {capsUpdates} from './features/capsUpdates';
1515
import {rateUpdatesV3} from './features/rateUpdates';
1616
import {collateralsUpdates} from './features/collateralsUpdates';
17+
import {eModeUpdates} from './features/eModeUpdates';
1718
import {lstPriceCapsUpdates} from './features/lstPriceCapsUpdates';
1819
import {stablePriceCapsUpdates} from './features/stablePriceCapsUpdates';
1920
import {generateFiles, writeFiles} from './generator';
@@ -43,7 +44,8 @@ const FEATURE_MODULES_V3 = [
4344
capsUpdates,
4445
collateralsUpdates,
4546
lstPriceCapsUpdates,
46-
stablePriceCapsUpdates
47+
stablePriceCapsUpdates,
48+
eModeUpdates
4749
];
4850

4951
async function generateDeterministicPoolCache(pool: PoolIdentifier): Promise<PoolCache> {

generator/common.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ export function getAssets(pool: PoolIdentifier): string[] {
4141
return Object.keys(assets);
4242
}
4343

44-
export function getEModes(pool: PoolIdentifierV3) {
45-
const eModes = addressBook[pool].E_MODES;
46-
return eModes;
44+
export function getEModes(pool: PoolIdentifierV3): {value: string; id: number}[] {
45+
return Object.keys(addressBook[pool].E_MODES).map((key) => ({
46+
// map the complex type to a string as used in the sol libs
47+
value: addressBook[pool].E_MODES[key].label.toUpperCase().replace(/[^A-Z0-9]+/gi, '_'),
48+
id: key as unknown as number,
49+
}));
4750
}
4851

4952
export function getVersion(pool: PoolIdentifier) {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`feature: eModeUpdates > should properly generate files 1`] = `
4+
{
5+
"jsonConfig": "import {ConfigFile} from '../../generator/types';
6+
export const config: ConfigFile = {
7+
rootOptions: {
8+
pools: ['AaveV3Ethereum'],
9+
title: 'test',
10+
shortName: 'Test',
11+
date: '20231023',
12+
author: 'test',
13+
discussion: 'test',
14+
},
15+
poolOptions: {
16+
AaveV3Ethereum: {
17+
configs: {
18+
EMODES_UPDATE: [
19+
{
20+
eModeCategory: 'AaveV3EthereumEModes.ETH_CORRELATED',
21+
ltv: '',
22+
liqThreshold: '50',
23+
liqBonus: '',
24+
label: '',
25+
},
26+
],
27+
},
28+
cache: {blockNumber: 42},
29+
},
30+
},
31+
};
32+
",
33+
"payloads": [
34+
{
35+
"contractName": "AaveV3Ethereum_Test_20231023",
36+
"payload": "// SPDX-License-Identifier: MIT
37+
pragma solidity ^0.8.0;
38+
39+
import {AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol';
40+
import {RiskStewardsEthereum} from '../../../../scripts/networks/RiskStewardsEthereum.s.sol';
41+
import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol';
42+
import {IAaveV3ConfigEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol';
43+
44+
/**
45+
* @title test
46+
* @author test
47+
* - discussion: test
48+
* - deploy-command: make run-script contract=src/contracts/updates/20231023_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231023.sol:AaveV3Ethereum_Test_20231023 network=mainnet broadcast=false generate_diff=true skip_timelock=false
49+
*/
50+
contract AaveV3Ethereum_Test_20231023 is RiskStewardsEthereum {
51+
function name() public pure override returns (string memory) {
52+
return 'AaveV3Ethereum_Test_20231023';
53+
}
54+
55+
function eModeCategoriesUpdates()
56+
public
57+
pure
58+
override
59+
returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory)
60+
{
61+
IAaveV3ConfigEngine.EModeCategoryUpdate[]
62+
memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1);
63+
64+
eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({
65+
eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED,
66+
ltv: EngineFlags.KEEP_CURRENT,
67+
liqThreshold: 50_00,
68+
liqBonus: EngineFlags.KEEP_CURRENT,
69+
label: EngineFlags.KEEP_CURRENT_STRING
70+
});
71+
72+
return eModeUpdates;
73+
}
74+
}
75+
",
76+
"pool": "AaveV3Ethereum",
77+
},
78+
],
79+
}
80+
`;
81+
82+
exports[`feature: eModeUpdates > should return reasonable code 1`] = `
83+
{
84+
"code": {
85+
"fn": [
86+
"function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) {
87+
IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1);
88+
89+
eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({
90+
eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED,
91+
ltv: EngineFlags.KEEP_CURRENT,
92+
liqThreshold: 50_00,
93+
liqBonus: EngineFlags.KEEP_CURRENT,
94+
label: EngineFlags.KEEP_CURRENT_STRING
95+
});
96+
97+
return eModeUpdates;
98+
}",
99+
],
100+
},
101+
}
102+
`;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// sum.test.js
2+
import {expect, describe, it} from 'vitest';
3+
import {MOCK_OPTIONS, eModeUpdate} from './mocks/configs';
4+
import {generateFiles} from '../generator';
5+
import {FEATURE, PoolConfigs} from '../types';
6+
import {eModeUpdates} from './eModeUpdates';
7+
8+
describe('feature: eModeUpdates', () => {
9+
it('should return reasonable code', () => {
10+
const output = eModeUpdates.build({
11+
options: MOCK_OPTIONS,
12+
pool: 'AaveV3Ethereum',
13+
cfg: eModeUpdate,
14+
cache: {blockNumber: 42},
15+
});
16+
expect(output).toMatchSnapshot();
17+
});
18+
19+
it('should properly generate files', async () => {
20+
const poolConfigs: PoolConfigs = {
21+
['AaveV3Ethereum']: {
22+
artifacts: [
23+
eModeUpdates.build({
24+
options: {...MOCK_OPTIONS, pools: ['AaveV3Ethereum']},
25+
pool: 'AaveV3Ethereum',
26+
cfg: eModeUpdate,
27+
cache: {blockNumber: 42},
28+
}),
29+
],
30+
configs: {[FEATURE.EMODES_UPDATE]: eModeUpdate},
31+
cache: {blockNumber: 42},
32+
},
33+
};
34+
const files = await generateFiles({...MOCK_OPTIONS, pools: ['AaveV3Ethereum']}, poolConfigs);
35+
expect(files).toMatchSnapshot();
36+
});
37+
});

generator/features/eModeUpdates.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import {CodeArtifact, FEATURE, FeatureModule} from '../types';
2+
import {eModesSelect} from '../prompts';
3+
import {EModeCategoryUpdate} from './types';
4+
import {stringOrKeepCurrent, stringPrompt} from '../prompts/stringPrompt';
5+
import {percentPrompt, translateJsPercentToSol} from '../prompts/percentPrompt';
6+
7+
async function fetchEmodeCategoryUpdate<T extends boolean>(
8+
eModeCategory: string | number,
9+
required?: T,
10+
): Promise<EModeCategoryUpdate> {
11+
return {
12+
eModeCategory,
13+
ltv: await percentPrompt({
14+
message: 'ltv',
15+
required,
16+
}),
17+
liqThreshold: await percentPrompt({
18+
message: 'liqThreshold',
19+
required,
20+
}),
21+
liqBonus: await percentPrompt({
22+
message: 'liqBonus',
23+
required,
24+
}),
25+
label: await stringPrompt({
26+
message: 'label',
27+
required,
28+
}),
29+
};
30+
}
31+
32+
type EmodeUpdates = EModeCategoryUpdate[];
33+
34+
export const eModeUpdates: FeatureModule<EmodeUpdates> = {
35+
value: FEATURE.EMODES_UPDATE,
36+
description: 'eModeCategoriesUpdates (altering eMode category params)',
37+
async cli({pool}) {
38+
console.log(`Fetching information for EMode category updates on ${pool}`);
39+
40+
const response: EmodeUpdates = [];
41+
const eModeCategories = await eModesSelect({
42+
message: 'Select the eModes you want to amend',
43+
pool,
44+
});
45+
46+
if (eModeCategories) {
47+
for (const eModeCategory of eModeCategories) {
48+
console.log(`collecting info for ${eModeCategory}`);
49+
response.push(await fetchEmodeCategoryUpdate(eModeCategory));
50+
}
51+
}
52+
return response;
53+
},
54+
build({pool, cfg}) {
55+
const response: CodeArtifact = {
56+
code: {
57+
fn: [
58+
`function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) {
59+
IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](${
60+
cfg.length
61+
});
62+
63+
${cfg
64+
.map(
65+
(cfg, ix) => `eModeUpdates[${ix}] = IAaveV3ConfigEngine.EModeCategoryUpdate({
66+
eModeCategory: ${cfg.eModeCategory},
67+
ltv: ${translateJsPercentToSol(cfg.ltv)},
68+
liqThreshold: ${translateJsPercentToSol(cfg.liqThreshold)},
69+
liqBonus: ${translateJsPercentToSol(cfg.liqBonus)},
70+
label: ${stringOrKeepCurrent(cfg.label)}
71+
});`,
72+
)
73+
.join('\n')}
74+
75+
return eModeUpdates;
76+
}`,
77+
],
78+
},
79+
};
80+
return response;
81+
},
82+
};

0 commit comments

Comments
 (0)