Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e7ccddf
feat: add emode and remove using data provider
brotherlymite Mar 22, 2025
d8b5eca
test: emode updates
brotherlymite Mar 22, 2025
da9ac08
fix: use bytes20 for timelock
brotherlymite Mar 25, 2025
603319d
feat: add generator for emode updates
brotherlymite Mar 25, 2025
1f61c0a
fix: use pool instead of addresses provider
brotherlymite Mar 25, 2025
8441323
feat: add pendle price cap
brotherlymite Mar 28, 2025
4066cbc
fix: test
brotherlymite Mar 28, 2025
5737c57
test: pendle price cap
brotherlymite Mar 28, 2025
b2cfdef
fix: edge risk stewards
brotherlymite Mar 28, 2025
1e18758
Update src/contracts/RiskSteward.sol
brotherlymite Mar 28, 2025
18d9562
Update src/contracts/RiskSteward.sol
brotherlymite Mar 28, 2025
bad3136
chore: fix ci
brotherlymite Mar 28, 2025
f203e01
fix: certora ci
brotherlymite Mar 28, 2025
282a923
fix: ci
brotherlymite Mar 28, 2025
de3ed28
refactor: config struct
brotherlymite Mar 28, 2025
3439766
Merge branch 'refactor/config' into feat/emode
brotherlymite Mar 28, 2025
ae8d10d
refactor: rename stablePriceCapUpdates
brotherlymite Apr 1, 2025
1a66eeb
Revert "refactor: rename stablePriceCapUpdates"
brotherlymite Apr 2, 2025
4339153
fix: remove bytes from timelock mapping
brotherlymite Apr 2, 2025
399fd4a
Merge branch 'refactor/config' into feat/emode
brotherlymite Apr 2, 2025
c0d1a3e
fix: use different mapping for emode timelock
brotherlymite Apr 2, 2025
ae13dc6
fix: struct
brotherlymite Apr 2, 2025
5125c6e
Merge branch 'feat/emode' into feat/pendle
brotherlymite Apr 2, 2025
6be86e0
fix: timelock
brotherlymite Apr 2, 2025
d5d51a3
Update src/interfaces/IRiskSteward.sol
brotherlymite Apr 2, 2025
3360ea9
fix: Debounce struct order
brotherlymite Apr 2, 2025
7d038ad
fix: dont allow emode label change
brotherlymite Apr 2, 2025
bcf0cdf
refactor: rename to updatePendleDiscountRates
brotherlymite Apr 2, 2025
cf0c074
Merge pull request #3 from bgd-labs/feat/pendle
brotherlymite Apr 2, 2025
581b58c
Merge pull request #6 from bgd-labs/feat/emode
brotherlymite Apr 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/certora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ jobs:

- name: Install solc
run: |
wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux
wget https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux
chmod +x solc-static-linux
sudo mv solc-static-linux /usr/local/bin/solc8.19
sudo mv solc-static-linux /usr/local/bin/solc8.24

- name: Verify rule ${{ matrix.rule }}
run: |
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ zkout/
.idea
.vscode

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

# ignore foundry deploy artifacts
Expand Down
6 changes: 4 additions & 2 deletions certora/confs/rules.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@
"lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src",
"aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin",
"aave-capo=lib/aave-capo/src",
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src"
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src",
"openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable",
"openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts"
],
"optimistic_loop": true,
"loop_iter": "2",
"rule_sanity": "basic",
"prover_args": ["-depth 15","-mediumTimeout 1000"],
"smt_timeout": "2000",
"solc": "solc8.19",
"solc": "solc8.24",
"verify": "RiskSteward:certora/specs/rules.spec",
"cache" :"none",
"msg": "RISK-STEWARD::rules"
Expand Down
6 changes: 4 additions & 2 deletions certora/confs/sanity.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
"lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src",
"aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin",
"aave-capo=lib/aave-capo/src",
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src"
"lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src",
"openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable",
"openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts"
],
"optimistic_loop": true,
"prover_args": ["-depth 15","-mediumTimeout 1000"],
"smt_timeout": "2000",
"solc": "solc8.19",
"solc": "solc8.24",
"verify": "RiskSteward:certora/specs/sanity.spec",
"cache" :"none",
"msg": "RISK-STEWARD::sanity"
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ src = 'src'
test = 'tests'
script = 'scripts'
out = 'out'
solc = '0.8.22'
solc = '0.8.24'
optimizer = true
optimizer_runs = 200
libs = ['lib']
Expand Down
4 changes: 3 additions & 1 deletion generator/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import {capsUpdates} from './features/capsUpdates';
import {rateUpdatesV3} from './features/rateUpdates';
import {collateralsUpdates} from './features/collateralsUpdates';
import {eModeUpdates} from './features/eModeUpdates';
import {lstPriceCapsUpdates} from './features/lstPriceCapsUpdates';
import {stablePriceCapsUpdates} from './features/stablePriceCapsUpdates';
import {generateFiles, writeFiles} from './generator';
Expand Down Expand Up @@ -42,7 +43,8 @@ const FEATURE_MODULES_V3 = [
capsUpdates,
collateralsUpdates,
lstPriceCapsUpdates,
stablePriceCapsUpdates
stablePriceCapsUpdates,
eModeUpdates
];

async function generateDeterministicPoolCache(pool: PoolIdentifier): Promise<PoolCache> {
Expand Down
9 changes: 6 additions & 3 deletions generator/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ export function getAssets(pool: PoolIdentifier): string[] {
return Object.keys(assets);
}

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

export function getVersion(pool: PoolIdentifier) {
Expand Down
102 changes: 102 additions & 0 deletions generator/features/__snapshots__/eModeUpdates.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`feature: eModeUpdates > should properly generate files 1`] = `
{
"jsonConfig": "import {ConfigFile} from '../../generator/types';
export const config: ConfigFile = {
rootOptions: {
pools: ['AaveV3Ethereum'],
title: 'test',
shortName: 'Test',
date: '20231023',
author: 'test',
discussion: 'test',
},
poolOptions: {
AaveV3Ethereum: {
configs: {
EMODES_UPDATE: [
{
eModeCategory: 'AaveV3EthereumEModes.ETH_CORRELATED',
ltv: '',
liqThreshold: '50',
liqBonus: '',
label: '',
},
],
},
cache: {blockNumber: 42},
},
},
};
",
"payloads": [
{
"contractName": "AaveV3Ethereum_Test_20231023",
"payload": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol';
import {RiskStewardsEthereum} from '../../../../scripts/networks/RiskStewardsEthereum.s.sol';
import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol';
import {IAaveV3ConfigEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol';

/**
* @title test
* @author test
* - discussion: test
* - 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
*/
contract AaveV3Ethereum_Test_20231023 is RiskStewardsEthereum {
function name() public pure override returns (string memory) {
return 'AaveV3Ethereum_Test_20231023';
}

function eModeCategoriesUpdates()
public
pure
override
returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory)
{
IAaveV3ConfigEngine.EModeCategoryUpdate[]
memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1);

eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({
eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED,
ltv: EngineFlags.KEEP_CURRENT,
liqThreshold: 50_00,
liqBonus: EngineFlags.KEEP_CURRENT,
label: EngineFlags.KEEP_CURRENT_STRING
});

return eModeUpdates;
}
}
",
"pool": "AaveV3Ethereum",
},
],
}
`;

exports[`feature: eModeUpdates > should return reasonable code 1`] = `
{
"code": {
"fn": [
"function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) {
IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1);

eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({
eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED,
ltv: EngineFlags.KEEP_CURRENT,
liqThreshold: 50_00,
liqBonus: EngineFlags.KEEP_CURRENT,
label: EngineFlags.KEEP_CURRENT_STRING
});

return eModeUpdates;
}",
],
},
}
`;
37 changes: 37 additions & 0 deletions generator/features/eModeUpdates.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// sum.test.js
import {expect, describe, it} from 'vitest';
import {MOCK_OPTIONS, eModeUpdate} from './mocks/configs';
import {generateFiles} from '../generator';
import {FEATURE, PoolConfigs} from '../types';
import {eModeUpdates} from './eModeUpdates';

describe('feature: eModeUpdates', () => {
it('should return reasonable code', () => {
const output = eModeUpdates.build({
options: MOCK_OPTIONS,
pool: 'AaveV3Ethereum',
cfg: eModeUpdate,
cache: {blockNumber: 42},
});
expect(output).toMatchSnapshot();
});

it('should properly generate files', async () => {
const poolConfigs: PoolConfigs = {
['AaveV3Ethereum']: {
artifacts: [
eModeUpdates.build({
options: {...MOCK_OPTIONS, pools: ['AaveV3Ethereum']},
pool: 'AaveV3Ethereum',
cfg: eModeUpdate,
cache: {blockNumber: 42},
}),
],
configs: {[FEATURE.EMODES_UPDATE]: eModeUpdate},
cache: {blockNumber: 42},
},
};
const files = await generateFiles({...MOCK_OPTIONS, pools: ['AaveV3Ethereum']}, poolConfigs);
expect(files).toMatchSnapshot();
});
});
82 changes: 82 additions & 0 deletions generator/features/eModeUpdates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {CodeArtifact, FEATURE, FeatureModule} from '../types';
import {eModesSelect} from '../prompts';
import {EModeCategoryUpdate} from './types';
import {stringOrKeepCurrent, stringPrompt} from '../prompts/stringPrompt';
import {percentPrompt, translateJsPercentToSol} from '../prompts/percentPrompt';

async function fetchEmodeCategoryUpdate<T extends boolean>(
eModeCategory: string | number,
required?: T,
): Promise<EModeCategoryUpdate> {
return {
eModeCategory,
ltv: await percentPrompt({
message: 'ltv',
required,
}),
liqThreshold: await percentPrompt({
message: 'liqThreshold',
required,
}),
liqBonus: await percentPrompt({
message: 'liqBonus',
required,
}),
label: await stringPrompt({
message: 'label',
required,
}),
};
}

type EmodeUpdates = EModeCategoryUpdate[];

export const eModeUpdates: FeatureModule<EmodeUpdates> = {
value: FEATURE.EMODES_UPDATE,
description: 'eModeCategoriesUpdates (altering eMode category params)',
async cli({pool}) {
console.log(`Fetching information for EMode category updates on ${pool}`);

const response: EmodeUpdates = [];
const eModeCategories = await eModesSelect({
message: 'Select the eModes you want to amend',
pool,
});

if (eModeCategories) {
for (const eModeCategory of eModeCategories) {
console.log(`collecting info for ${eModeCategory}`);
response.push(await fetchEmodeCategoryUpdate(eModeCategory));
}
}
return response;
},
build({pool, cfg}) {
const response: CodeArtifact = {
code: {
fn: [
`function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) {
IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](${
cfg.length
});

${cfg
.map(
(cfg, ix) => `eModeUpdates[${ix}] = IAaveV3ConfigEngine.EModeCategoryUpdate({
eModeCategory: ${cfg.eModeCategory},
ltv: ${translateJsPercentToSol(cfg.ltv)},
liqThreshold: ${translateJsPercentToSol(cfg.liqThreshold)},
liqBonus: ${translateJsPercentToSol(cfg.liqBonus)},
label: ${stringOrKeepCurrent(cfg.label)}
});`,
)
.join('\n')}

return eModeUpdates;
}`,
],
},
};
return response;
},
};
12 changes: 11 additions & 1 deletion generator/features/mocks/configs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Options} from '../../types';
import {CapsUpdate, CollateralUpdate, RateStrategyUpdate, LstPriceCapUpdate, StablePriceCapUpdate} from '../types';
import {CapsUpdate, CollateralUpdate, RateStrategyUpdate, LstPriceCapUpdate, StablePriceCapUpdate, EModeCategoryUpdate} from '../types';

export const MOCK_OPTIONS: Options = {
pools: ['AaveV3Ethereum'],
Expand Down Expand Up @@ -29,6 +29,16 @@ export const collateralUpdate: CollateralUpdate[] = [
},
];

export const eModeUpdate: EModeCategoryUpdate[] = [
{
eModeCategory: 'AaveV3EthereumEModes.ETH_CORRELATED',
ltv: '',
liqThreshold: '50',
liqBonus: '',
label: '',
},
];

export const rateUpdateV3: RateStrategyUpdate[] = [
{
asset: 'WETH',
Expand Down
9 changes: 9 additions & 0 deletions generator/features/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ export interface CollateralUpdatePartial {

export interface CollateralUpdate extends CollateralUpdatePartial, AssetSelector {}

export interface EModeCategoryUpdate {
// library accessor or new id
eModeCategory: string | number;
ltv: NumberInputValues;
liqThreshold: NumberInputValues;
liqBonus: NumberInputValues;
label: string;
}

export interface RateStrategyParams {
optimalUtilizationRate: string;
baseVariableBorrowRate: string;
Expand Down
15 changes: 4 additions & 11 deletions generator/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,10 @@ export async function eModeSelect<T extends boolean>({
pool,
}: EModeSelectPrompt<T>) {
const eModes = getEModes(pool as any);
if (Object.keys(eModes).length != 0) {
if (eModes.length != 0) {
const eMode = await select({
message,
choices: [
...(disableKeepCurrent ? [] : [{value: ENGINE_FLAGS.KEEP_CURRENT}]),
...Object.keys(eModes).map((eMode) => ({value: eMode})),
],
choices: eModes,
});
return translateEModeToEModeLib(eMode, pool);
} else {
Expand All @@ -51,14 +48,10 @@ export async function eModeSelect<T extends boolean>({

export async function eModesSelect<T extends boolean>({message, pool}: EModeSelectPrompt<T>) {
const eModes = getEModes(pool as any);
if (Object.keys(eModes).length != 0) {
if (eModes.length != 0) {
const values = await checkbox({
message,
choices: [
...Object.keys(eModes)
.filter((e) => e != 'NONE')
.map((eMode) => ({value: eMode})),
],
choices: eModes,
required: true,
});
return values.map((mode) => translateEModeToEModeLib(mode, pool));
Expand Down
Loading
Loading